From ba5ea18f51a37cef57369c813feec825a88e3e2f Mon Sep 17 00:00:00 2001 From: xuwu1 Date: Thu, 16 Feb 2023 11:02:38 +0800 Subject: [PATCH] add new data source for built-in policy definition --- internal/services/policy/policy.go | 8 +- .../policy_definition_built_in_data_source.go | 20 ++ ...cy_definition_built_in_data_source_test.go | 42 ++++ .../policy/policy_definition_data_source.go | 230 +++++++++--------- .../policy_definition_data_source_test.go | 1 - .../policy/policy_definition_resource.go | 8 +- internal/services/policy/registration.go | 1 + 7 files changed, 187 insertions(+), 123 deletions(-) create mode 100644 internal/services/policy/policy_definition_built_in_data_source.go create mode 100644 internal/services/policy/policy_definition_built_in_data_source_test.go diff --git a/internal/services/policy/policy.go b/internal/services/policy/policy.go index a827cc6245f8..f5e2ee3cdc30 100644 --- a/internal/services/policy/policy.go +++ b/internal/services/policy/policy.go @@ -11,14 +11,14 @@ import ( ) func getPolicyDefinitionByDisplayName(ctx context.Context, client *policy.DefinitionsClient, displayName, managementGroupName string, - typ policy.Type) (policy.Definition, error) { + builtInOnly bool) (policy.Definition, error) { var policyDefinitions policy.DefinitionListResultIterator var err error if managementGroupName != "" { policyDefinitions, err = client.ListByManagementGroupComplete(ctx, managementGroupName, "", nil) } else { - if typ == policy.TypeBuiltIn { + if builtInOnly { policyDefinitions, err = client.ListBuiltInComplete(ctx, "", nil) } else { policyDefinitions, err = client.ListComplete(ctx, "", nil) @@ -53,10 +53,10 @@ func getPolicyDefinitionByDisplayName(ctx context.Context, client *policy.Defini return results[0], nil } -func getPolicyDefinitionByName(ctx context.Context, client *policy.DefinitionsClient, name, managementGroupName string, typ policy.Type) (res policy.Definition, err error) { +func getPolicyDefinitionByName(ctx context.Context, client *policy.DefinitionsClient, name, managementGroupName string) (res policy.Definition, err error) { if managementGroupName == "" { res, err = client.GetBuiltIn(ctx, name) - if utils.ResponseWasNotFound(res.Response) && typ != policy.TypeBuiltIn { + if utils.ResponseWasNotFound(res.Response) { res, err = client.Get(ctx, name) } } else { diff --git a/internal/services/policy/policy_definition_built_in_data_source.go b/internal/services/policy/policy_definition_built_in_data_source.go new file mode 100644 index 000000000000..0e9ed58d4c86 --- /dev/null +++ b/internal/services/policy/policy_definition_built_in_data_source.go @@ -0,0 +1,20 @@ +package policy + +import ( + "time" + + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" +) + +// dataSourceArmPolicyDefinitionBuiltIn read built-in policy definition only +func dataSourceArmPolicyDefinitionBuiltIn() *pluginsdk.Resource { + return &pluginsdk.Resource{ + Read: policyDefinitionReadFunc(true), + + Timeouts: &pluginsdk.ResourceTimeout{ + Read: pluginsdk.DefaultTimeout(5 * time.Minute), + }, + + Schema: policyDefinitionDataSourceSchema(), + } +} diff --git a/internal/services/policy/policy_definition_built_in_data_source_test.go b/internal/services/policy/policy_definition_built_in_data_source_test.go new file mode 100644 index 000000000000..801b5dd4165d --- /dev/null +++ b/internal/services/policy/policy_definition_built_in_data_source_test.go @@ -0,0 +1,42 @@ +package policy_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" + "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" +) + +type PolicyDefinitionBuiltInDataSource struct{} + +func TestAccDataSourceAzureRMPolicyDefinitionBuiltIn_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_policy_definition_built_in", "test") + d := PolicyDefinitionBuiltInDataSource{} + + data.DataSourceTest(t, []acceptance.TestStep{ + { + Config: d.basic("Allowed resource types"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("id").HasValue("/providers/Microsoft.Authorization/policyDefinitions/a08ec900-254a-4555-9bf5-e42af04b5c5c"), + check.That(data.ResourceName).Key("name").HasValue("a08ec900-254a-4555-9bf5-e42af04b5c5c"), + check.That(data.ResourceName).Key("display_name").HasValue("Allowed resource types"), + check.That(data.ResourceName).Key("type").HasValue("Microsoft.Authorization/policyDefinitions"), + check.That(data.ResourceName).Key("description").HasValue("This policy enables you to specify the resource types that your organization can deploy. Only resource types that support 'tags' and 'location' will be affected by this policy. To restrict all resources please duplicate this policy and change the 'mode' to 'All'."), + check.That(data.ResourceName).Key("mode").HasValue("Indexed"), + ), + }, + }) +} + +func (d PolicyDefinitionBuiltInDataSource) basic(name string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_policy_definition_built_in" "test" { + display_name = "%s" +} +`, name) +} diff --git a/internal/services/policy/policy_definition_data_source.go b/internal/services/policy/policy_definition_data_source.go index 3fbc6a2a126d..e6d552d4fca2 100644 --- a/internal/services/policy/policy_definition_data_source.go +++ b/internal/services/policy/policy_definition_data_source.go @@ -14,147 +14,149 @@ import ( func dataSourceArmPolicyDefinition() *pluginsdk.Resource { return &pluginsdk.Resource{ - Read: dataSourceArmPolicyDefinitionRead, + Read: policyDefinitionReadFunc(false), Timeouts: &pluginsdk.ResourceTimeout{ Read: pluginsdk.DefaultTimeout(5 * time.Minute), }, - Schema: map[string]*pluginsdk.Schema{ - "display_name": { - Type: pluginsdk.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringIsNotEmpty, - ExactlyOneOf: []string{"name", "display_name"}, - }, + Schema: policyDefinitionDataSourceSchema(), + } +} - "name": { - Type: pluginsdk.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringIsNotEmpty, - ExactlyOneOf: []string{"name", "display_name"}, - }, +func policyDefinitionDataSourceSchema() map[string]*pluginsdk.Schema { + return map[string]*pluginsdk.Schema{ + "display_name": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringIsNotEmpty, + ExactlyOneOf: []string{"name", "display_name"}, + }, - "management_group_name": { - Type: pluginsdk.TypeString, - Optional: true, - }, + "name": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringIsNotEmpty, + ExactlyOneOf: []string{"name", "display_name"}, + }, - "type": { - Type: pluginsdk.TypeString, - Computed: true, - }, + "management_group_name": { + Type: pluginsdk.TypeString, + Optional: true, + }, - "description": { - Type: pluginsdk.TypeString, - Computed: true, - }, + "type": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "policy_type": { - Type: pluginsdk.TypeString, - Computed: true, - Optional: true, - ValidateFunc: validation.StringInSlice(func() (res []string) { - for _, val := range policy.PossibleTypeValues() { - res = append(res, string(val)) - } - return - }(), false), - }, + "description": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "policy_rule": { - Type: pluginsdk.TypeString, - Computed: true, - }, + "policy_type": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "parameters": { - Type: pluginsdk.TypeString, - Computed: true, - }, + "policy_rule": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "metadata": { - Type: pluginsdk.TypeString, - Computed: true, - }, + "parameters": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "role_definition_ids": { - Type: pluginsdk.TypeList, - Computed: true, - Elem: &pluginsdk.Schema{ - Type: pluginsdk.TypeString, - }, - }, + "metadata": { + Type: pluginsdk.TypeString, + Computed: true, + }, - "mode": { - Type: pluginsdk.TypeString, - Computed: true, + "role_definition_ids": { + Type: pluginsdk.TypeList, + Computed: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, }, }, + + "mode": { + Type: pluginsdk.TypeString, + Computed: true, + }, } } -func dataSourceArmPolicyDefinitionRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Policy.DefinitionsClient - ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) - defer cancel() - - displayName := d.Get("display_name").(string) - name := d.Get("name").(string) - managementGroupName := "" - if v, ok := d.GetOk("management_group_name"); ok { - managementGroupName = v.(string) - } +func policyDefinitionReadFunc(builtInOnly bool) func(d *pluginsdk.ResourceData, meta interface{}) error { + return func(d *pluginsdk.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Policy.DefinitionsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + displayName := d.Get("display_name").(string) + name := d.Get("name").(string) + managementGroupName := "" + if v, ok := d.GetOk("management_group_name"); ok { + managementGroupName = v.(string) + } - var policyDefinition policy.Definition - var err error - // one of display_name and name must be non-empty, this is guaranteed by schema - policyType := policy.Type(d.Get("policy_type").(string)) - if displayName != "" { - policyDefinition, err = getPolicyDefinitionByDisplayName(ctx, client, displayName, managementGroupName, policyType) - if err != nil { - return fmt.Errorf("reading Policy Definition (Display Name %q): %+v", displayName, err) + var policyDefinition policy.Definition + var err error + // one of display_name and name must be non-empty, this is guaranteed by schema + if displayName != "" { + policyDefinition, err = getPolicyDefinitionByDisplayName(ctx, client, displayName, managementGroupName, builtInOnly) + if err != nil { + return fmt.Errorf("reading Policy Definition (Display Name %q): %+v", displayName, err) + } } - } - if name != "" { - policyDefinition, err = getPolicyDefinitionByName(ctx, client, name, managementGroupName, policyType) + if name != "" { + if builtInOnly && managementGroupName == "" { + policyDefinition, err = client.GetBuiltIn(ctx, name) + } else { + policyDefinition, err = getPolicyDefinitionByName(ctx, client, name, managementGroupName) + } + if err != nil { + return fmt.Errorf("reading Policy Definition %q: %+v", name, err) + } + } + + id, err := parse.PolicyDefinitionID(*policyDefinition.ID) if err != nil { - return fmt.Errorf("reading Policy Definition %q: %+v", name, err) + return fmt.Errorf("parsing Policy Definition %q: %+v", *policyDefinition.ID, err) } - } - id, err := parse.PolicyDefinitionID(*policyDefinition.ID) - if err != nil { - return fmt.Errorf("parsing Policy Definition %q: %+v", *policyDefinition.ID, err) - } + d.SetId(id.Id) + d.Set("name", policyDefinition.Name) + d.Set("display_name", policyDefinition.DisplayName) + d.Set("description", policyDefinition.Description) + d.Set("type", policyDefinition.Type) + d.Set("policy_type", policyDefinition.PolicyType) + d.Set("mode", policyDefinition.Mode) + + policyRule := policyDefinition.PolicyRule.(map[string]interface{}) + if policyRuleStr := flattenJSON(policyRule); policyRuleStr != "" { + d.Set("policy_rule", policyRuleStr) + roleIDs, _ := getPolicyRoleDefinitionIDs(policyRuleStr) + d.Set("role_definition_ids", roleIDs) + } else { + return fmt.Errorf("flattening Policy Definition Rule %q: %+v", name, err) + } - d.SetId(id.Id) - d.Set("name", policyDefinition.Name) - d.Set("display_name", policyDefinition.DisplayName) - d.Set("description", policyDefinition.Description) - d.Set("type", policyDefinition.Type) - d.Set("policy_type", policyDefinition.PolicyType) - d.Set("mode", policyDefinition.Mode) - - policyRule := policyDefinition.PolicyRule.(map[string]interface{}) - if policyRuleStr := flattenJSON(policyRule); policyRuleStr != "" { - d.Set("policy_rule", policyRuleStr) - roleIDs, _ := getPolicyRoleDefinitionIDs(policyRuleStr) - d.Set("role_definition_ids", roleIDs) - } else { - return fmt.Errorf("flattening Policy Definition Rule %q: %+v", name, err) - } + if metadataStr := flattenJSON(policyDefinition.Metadata); metadataStr != "" { + d.Set("metadata", metadataStr) + } - if metadataStr := flattenJSON(policyDefinition.Metadata); metadataStr != "" { - d.Set("metadata", metadataStr) - } + if parametersStr, err := flattenParameterDefinitionsValueToString(policyDefinition.Parameters); err == nil { + d.Set("parameters", parametersStr) + } else { + return fmt.Errorf("failed to flatten Policy Parameters %q: %+v", name, err) + } - if parametersStr, err := flattenParameterDefinitionsValueToString(policyDefinition.Parameters); err == nil { - d.Set("parameters", parametersStr) - } else { - return fmt.Errorf("failed to flatten Policy Parameters %q: %+v", name, err) + return nil } - - return nil } diff --git a/internal/services/policy/policy_definition_data_source_test.go b/internal/services/policy/policy_definition_data_source_test.go index dc56cf519204..bb1b89e7b140 100644 --- a/internal/services/policy/policy_definition_data_source_test.go +++ b/internal/services/policy/policy_definition_data_source_test.go @@ -127,7 +127,6 @@ provider "azurerm" { data "azurerm_policy_definition" "test" { display_name = "%s" - policy_type = "BuiltIn" } `, name) } diff --git a/internal/services/policy/policy_definition_resource.go b/internal/services/policy/policy_definition_resource.go index 2d322f9a6c6f..fdd3e4c105d5 100644 --- a/internal/services/policy/policy_definition_resource.go +++ b/internal/services/policy/policy_definition_resource.go @@ -63,7 +63,7 @@ func resourceArmPolicyDefinitionCreateUpdate(d *pluginsdk.ResourceData, meta int } if d.IsNewResource() { - existing, err := getPolicyDefinitionByName(ctx, client, name, managementGroupName, "") + existing, err := getPolicyDefinitionByName(ctx, client, name, managementGroupName) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { return fmt.Errorf("checking for presence of existing Policy Definition %q: %+v", name, err) @@ -143,7 +143,7 @@ func resourceArmPolicyDefinitionCreateUpdate(d *pluginsdk.ResourceData, meta int return fmt.Errorf("waiting for Policy Definition %q to become available: %+v", name, err) } - resp, err := getPolicyDefinitionByName(ctx, client, name, managementGroupName, "") + resp, err := getPolicyDefinitionByName(ctx, client, name, managementGroupName) if err != nil { return err } @@ -179,7 +179,7 @@ func resourceArmPolicyDefinitionRead(d *pluginsdk.ResourceData, meta interface{} managementGroupName = managementGroupId.Name } - resp, err := getPolicyDefinitionByName(ctx, client, id.Name, managementGroupName, "") + resp, err := getPolicyDefinitionByName(ctx, client, id.Name, managementGroupName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[INFO] Error reading Policy Definition %q - removing from state", d.Id()) @@ -259,7 +259,7 @@ func resourceArmPolicyDefinitionDelete(d *pluginsdk.ResourceData, meta interface func policyDefinitionRefreshFunc(ctx context.Context, client *policy.DefinitionsClient, name, managementGroupID string) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { - res, err := getPolicyDefinitionByName(ctx, client, name, managementGroupID, "") + res, err := getPolicyDefinitionByName(ctx, client, name, managementGroupID) if err != nil { return nil, strconv.Itoa(res.StatusCode), fmt.Errorf("issuing read request in policyAssignmentRefreshFunc for Policy Assignment %q: %+v", name, err) } diff --git a/internal/services/policy/registration.go b/internal/services/policy/registration.go index f22756c2fae7..1a35bd55e437 100644 --- a/internal/services/policy/registration.go +++ b/internal/services/policy/registration.go @@ -47,6 +47,7 @@ func (r Registration) WebsiteCategories() []string { func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ "azurerm_policy_definition": dataSourceArmPolicyDefinition(), + "azurerm_policy_definition_built_in": dataSourceArmPolicyDefinitionBuiltIn(), "azurerm_policy_set_definition": dataSourceArmPolicySetDefinition(), "azurerm_policy_virtual_machine_configuration_assignment": dataSourcePolicyVirtualMachineConfigurationAssignment(), }