diff --git a/azurerm/resource_arm_role_assignment.go b/azurerm/resource_arm_role_assignment.go index cc302be37a2d..e428baffdef9 100644 --- a/azurerm/resource_arm_role_assignment.go +++ b/azurerm/resource_arm_role_assignment.go @@ -35,11 +35,20 @@ func resourceArmRoleAssignment() *schema.Resource { "role_definition_id": { Type: schema.TypeString, - Required: true, + Optional: true, + Computed: true, ForceNew: true, + ConflictsWith: []string{"role_definition_name"}, DiffSuppressFunc: ignoreCaseDiffSuppressFunc, }, + "role_definition_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"role_definition_id"}, + }, + "principal_id": { Type: schema.TypeString, Required: true, @@ -50,12 +59,31 @@ func resourceArmRoleAssignment() *schema.Resource { } func resourceArmRoleAssignmentCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient).roleAssignmentsClient + roleAssignmentsClient := meta.(*ArmClient).roleAssignmentsClient + roleDefinitionsClient := meta.(*ArmClient).roleDefinitionsClient ctx := meta.(*ArmClient).StopContext name := d.Get("name").(string) scope := d.Get("scope").(string) - roleDefinitionId := d.Get("role_definition_id").(string) + + var roleDefinitionId string + if v, ok := d.GetOk("role_definition_id"); ok { + roleDefinitionId = v.(string) + } else if v, ok := d.GetOk("role_definition_name"); ok { + filter := fmt.Sprintf("roleName eq '%s'", v.(string)) + roleDefinitions, err := roleDefinitionsClient.List(ctx, "", filter) + if err != nil { + return fmt.Errorf("Error loading Role Definition List: %+v", err) + } + if len(roleDefinitions.Values()) != 1 { + return fmt.Errorf("Error loading Role Definition List: could not find role '%s'", name) + } + roleDefinitionId = *roleDefinitions.Values()[0].ID + } else { + return fmt.Errorf("Error: either role_definition_id or role_definition_name needs to be set") + } + d.Set("role_definition_id", roleDefinitionId) + principalId := d.Get("principal_id").(string) if name == "" { @@ -74,12 +102,12 @@ func resourceArmRoleAssignmentCreate(d *schema.ResourceData, meta interface{}) e }, } - _, err := client.Create(ctx, scope, name, properties) + _, err := roleAssignmentsClient.Create(ctx, scope, name, properties) if err != nil { return err } - read, err := client.Get(ctx, scope, name) + read, err := roleAssignmentsClient.Get(ctx, scope, name) if err != nil { return err } diff --git a/azurerm/resource_arm_role_assignment_test.go b/azurerm/resource_arm_role_assignment_test.go index 3685c2c2f91f..eea5c60fc8b8 100644 --- a/azurerm/resource_arm_role_assignment_test.go +++ b/azurerm/resource_arm_role_assignment_test.go @@ -31,6 +31,27 @@ func TestAccAzureRMRoleAssignment_emptyName(t *testing.T) { }) } +func TestAccAzureRMRoleAssignment_roleName(t *testing.T) { + id := uuid.New().String() + resourceName := "azurerm_role_assignment.test" + config := testAccAzureRMRoleAssignment_roleName(id) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMRoleAssignmentDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMRoleAssignmentExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "role_definition_id"), + ), + }, + }, + }) +} + func TestAccAzureRMRoleAssignment_builtin(t *testing.T) { id := uuid.New().String() config := testAccAzureRMRoleAssignment_builtin(id) @@ -141,6 +162,21 @@ resource "azurerm_role_assignment" "test" { ` } +func testAccAzureRMRoleAssignment_roleName(id string) string { + return fmt.Sprintf(` +data "azurerm_subscription" "primary" {} + +data "azurerm_client_config" "test" {} + +resource "azurerm_role_assignment" "test" { + name = "%s" + scope = "${data.azurerm_subscription.primary.id}" + role_definition_name = "Reader" + principal_id = "${data.azurerm_client_config.test.service_principal_object_id}" +} +`, id) +} + func testAccAzureRMRoleAssignment_builtin(id string) string { return fmt.Sprintf(` data "azurerm_subscription" "primary" {} diff --git a/website/docs/r/role_assignment.html.markdown b/website/docs/r/role_assignment.html.markdown index 0b0916ba63a3..1ec6748426ea 100644 --- a/website/docs/r/role_assignment.html.markdown +++ b/website/docs/r/role_assignment.html.markdown @@ -18,14 +18,10 @@ data "azurerm_subscription" "primary" {} data "azurerm_client_config" "test" {} -data "azurerm_builtin_role_definition" "test" { - name = "Reader" -} - resource "azurerm_role_assignment" "test" { - scope = "${data.azurerm_subscription.primary.id}" - role_definition_id = "${data.azurerm_subscription.primary.id}${data.azurerm_builtin_role_definition.test.id}" - principal_id = "${data.azurerm_client_config.test.service_principal_object_id}" + scope = "${data.azurerm_subscription.primary.id}" + role_definition_name = "Reader" + principal_id = "${data.azurerm_client_config.test.service_principal_object_id}" } ``` @@ -97,7 +93,9 @@ The following arguments are supported: * `scope` - (Required) The scope at which the Role Assignment applies too, such as `/subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333`, `/subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333/resourceGroups/myGroup`, or `/subscriptions/0b1f6471-1bf0-4dda-aec3-111122223333/resourceGroups/myGroup/providers/Microsoft.Compute/virtualMachines/myVM`. Changing this forces a new resource to be created. -* `role_definition_id` - (Required) The Scoped-ID of the Role Definition. Changing this forces a new resource to be created. +* `role_definition_id` - (Optional) The Scoped-ID of the Role Definition. Changing this forces a new resource to be created. Conflicts with `role_definition_name`. + +* `role_definition_name` - (Optional) The name of a built-in Role. Changing this forces a new resource to be created. Conflicts with `role_definition_id`. * `principal_id` - (Required) The ID of the Principal (User or Application) to assign the Role Definition to. Changing this forces a new resource to be created.