Skip to content

Commit

Permalink
Merge pull request #2798 from terraform-providers/roledef/data_by_name
Browse files Browse the repository at this point in the history
azurerm_role_definition: ability to lookup by name
  • Loading branch information
tombuildsstuff authored Jan 30, 2019
2 parents f4ed2bb + 0038bc0 commit 3f5d9f1
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 18 deletions.
6 changes: 6 additions & 0 deletions azurerm/data_source_builtin_role_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import (
func dataSourceArmBuiltInRoleDefinition() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmBuiltInRoleDefinitionRead,

DeprecationMessage: `This Data Source has been deprecated in favour of the 'azurerm_role_definition' resource that now can look up role definitions by names.
As such this Data Source will be removed in v2.0 of the AzureRM Provider.
`,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand Down
76 changes: 65 additions & 11 deletions azurerm/data_source_role_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,49 @@ package azurerm
import (
"fmt"

"github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-01-01-preview/authorization"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"

"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceArmRoleDefinition() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmRoleDefinitionRead,
Schema: map[string]*schema.Schema{

"name": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ConflictsWith: []string{"role_definition_id"},
},

"role_definition_id": {
Type: schema.TypeString,
Required: true,
Type: schema.TypeString,
Optional: true,
Computed: true,
ConflictsWith: []string{"name"},
ValidateFunc: validate.UUIDOrEmpty,
},

"scope": {
Type: schema.TypeString,
Required: true,
Optional: true,
},

// Computed
"name": {
Type: schema.TypeString,
Computed: true,
},

"description": {
Type: schema.TypeString,
Computed: true,
},

"type": {
Type: schema.TypeString,
Computed: true,
},

"permissions": {
Type: schema.TypeList,
Computed: true,
Expand All @@ -44,13 +58,15 @@ func dataSourceArmRoleDefinition() *schema.Resource {
Type: schema.TypeString,
},
},

"not_actions": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

"data_actions": {
Type: schema.TypeSet,
Optional: true,
Expand All @@ -59,6 +75,7 @@ func dataSourceArmRoleDefinition() *schema.Resource {
},
Set: schema.HashString,
},

"not_data_actions": {
Type: schema.TypeSet,
Optional: true,
Expand All @@ -70,6 +87,7 @@ func dataSourceArmRoleDefinition() *schema.Resource {
},
},
},

"assignable_scopes": {
Type: schema.TypeList,
Computed: true,
Expand All @@ -85,18 +103,54 @@ func dataSourceArmRoleDefinitionRead(d *schema.ResourceData, meta interface{}) e
client := meta.(*ArmClient).roleDefinitionsClient
ctx := meta.(*ArmClient).StopContext

roleDefinitionId := d.Get("role_definition_id").(string)
name := d.Get("name").(string)
defId := d.Get("role_definition_id").(string)
scope := d.Get("scope").(string)

role, err := client.Get(ctx, scope, roleDefinitionId)
if err != nil {
return fmt.Errorf("Error loading Role Definition: %+v", err)
if name == "" && defId == "" {
return fmt.Errorf("Error one of `name` or `role_definition_id` must be specified")
}

// search by name
var role authorization.RoleDefinition
if name != "" {
// TODO: remove this in 2.0
if name == "VirtualMachineContributor" {
name = "Virtual Machine Contributor"
}

roleDefinitions, err := client.List(ctx, scope, fmt.Sprintf("roleName eq '%s'", name))
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)
}
if roleDefinitions.Values()[0].ID == nil {
return fmt.Errorf("Error loading Role Definition List: values[0].ID is nil '%s'", name)
}

defId = *roleDefinitions.Values()[0].ID
role, err = client.GetByID(ctx, defId)
if err != nil {
return fmt.Errorf("Error Getting Role Definition by ID %s: %+v", defId, err)
}
} else {
var err error
role, err = client.Get(ctx, scope, defId)
if err != nil {
return fmt.Errorf("Error loading Role Definition: %+v", err)
}
}

if role.ID == nil {
return fmt.Errorf("Error returned role had a nil ID (id %q, scope %q, name %q)", defId, scope, name)
}
d.SetId(*role.ID)

if props := role.RoleDefinitionProperties; props != nil {
d.Set("name", props.RoleName)
d.Set("role_definition_id", defId)
d.Set("description", props.Description)
d.Set("type", props.RoleType)

Expand Down
146 changes: 144 additions & 2 deletions azurerm/data_source_role_definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestAccDataSourceAzureRMRoleDefinition_basic(t *testing.T) {
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceRoleDefinition(id, ri),
Config: testAccDataSourceRoleDefinition_basic(id, ri),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "description"),
Expand All @@ -38,7 +38,138 @@ func TestAccDataSourceAzureRMRoleDefinition_basic(t *testing.T) {
})
}

func testAccDataSourceRoleDefinition(id string, rInt int) string {
func TestAccDataSourceAzureRMRoleDefinition_basicByName(t *testing.T) {
dataSourceName := "data.azurerm_role_definition.test"

id := uuid.New().String()
ri := tf.AccRandTimeInt()

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceRoleDefinition_byName(id, ri),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet(dataSourceName, "name"),
resource.TestCheckResourceAttrSet(dataSourceName, "description"),
resource.TestCheckResourceAttrSet(dataSourceName, "type"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.0", "*"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.#", "3"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.0", "Microsoft.Authorization/*/Delete"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.1", "Microsoft.Authorization/*/Write"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.2", "Microsoft.Authorization/elevateAccess/Action"),
),
},
},
})
}

func TestAccDataSourceAzureRMRoleDefinition_builtIn_contributor(t *testing.T) {
dataSourceName := "data.azurerm_role_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAzureRMRoleDefinition_builtIn("Contributor"),
Check: resource.ComposeTestCheckFunc(
testAzureRMClientConfigAttr(dataSourceName, "id", "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"),
resource.TestCheckResourceAttrSet(dataSourceName, "description"),
resource.TestCheckResourceAttrSet(dataSourceName, "type"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.0", "*"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.#", "5"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.0", "Microsoft.Authorization/*/Delete"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.1", "Microsoft.Authorization/*/Write"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.2", "Microsoft.Authorization/elevateAccess/Action"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.3", "Microsoft.Blueprint/blueprintAssignments/write"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.4", "Microsoft.Blueprint/blueprintAssignments/delete"),
),
},
},
})
}

func TestAccDataSourceAzureRMRoleDefinition_builtIn_owner(t *testing.T) {
dataSourceName := "data.azurerm_role_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAzureRMRoleDefinition_builtIn("Owner"),
Check: resource.ComposeTestCheckFunc(
testAzureRMClientConfigAttr(dataSourceName, "id", "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635"),
resource.TestCheckResourceAttrSet(dataSourceName, "description"),
resource.TestCheckResourceAttrSet(dataSourceName, "type"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.0", "*"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.#", "0"),
),
},
},
})
}

func TestAccDataSourceAzureRMRoleDefinition_builtIn_reader(t *testing.T) {
dataSourceName := "data.azurerm_role_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAzureRMRoleDefinition_builtIn("Reader"),
Check: resource.ComposeTestCheckFunc(
testAzureRMClientConfigAttr(dataSourceName, "id", "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7"),
resource.TestCheckResourceAttrSet(dataSourceName, "description"),
resource.TestCheckResourceAttrSet(dataSourceName, "type"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.0", "*/read"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.#", "0"),
),
},
},
})
}

func TestAccDataSourceAzureRMRoleDefinition_builtIn_virtualMachineContributor(t *testing.T) {
dataSourceName := "data.azurerm_role_definition.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAzureRMRoleDefinition_builtIn("VirtualMachineContributor"),
Check: resource.ComposeTestCheckFunc(
testAzureRMClientConfigAttr(dataSourceName, "id", "/providers/Microsoft.Authorization/roleDefinitions/9980e02c-c2be-4d73-94e8-173b1dc7cf3c"),
resource.TestCheckResourceAttrSet(dataSourceName, "description"),
resource.TestCheckResourceAttrSet(dataSourceName, "type"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.#", "1"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.#", "38"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.0", "Microsoft.Authorization/*/read"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.actions.15", "Microsoft.Network/networkSecurityGroups/join/action"),
resource.TestCheckResourceAttr(dataSourceName, "permissions.0.not_actions.#", "0"),
),
},
},
})
}

func testAccDataSourceAzureRMRoleDefinition_builtIn(name string) string {
return fmt.Sprintf(`
data "azurerm_role_definition" "test" {
name = "%s"
}
`, name)
}

func testAccDataSourceRoleDefinition_basic(id string, rInt int) string {
return fmt.Sprintf(`
data "azurerm_subscription" "primary" {}
Expand Down Expand Up @@ -69,3 +200,14 @@ data "azurerm_role_definition" "test" {
}
`, id, rInt)
}

func testAccDataSourceRoleDefinition_byName(id string, rInt int) string {
return fmt.Sprintf(`
%s
data "azurerm_role_definition" "byName" {
name = "${azurerm_role_definition.test.name}"
scope = "${data.azurerm_subscription.primary.id}"
}
`, testAccDataSourceRoleDefinition_basic(id, rInt))
}
2 changes: 2 additions & 0 deletions website/docs/d/builtin_role_definition.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ description: |-

Use this data source to access information about a built-in Role Definition. To access information about a custom Role Definition, [please see the `azurerm_role_definition` data source](role_definition.html) instead.

~> **NOTE:** The this datasource has been deprecated in favour of `azurerm_role_definition` that now can look up role definitions by name. As such this data source will be removed in version 2.0 of the AzureRM Provider.

## Example Usage

```hcl
Expand Down
37 changes: 32 additions & 5 deletions website/docs/d/role_definition.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,60 @@ layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_role_definition"
sidebar_current: "docs-azurerm-datasource-role-definition"
description: |-
Get information about an existing Custom Role Definition.
Get information about an existing Role Definition.
---

# Data Source: azurerm_role_definition

Use this data source to access information about an existing Custom Role Definition. To access information about a built-in Role Definition, [please see the `azurerm_builtin_role_definition` data source](builtin_role_definition.html) instead.
Use this data source to access information about an existing Role Definition.

## Example Usage

```hcl
data "azurerm_subscription" "primary" {}
data "azurerm_role_definition" "custom" {
resource "azurerm_role_definition" "custom" {
role_definition_id = "00000000-0000-0000-0000-000000000000"
name = "CustomRoleDef"
scope = "${data.azurerm_subscription.primary.id}"
#...
}
data "azurerm_role_definition" "custom" {
role_definition_id = "${azurerm_role_definition.custom.role_definition_id}"
scope = "${data.azurerm_subscription.primary.id}" # /subscriptions/00000000-0000-0000-0000-000000000000
}
data "azurerm_role_definition" "custom-byname" {
name = "${azurerm_role_definition.custom.name}"
scope = "${data.azurerm_subscription.primary.id}"
}
data "azurerm_builtin_role_definition" "builtin" {
name = "Contributor"
}
output "custom_role_definition_id" {
value = "${data.azurerm_role_definition.custom.id}"
}
output "contributor_role_definition_id" {
value = "${data.azurerm_role_definition.builtin.id}"
}
```



## Argument Reference

* `role_definition_id` - (Required) Specifies the ID of the Role Definition as a UUID/GUID.
* `name` - (Optional) Specifies the Name of either a built-in or custom Role Definition.

-> You can also use this for built-in roles such as `Contributor`, `Owner`, `Reader` and `Virtual Machine Contributor`

* `role_definition_id` - (Optional) Specifies the ID of the Role Definition as a UUID/GUID.
* `scope` - (Optional) Specifies the Scope at which the Custom Role Definition exists.

* `scope` - (Required) Specifies the Scope at which the Custom Role Definition exists.
~> **NOTE:** One of `name` or `role_definition_id` must be specified.

## Attributes Reference

Expand Down

0 comments on commit 3f5d9f1

Please sign in to comment.