Skip to content

Commit

Permalink
Make name as a possible input variable of data source azurerm_policy_…
Browse files Browse the repository at this point in the history
…definition
  • Loading branch information
ArcturusZhang committed Mar 27, 2020
1 parent 5896055 commit c1026ff
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 56 deletions.
83 changes: 50 additions & 33 deletions azurerm/internal/services/policy/data_source_policy_definition.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package policy

import (
"context"
"fmt"
"time"

"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-05-01/policy"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
)
Expand All @@ -23,17 +23,22 @@ func dataSourceArmPolicyDefinition() *schema.Resource {
Schema: map[string]*schema.Schema{
"display_name": {
Type: schema.TypeString,
Required: true,
Optional: true,
Computed: true,
ValidateFunc: validation.StringIsNotEmpty,
ExactlyOneOf: []string{"name", "display_name"},
},
"management_group_id": {
"name": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: azure.ValidateResourceIDOrEmpty,
Computed: true,
ValidateFunc: validation.StringIsNotEmpty,
ExactlyOneOf: []string{"name", "display_name"},
},
"name": {
"management_group_id": {
Type: schema.TypeString,
Computed: true,
Optional: true,
// TODO -- temporary removed this validation, since a management group ID is always not a resource ID. add this back when there is a proper function for validation of mgmt group IDs
},
"type": {
Type: schema.TypeString,
Expand Down Expand Up @@ -68,39 +73,24 @@ func dataSourceArmPolicyDefinitionRead(d *schema.ResourceData, meta interface{})
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

name := d.Get("display_name").(string)
displayName := d.Get("display_name").(string)
name := d.Get("name").(string)
managementGroupID := d.Get("management_group_id").(string)

var policyDefinitions policy.DefinitionListResultIterator
var err error

if managementGroupID != "" {
policyDefinitions, err = client.ListByManagementGroupComplete(ctx, managementGroupID)
} else {
policyDefinitions, err = client.ListComplete(ctx)
}

if err != nil {
return fmt.Errorf("Error loading Policy Definition List: %+v", err)
}

var policyDefinition policy.Definition

for policyDefinitions.NotDone() {
def := policyDefinitions.Value()
if def.DisplayName != nil && *def.DisplayName == name {
policyDefinition = def
break
var err error
if displayName != "" {
policyDefinition, err = getPolicyDefinitionByDisplayName(ctx, client, displayName, managementGroupID)
if err != nil {
return fmt.Errorf("failed to read Policy Definition (Display Name %q): %+v", displayName, err)
}

err = policyDefinitions.NextWithContext(ctx)
} else if name != "" {
policyDefinition, err = getPolicyDefinition(ctx, client, name, managementGroupID)
if err != nil {
return fmt.Errorf("Error loading Policy Definition List: %s", err)
return fmt.Errorf("failed to read Policy Definition %q: %+v", name, err)
}
}

if policyDefinition.ID == nil {
return fmt.Errorf("Error loading Policy Definition List: could not find policy '%s'", name)
} else {
return fmt.Errorf("one of `display_name` or `name` must be set")
}

d.SetId(*policyDefinition.ID)
Expand All @@ -124,3 +114,30 @@ func dataSourceArmPolicyDefinitionRead(d *schema.ResourceData, meta interface{})

return nil
}

func getPolicyDefinitionByDisplayName(ctx context.Context, client *policy.DefinitionsClient, displayName, managementGroupID string) (policy.Definition, error) {
var policyDefinitions policy.DefinitionListResultIterator
var err error

if managementGroupID != "" {
policyDefinitions, err = client.ListByManagementGroupComplete(ctx, managementGroupID)
} else {
policyDefinitions, err = client.ListComplete(ctx)
}
if err != nil {
return policy.Definition{}, fmt.Errorf("failed to load Policy Definition List: %+v", err)
}

for policyDefinitions.NotDone() {
def := policyDefinitions.Value()
if def.DisplayName != nil && *def.DisplayName == displayName && def.ID != nil {
return def, nil
}

if err := policyDefinitions.NextWithContext(ctx); err != nil {
return policy.Definition{}, fmt.Errorf("failed to load Policy Definition List: %s", err)
}
}

return policy.Definition{}, fmt.Errorf("failed to load Policy Definition List: could not find policy '%s'", displayName)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

func TestAccDataSourceAzureRMPolicyDefinition_builtIn(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_policy_definition", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
Expand All @@ -30,6 +31,7 @@ func TestAccDataSourceAzureRMPolicyDefinition_builtIn(t *testing.T) {

func TestAccDataSourceAzureRMPolicyDefinition_builtIn_AtManagementGroup(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_policy_definition", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
Expand All @@ -44,17 +46,41 @@ func TestAccDataSourceAzureRMPolicyDefinition_builtIn_AtManagementGroup(t *testi
})
}

func TestAccDataSourceAzureRMPolicyDefinition_custom(t *testing.T) {
func TestAccDataSourceAzureRMPolicyDefinition_customByDisplayName(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_policy_definition", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAzureRMPolicyDefinition_customByDisplayName(data),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(data.ResourceName, "name", fmt.Sprintf("acctestpol-%d", data.RandomInteger)),
resource.TestCheckResourceAttr(data.ResourceName, "display_name", fmt.Sprintf("acctestpol-display-%d", data.RandomInteger)),
resource.TestCheckResourceAttr(data.ResourceName, "type", "Microsoft.Authorization/policyDefinitions"),
resource.TestCheckResourceAttr(data.ResourceName, "policy_type", "Custom"),
resource.TestCheckResourceAttr(data.ResourceName, "policy_rule", "{\"if\":{\"not\":{\"field\":\"location\",\"in\":\"[parameters('allowedLocations')]\"}},\"then\":{\"effect\":\"audit\"}}"),
resource.TestCheckResourceAttr(data.ResourceName, "parameters", "{\"allowedLocations\":{\"metadata\":{\"description\":\"The list of allowed locations for resources.\",\"displayName\":\"Allowed locations\",\"strongType\":\"location\"},\"type\":\"Array\"}}"),
resource.TestCheckResourceAttrSet(data.ResourceName, "metadata"),
),
},
},
})
}

func TestAccDataSourceAzureRMPolicyDefinition_customByName(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_policy_definition", "test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acceptance.PreCheck(t) },
Providers: acceptance.SupportedProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceCustomPolicyDefinition(data),
Config: testAccDataSourceAzureRMPolicyDefinition_customByName(data),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(data.ResourceName, "name", fmt.Sprintf("acctestpol-%d", data.RandomInteger)),
resource.TestCheckResourceAttr(data.ResourceName, "display_name", fmt.Sprintf("acctestpol-%d", data.RandomInteger)),
resource.TestCheckResourceAttr(data.ResourceName, "display_name", fmt.Sprintf("acctestpol-display-%d", data.RandomInteger)),
resource.TestCheckResourceAttr(data.ResourceName, "type", "Microsoft.Authorization/policyDefinitions"),
resource.TestCheckResourceAttr(data.ResourceName, "policy_type", "Custom"),
resource.TestCheckResourceAttr(data.ResourceName, "policy_rule", "{\"if\":{\"not\":{\"field\":\"location\",\"in\":\"[parameters('allowedLocations')]\"}},\"then\":{\"effect\":\"audit\"}}"),
Expand Down Expand Up @@ -94,7 +120,29 @@ data "azurerm_policy_definition" "test" {
`, name)
}

func testAccDataSourceCustomPolicyDefinition(data acceptance.TestData) string {
func testAccDataSourceAzureRMPolicyDefinition_customByDisplayName(data acceptance.TestData) string {
template := testAccDataSourceAzureRMPolicyDefinition_template(data)
return fmt.Sprintf(`
%s
data "azurerm_policy_definition" "test" {
display_name = azurerm_policy_definition.test_policy.display_name
}
`, template)
}

func testAccDataSourceAzureRMPolicyDefinition_customByName(data acceptance.TestData) string {
template := testAccDataSourceAzureRMPolicyDefinition_template(data)
return fmt.Sprintf(`
%s
data "azurerm_policy_definition" "test" {
name = azurerm_policy_definition.test_policy.name
}
`, template)
}

func testAccDataSourceAzureRMPolicyDefinition_template(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
Expand All @@ -104,7 +152,7 @@ resource "azurerm_policy_definition" "test_policy" {
name = "acctestpol-%d"
policy_type = "Custom"
mode = "All"
display_name = "acctestpol-%d"
display_name = "acctestpol-display-%d"
policy_rule = <<POLICY_RULE
{
Expand All @@ -120,7 +168,6 @@ resource "azurerm_policy_definition" "test_policy" {
}
POLICY_RULE
parameters = <<PARAMETERS
{
"allowedLocations": {
Expand All @@ -133,18 +180,6 @@ POLICY_RULE
}
}
PARAMETERS
metadata = <<METADATA
{
"note":"azurerm acceptance test"
}
METADATA
}
data "azurerm_policy_definition" "test" {
display_name = azurerm_policy_definition.test_policy.display_name
}
`, data.RandomInteger, data.RandomInteger)
}
14 changes: 11 additions & 3 deletions website/docs/d/policy_definition.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,27 @@ output "id" {

## Argument Reference

* `display_name` - Specifies the name of the Policy Definition.
* `name` - Specifies the name of the Policy Definition. Conflicts with `display_name`.

* `display_name` - Specifies the display name of the Policy Definition. Conflicts with `name`.

* `management_group_id` - (Optional) Only retrieve Policy Definitions from this Management Group.


## Attributes Reference

* `id` - The ID of the Policy Definition.
* `name` - The Name of the Policy Definition.

* `type` - The Type of Policy.

* `description` - The Description of the Policy.
* `policy_type` - The Type of the Policy, such as `Microsoft.Authorization/policyDefinitions`.

* `policy_type` - The Type of the Policy. Possible values are "BuiltIn", "Custom" and "NotSpecified".

* `policy_rule` - The Rule as defined (in JSON) in the Policy.

* `parameters` - Any Parameters defined in the Policy.

* `metadata` - Any Metadata defined in the Policy.

## Timeouts
Expand Down
3 changes: 1 addition & 2 deletions website/docs/r/policy_definition.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ The following arguments are supported:
* `name` - (Required) The name of the policy definition. Changing this forces a
new resource to be created.

* `policy_type` - (Required) The policy type. The value can be "BuiltIn", "Custom"
or "NotSpecified". Changing this forces a new resource to be created.
* `policy_type` - (Required) The policy type. Possible values are "BuiltIn", "Custom" and "NotSpecified". Changing this forces a new resource to be created.

* `mode` - (Required) The policy mode that allows you to specify which resource
types will be evaluated. The value can be "All", "Indexed" or
Expand Down

0 comments on commit c1026ff

Please sign in to comment.