Skip to content

Commit

Permalink
New Resources: azurerm_*_policy_exemption (#16293)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbfrahry authored Apr 12, 2022
1 parent 11915af commit be57a93
Show file tree
Hide file tree
Showing 25 changed files with 2,513 additions and 0 deletions.
6 changes: 6 additions & 0 deletions internal/services/policy/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"github.com/Azure/azure-sdk-for-go/services/guestconfiguration/mgmt/2020-06-25/guestconfiguration"
"github.com/Azure/azure-sdk-for-go/services/preview/policyinsights/mgmt/2019-10-01-preview/policyinsights"
"github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2021-06-01-preview/policy"
policyPreview "github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2021-06-01-preview/policy"
"github.com/hashicorp/terraform-provider-azurerm/internal/common"
)

type Client struct {
AssignmentsClient *policy.AssignmentsClient
DefinitionsClient *policy.DefinitionsClient
ExemptionsClient *policyPreview.ExemptionsClient
SetDefinitionsClient *policy.SetDefinitionsClient
RemediationsClient *policyinsights.RemediationsClient
GuestConfigurationAssignmentsClient *guestconfiguration.AssignmentsClient
Expand All @@ -22,6 +24,9 @@ func NewClient(o *common.ClientOptions) *Client {
definitionsClient := policy.NewDefinitionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&definitionsClient.Client, o.ResourceManagerAuthorizer)

exemptionsClient := policyPreview.NewExemptionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&exemptionsClient.Client, o.ResourceManagerAuthorizer)

setDefinitionsClient := policy.NewSetDefinitionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&setDefinitionsClient.Client, o.ResourceManagerAuthorizer)

Expand All @@ -34,6 +39,7 @@ func NewClient(o *common.ClientOptions) *Client {
return &Client{
AssignmentsClient: &assignmentsClient,
DefinitionsClient: &definitionsClient,
ExemptionsClient: &exemptionsClient,
SetDefinitionsClient: &setDefinitionsClient,
RemediationsClient: &remediationsClient,
GuestConfigurationAssignmentsClient: &guestConfigurationAssignmentsClient,
Expand Down
243 changes: 243 additions & 0 deletions internal/services/policy/exemption_management_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
package policy

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/preview/resources/mgmt/2021-06-01-preview/policy"
"github.com/Azure/go-autorest/autorest/date"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-provider-azurerm/helpers/tf"
azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
managmentGroupParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/managementgroup/parse"
managementGroupValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/managementgroup/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/validate"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func resourceArmManagementGroupPolicyExemption() *pluginsdk.Resource {
return &pluginsdk.Resource{
Create: resourceArmManagementGroupPolicyExemptionCreateUpdate,
Read: resourceArmManagementGroupPolicyExemptionRead,
Update: resourceArmManagementGroupPolicyExemptionCreateUpdate,
Delete: resourceArmManagementGroupPolicyExemptionDelete,

Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error {
_, err := parse.ResourcePolicyExemptionID(id)
return err
}),

Timeouts: &pluginsdk.ResourceTimeout{
Create: pluginsdk.DefaultTimeout(30 * time.Minute),
Read: pluginsdk.DefaultTimeout(5 * time.Minute),
Update: pluginsdk.DefaultTimeout(30 * time.Minute),
Delete: pluginsdk.DefaultTimeout(30 * time.Minute),
},

Schema: map[string]*pluginsdk.Schema{
"name": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"management_group_id": {
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: managementGroupValidate.ManagementGroupID,
},

"exemption_category": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{
string(policy.ExemptionCategoryMitigated),
string(policy.ExemptionCategoryWaiver),
}, false),
},

"policy_assignment_id": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validate.PolicyAssignmentID,
},

"display_name": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(1, 128),
},

"description": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(1, 512),
},

"policy_definition_reference_ids": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringIsNotEmpty,
},
},

"expires_on": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: azValidate.ISO8601DateTime,
},

"metadata": metadataSchema(),
},
}
}

func resourceArmManagementGroupPolicyExemptionCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Policy.ExemptionsClient
ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

id := parse.NewResourcePolicyExemptionId(d.Get("management_group_id").(string), d.Get("name").(string))

managementGroupId, err := managmentGroupParse.ManagementGroupID(id.ResourceId)
if err != nil {
return err
}

if d.IsNewResource() {
existing, err := client.Get(ctx, managementGroupId.ID(), id.Name)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("checking for presence of existing %s: %+v", id.ID(), err)
}
}
if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_management_group_policy_exemption", *existing.ID)
}
}

exemption := policy.Exemption{
ExemptionProperties: &policy.ExemptionProperties{
PolicyAssignmentID: utils.String(d.Get("policy_assignment_id").(string)),
PolicyDefinitionReferenceIds: utils.ExpandStringSlice(d.Get("policy_definition_reference_ids").([]interface{})),
ExemptionCategory: policy.ExemptionCategory(d.Get("exemption_category").(string)),
},
}

if v, ok := d.GetOk("display_name"); ok {
exemption.ExemptionProperties.DisplayName = utils.String(v.(string))
}

if v, ok := d.GetOk("description"); ok {
exemption.ExemptionProperties.Description = utils.String(v.(string))
}

if v, ok := d.GetOk("expires_on"); ok {
t, err := date.ParseTime(time.RFC3339, v.(string))
if err != nil {
return fmt.Errorf("expanding `expires_on`: %+v", err)
}
exemption.ExemptionProperties.ExpiresOn = &date.Time{Time: t}
}

if metaDataString := d.Get("metadata").(string); metaDataString != "" {
metaData, err := structure.ExpandJsonFromString(metaDataString)
if err != nil {
return fmt.Errorf("unable to parse metadata: %+v", err)
}
exemption.ExemptionProperties.Metadata = &metaData
}

if _, err := client.CreateOrUpdate(ctx, managementGroupId.ID(), id.Name, exemption); err != nil {
return fmt.Errorf("creating/updating %s: %+v", id.ID(), err)
}

d.SetId(id.ID())

return resourceArmManagementGroupPolicyExemptionRead(d, meta)
}

func resourceArmManagementGroupPolicyExemptionRead(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Policy.ExemptionsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.ResourcePolicyExemptionID(d.Id())
if err != nil {
return fmt.Errorf("reading Policy Exemption: %+v", err)
}

managementGroupId, err := managmentGroupParse.ManagementGroupID(id.ResourceId)
if err != nil {
return err
}

resp, err := client.Get(ctx, managementGroupId.ID(), id.Name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[INFO] Error reading Policy Exemption %q - removing from state", d.Id())
d.SetId("")
return nil
}

return fmt.Errorf("reading %s: %+v", id.ID(), err)
}

d.Set("name", resp.Name)
d.Set("management_group_id", managementGroupId.ID())
if props := resp.ExemptionProperties; props != nil {
d.Set("policy_assignment_id", props.PolicyAssignmentID)
d.Set("display_name", props.DisplayName)
d.Set("description", props.Description)
d.Set("exemption_category", string(props.ExemptionCategory))

if err := d.Set("policy_definition_reference_ids", utils.FlattenStringSlice(props.PolicyDefinitionReferenceIds)); err != nil {
return fmt.Errorf("setting `policy_definition_reference_ids: %+v", err)
}

expiresOn := ""
if expiresTime := props.ExpiresOn; expiresTime != nil {
expiresOn = expiresTime.String()
}
d.Set("expires_on", expiresOn)

if metadataStr := flattenJSON(props.Metadata); metadataStr != "" {
d.Set("metadata", metadataStr)
}
}

return nil
}

func resourceArmManagementGroupPolicyExemptionDelete(d *pluginsdk.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Policy.ExemptionsClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := parse.ResourcePolicyExemptionID(d.Id())
if err != nil {
return fmt.Errorf("reading Policy Exemption: %+v", err)
}

managementGroupId, err := managmentGroupParse.ManagementGroupID(id.ResourceId)
if err != nil {
return err
}

if _, err := client.Delete(ctx, managementGroupId.ID(), id.Name); err != nil {
return fmt.Errorf("deleting %s: %+v", id.ID(), err)
}

return nil
}
Loading

0 comments on commit be57a93

Please sign in to comment.