Skip to content

Commit

Permalink
azurerm_policy_virtual_machine_configuration_assignment: Updated ex…
Browse files Browse the repository at this point in the history
…ample HCL, add datasource (hashicorp#13311)

Service team requested that we add the assignment_type = "ApplyAndMonitor" to the example usage.

Added Datasource:
azurerm_policy_virtual_machine_configuration_assignment
WodansSon authored Sep 16, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent e3aa1cf commit b9c7e09
Showing 7 changed files with 431 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package policy

import (
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/guestconfiguration/mgmt/2020-06-25/guestconfiguration"
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
"github.com/hashicorp/terraform-provider-azurerm/internal/services/policy/parse"
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azurerm/internal/timeouts"
"github.com/hashicorp/terraform-provider-azurerm/utils"
)

func dataSourcePolicyVirtualMachineConfigurationAssignment() *pluginsdk.Resource {
return &pluginsdk.Resource{
Read: dataSourcePolicyVirtualMachineConfigurationAssignmentRead,

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

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

"resource_group_name": azure.SchemaResourceGroupNameForDataSource(),

"virtual_machine_name": {
Type: pluginsdk.TypeString,
Required: true,
},

"content_hash": {
Type: pluginsdk.TypeString,
Computed: true,
},

"content_uri": {
Type: pluginsdk.TypeString,
Computed: true,
},

"assignment_hash": {
Type: pluginsdk.TypeString,
Computed: true,
},

"compliance_status": {
Type: pluginsdk.TypeString,
Computed: true,
},

"latest_report_id": {
Type: pluginsdk.TypeString,
Computed: true,
},

"last_compliance_status_checked": {
Type: pluginsdk.TypeString,
Computed: true,
},
},
}
}

func dataSourcePolicyVirtualMachineConfigurationAssignmentRead(d *pluginsdk.ResourceData, meta interface{}) error {
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
client := meta.(*clients.Client).Policy.GuestConfigurationAssignmentsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

resourceGroup := d.Get("resource_group_name").(string)
vmName := d.Get("virtual_machine_name").(string)
name := d.Get("name").(string)

id := parse.NewVirtualMachineConfigurationAssignmentID(subscriptionId, resourceGroup, vmName, name)

resp, err := client.Get(ctx, id.ResourceGroup, id.GuestConfigurationAssignmentName, id.VirtualMachineName)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[INFO] guestConfiguration %q was not found", id.GuestConfigurationAssignmentName)
return nil
}
return fmt.Errorf("retrieving %s: %+v", id, err)
}

d.SetId(id.ID())

d.Set("name", id.GuestConfigurationAssignmentName)
d.Set("resource_group_name", resourceGroup)
d.Set("virtual_machine_name", vmName)

if props := resp.Properties; props != nil {
if v := props.AssignmentHash; v != nil {
d.Set("assignment_hash", v)
}

if v := string(props.ComplianceStatus); v != "" {
d.Set("compliance_status", v)
}

if v := props.LatestReportID; v != nil {
d.Set("latest_report_id", v)
}

if v := props.LastComplianceStatusChecked; v != nil {
d.Set("last_compliance_status_checked", v.Format(time.RFC3339))
}

contentHash, contentUri := dataSourceFlattenGuestConfigurationAssignment(props.GuestConfiguration)

if contentHash != nil {
d.Set("content_hash", contentHash)
}

if contentUri != nil {
d.Set("content_uri", contentUri)
}
}
return nil
}

func dataSourceFlattenGuestConfigurationAssignment(input *guestconfiguration.Navigation) (*string, *string) {
if input == nil {
return nil, nil
}

var contentHash *string
if input.ContentHash != nil {
contentHash = input.ContentHash
}
var contentUri *string
if input.ContentURI != nil {
contentUri = input.ContentURI
}

return contentHash, contentUri
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package policy_test

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
)

type PolicyVirtualMachineConfigurationAssignmentDataSource struct {
}

func TestAccPolicyVirtualMachineConfigurationAssignmentDataSource_basic(t *testing.T) {
data := acceptance.BuildTestData(t, "data.azurerm_policy_virtual_machine_configuration_assignment", "test")
r := PolicyVirtualMachineConfigurationAssignmentDataSource{}

data.DataSourceTest(t, []acceptance.TestStep{
{
Config: r.basic(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).Key("compliance_status").Exists(),
),
},
})
}

func (r PolicyVirtualMachineConfigurationAssignmentDataSource) templateBase(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
locals {
vm_name = "acctestvm%s"
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-%d"
location = "%s"
}
resource "azurerm_virtual_network" "test" {
name = "acctestnw-%d"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
}
resource "azurerm_subnet" "test" {
name = "internal"
resource_group_name = azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.test.name
address_prefix = "10.0.2.0/24"
}
resource "azurerm_network_interface" "test" {
name = "acctestnic-%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.test.id
private_ip_address_allocation = "Dynamic"
}
}
`, data.RandomString, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger)
}

func (r PolicyVirtualMachineConfigurationAssignmentDataSource) template(data acceptance.TestData) string {
tags := ""
if strings.HasPrefix(strings.ToLower(data.Client().SubscriptionID), "85b3dbca") {
tags = `
tags = {
"azsecpack" = "nonprod"
"platformsettings.host_environment.service.platform_optedin_for_rootcerts" = "true"
}
`
}
return fmt.Sprintf(`
%s
resource "azurerm_windows_virtual_machine" "test" {
name = local.vm_name
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
size = "Standard_F2"
admin_username = "adminuser"
admin_password = "P@$$w0rd1234!"
network_interface_ids = [
azurerm_network_interface.test.id,
]
identity {
type = "SystemAssigned"
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
%s
}
`, r.templateBase(data), tags)
}

func (r PolicyVirtualMachineConfigurationAssignmentDataSource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
name = "AzureWindowsBaseline"
location = azurerm_windows_virtual_machine.test.location
virtual_machine_id = azurerm_windows_virtual_machine.test.id
configuration {
assignment_type = "ApplyAndMonitor"
version = "1.*"
parameter {
name = "Minimum Password Length;ExpectedValue"
value = "16"
}
parameter {
name = "Minimum Password Age;ExpectedValue"
value = "0"
}
parameter {
name = "Maximum Password Age;ExpectedValue"
value = "30,45"
}
parameter {
name = "Enforce Password History;ExpectedValue"
value = "10"
}
parameter {
name = "Password Must Meet Complexity Requirements;ExpectedValue"
value = "1"
}
}
}
data "azurerm_policy_virtual_machine_configuration_assignment" "test" {
name = azurerm_policy_virtual_machine_configuration_assignment.test.name
resource_group_name = azurerm_resource_group.test.name
virtual_machine_name = azurerm_windows_virtual_machine.test.name
}
`, r.template(data))
}
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package policy
import (
"fmt"
"log"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/guestconfiguration/mgmt/2020-06-25/guestconfiguration"
@@ -40,9 +41,10 @@ func resourcePolicyVirtualMachineConfigurationAssignment() *pluginsdk.Resource {

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

"location": azure.SchemaLocation(),
@@ -60,10 +62,11 @@ func resourcePolicyVirtualMachineConfigurationAssignment() *pluginsdk.Resource {
MaxItems: 1,
Elem: &pluginsdk.Resource{
Schema: map[string]*pluginsdk.Schema{
// TODO: Remove in 3.0
"name": {
Type: pluginsdk.TypeString,
Required: true,
ValidateFunc: validation.StringIsNotEmpty,
Type: pluginsdk.TypeString,
Optional: true,
Deprecated: "This field is no longer used and will be removed in the next major version of the Azure Provider",
},

"assignment_type": {
@@ -80,12 +83,14 @@ func resourcePolicyVirtualMachineConfigurationAssignment() *pluginsdk.Resource {
"content_hash": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringIsNotEmpty,
},

"content_uri": {
Type: pluginsdk.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.IsURLWithScheme([]string{"http", "https"}),
},

@@ -143,14 +148,27 @@ func resourcePolicyVirtualMachineConfigurationAssignmentCreateUpdate(d *pluginsd
return tf.ImportAsExistsError("azurerm_policy_virtual_machine_configuration_assignment", id.ID())
}
}

guestConfiguration := expandGuestConfigurationAssignment(d.Get("configuration").([]interface{}), id.GuestConfigurationAssignmentName)
parameter := guestconfiguration.Assignment{
Name: utils.String(d.Get("name").(string)),
Name: utils.String(id.GuestConfigurationAssignmentName),
Location: utils.String(location.Normalize(d.Get("location").(string))),
Properties: &guestconfiguration.AssignmentProperties{
GuestConfiguration: expandGuestConfigurationAssignment(d.Get("configuration").([]interface{})),
GuestConfiguration: guestConfiguration,
},
}

// I need to determine if the passed in guest config is a built-in config or not
// since the attribute is computed and optional I need to check the value of the
// contentURI to see if it is on a service team owned storage account or not
// all built-in guest configuration will always be on a service team owned
// storage account
if guestConfiguration.ContentURI != nil || *guestConfiguration.ContentURI != "" {
if strings.Contains(strings.ToLower(*guestConfiguration.ContentURI), "oaasguestconfig") {
parameter.Properties.GuestConfiguration.ContentHash = nil
parameter.Properties.GuestConfiguration.ContentURI = nil
}
}

if _, err := client.CreateOrUpdate(ctx, id.GuestConfigurationAssignmentName, parameter, id.ResourceGroup, id.VirtualMachineName); err != nil {
return fmt.Errorf("creating/updating %s: %+v", id, err)
}
@@ -211,14 +229,14 @@ func resourcePolicyVirtualMachineConfigurationAssignmentDelete(d *pluginsdk.Reso
return nil
}

func expandGuestConfigurationAssignment(input []interface{}) *guestconfiguration.Navigation {
func expandGuestConfigurationAssignment(input []interface{}, name string) *guestconfiguration.Navigation {
if len(input) == 0 {
return nil
}
v := input[0].(map[string]interface{})

result := guestconfiguration.Navigation{
Name: utils.String(v["name"].(string)),
Name: utils.String(name),
Version: utils.String(v["version"].(string)),
ConfigurationParameter: expandGuestConfigurationAssignmentConfigurationParameters(v["parameter"].(*pluginsdk.Set).List()),
}
@@ -255,10 +273,6 @@ func flattenGuestConfigurationAssignment(input *guestconfiguration.Navigation) [
return make([]interface{}, 0)
}

var name string
if input.Name != nil {
name = *input.Name
}
var version string
if input.Version != nil {
version = *input.Version
@@ -277,7 +291,6 @@ func flattenGuestConfigurationAssignment(input *guestconfiguration.Navigation) [
}
return []interface{}{
map[string]interface{}{
"name": name,
"assignment_type": string(assignmentType),
"content_hash": contentHash,
"content_uri": contentUri,
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package policy_test
import (
"context"
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
@@ -84,6 +85,10 @@ func (r PolicyVirtualMachineConfigurationAssignmentResource) Exists(ctx context.

func (r PolicyVirtualMachineConfigurationAssignmentResource) templateBase(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
locals {
vm_name = "acctestvm%s"
}
@@ -122,6 +127,15 @@ resource "azurerm_network_interface" "test" {
}

func (r PolicyVirtualMachineConfigurationAssignmentResource) template(data acceptance.TestData) string {
tags := ""
if strings.HasPrefix(strings.ToLower(data.Client().SubscriptionID), "85b3dbca") {
tags = `
tags = {
"azsecpack" = "nonprod"
"platformsettings.host_environment.service.platform_optedin_for_rootcerts" = "true"
}
`
}
return fmt.Sprintf(`
%s
@@ -147,20 +161,23 @@ resource "azurerm_windows_virtual_machine" "test" {
sku = "2016-Datacenter"
version = "latest"
}
%s
}
`, r.templateBase(data))
`, r.templateBase(data), tags)
}

func (r PolicyVirtualMachineConfigurationAssignmentResource) basic(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
name = "acctest-gca-%d"
location = azurerm_windows_virtual_machine.test.location
name = "WhitelistedApplication"
location = azurerm_windows_virtual_machine.test.location
virtual_machine_id = azurerm_windows_virtual_machine.test.id
configuration {
name = "WhitelistedApplication"
version = "1.*"
parameter {
@@ -169,7 +186,7 @@ resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
}
}
}
`, r.template(data), data.RandomInteger)
`, r.template(data))
}

func (r PolicyVirtualMachineConfigurationAssignmentResource) requiresImport(data acceptance.TestData) string {
@@ -182,7 +199,6 @@ resource "azurerm_policy_virtual_machine_configuration_assignment" "import" {
virtual_machine_id = azurerm_policy_virtual_machine_configuration_assignment.test.virtual_machine_id
configuration {
name = "WhitelistedApplication"
version = "1.*"
parameter {
@@ -199,12 +215,11 @@ func (r PolicyVirtualMachineConfigurationAssignmentResource) complete(data accep
%s
resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
name = "acctest-gca-%d"
name = "WhitelistedApplication"
location = azurerm_windows_virtual_machine.test.location
virtual_machine_id = azurerm_windows_virtual_machine.test.id
configuration {
name = "WhitelistedApplication"
version = "1.1.1.1"
assignment_type = "ApplyAndAutoCorrect"
content_hash = "testcontenthash"
@@ -216,20 +231,19 @@ resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
}
}
}
`, r.template(data), data.RandomInteger)
`, r.template(data))
}

func (r PolicyVirtualMachineConfigurationAssignmentResource) updateGuestConfiguration(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
name = "acctest-gca-%d"
name = "WhitelistedApplication"
location = azurerm_windows_virtual_machine.test.location
virtual_machine_id = azurerm_windows_virtual_machine.test.id
configuration {
name = "WhitelistedApplication"
version = "1.1.1.1"
assignment_type = "Audit"
content_hash = "testcontenthash2"
@@ -241,5 +255,5 @@ resource "azurerm_policy_virtual_machine_configuration_assignment" "test" {
}
}
}
`, r.template(data), data.RandomInteger)
`, r.template(data))
}
5 changes: 3 additions & 2 deletions internal/services/policy/registration.go
Original file line number Diff line number Diff line change
@@ -39,8 +39,9 @@ func (r Registration) WebsiteCategories() []string {
// SupportedDataSources returns the supported Data Sources supported by this Service
func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource {
return map[string]*pluginsdk.Resource{
"azurerm_policy_definition": dataSourceArmPolicyDefinition(),
"azurerm_policy_set_definition": dataSourceArmPolicySetDefinition(),
"azurerm_policy_definition": dataSourceArmPolicyDefinition(),
"azurerm_policy_set_definition": dataSourceArmPolicySetDefinition(),
"azurerm_policy_virtual_machine_configuration_assignment": dataSourcePolicyVirtualMachineConfigurationAssignment(),
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
subcategory: "Policy"
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_policy_virtual_machine_configuration_assignment"
description: |-
Get information about a Guest Configuration Policy.
---

# Data Source: azurerm_policy_virtual_machine_configuration_assignment

Use this data source to access information about an existing Guest Configuration Policy.

## Example Usage

```hcl
data "azurerm_policy_virtual_machine_configuration_assignment" "example" {
name = "AzureWindowsBaseline"
resource_group_name = "example-RG"
virtual_machine_name = "example-vm"
}
output "compliance_status" {
value = data.azurerm_policy_virtual_machine_configuration_assignment.example.compliance_status
}
```

## Argument Reference

* `name` - (Required) Specifies the name of the Guest Configuration Assignment.

* `resource_group_name` - (Required) Specifies the Name of the Resource Group where the Guest Configuration Assignment exists.

* `virtual_machine_name` - (Required) Only retrieve Policy Set Definitions from this Management Group.

## Attributes Reference

* `id` - The ID of the Guest Configuration Assignment.

* `content_hash` - The content hash for the Guest Configuration package.

* `content_uri` - The content URI where the Guest Configuration package is stored.

* `assignment_hash` - Combined hash of the configuration package and parameters.

* `compliance_status` - A value indicating compliance status of the machine for the assigned guest configuration. Possible return values are `Compliant`, `NonCompliant` and `Pending`.

* `last_compliance_status_checked` - Date and time, in RFC3339 format, when the machines compliance status was last checked.

* `latest_report_id` - The ID of the latest report for the guest configuration assignment.

## Timeouts

The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions:

* `read` - (Defaults to 5 minutes) Used when retrieving the Guest Configuration Assignment.
Original file line number Diff line number Diff line change
@@ -3,12 +3,14 @@ subcategory: "Policy"
layout: "azurerm"
page_title: "Azure Resource Manager: azurerm_policy_virtual_machine_configuration_assignment"
description: |-
Applies a Configuration Policy to a Virtual Machine.
Applies a Guest Configuration Policy to a Virtual Machine.
---

# azurerm_policy_virtual_machine_configuration_assignment

Applies a Configuration Policy to a Virtual Machine.
Applies a Guest Configuration Policy to a Virtual Machine.

~> **NOTE:** You can create Guest Configuration Policies without defining a `azurerm_virtual_machine_extension` resource, however the policies will not be executed until a `azurerm_virtual_machine_extension` has been provisioned to the virtual machine.

## Example Usage

@@ -85,9 +87,11 @@ resource "azurerm_policy_virtual_machine_configuration_assignment" "example" {
name = "AzureWindowsBaseline"
location = azurerm_windows_virtual_machine.example.location
virtual_machine_id = azurerm_windows_virtual_machine.example.id
configuration {
name = "AzureWindowsBaseline"
version = "1.*"
assignment_type = "ApplyAndMonitor"
version = "1.*"
parameter {
name = "Minimum Password Length;ExpectedValue"
value = "16"
@@ -116,7 +120,7 @@ resource "azurerm_policy_virtual_machine_configuration_assignment" "example" {

The following arguments are supported:

* `name` - (Required) The name of the Policy Virtual Machine Configuration Assignment. Changing this forces a new resource to be created.
* `name` - (Required) The name of the Guest Configuration that will be assigned in this Guest Configuration Assignment. Changing this forces a new resource to be created.

* `location` - (Required) The Azure location where the Policy Virtual Machine Configuration Assignment should exist. Changing this forces a new resource to be created.

@@ -128,23 +132,26 @@ The following arguments are supported:

---

An `configuration` block supports the following:
A `configuration` block supports the following:

* `name` - (Required) The name of the Guest Configuration that will be assigned in this Guest Configuration Assignment.
[comment]: # (TODO: Remove in 3.0)
* `name` - (Deprecated) This field is no longer used and will be removed in the next major version of the Azure Provider.

* `assignment_type` - (Optional) The assignment type for the Guest Configuration Assignment. Possible values are `Audit`, `ApplyAndAutoCorrect`, `ApplyAndMonitor` and `DeployAndAutoCorrect`.

* `content_hash` - (Optional) The content hash for the Guest Configuration package.

* `content_uri` - (Optional) The content URI where the Guest Configuration package is stored.

~> **NOTE:** When deploying a Custom Guest Configuration package the `content_hash` and `content_uri` fields must be defined. For Built-in Guest Configuration packages, such as the `AzureWindowsBaseline` package, the `content_hash` and `content_uri` should not be defined, rather these fields will be returned after the Built-in Guest Configuration package has been provisioned. For more information on guest configuration assignments please see the [product documentation](https://docs.microsoft.com/azure/governance/policy/concepts/guest-configuration-assignments).

* `parameter` - (Optional) One or more `parameter` blocks which define what configuration parameters and values against.

* `version` - (Optional) The version of the Guest Configuration that will be assigned in this Guest Configuration Assignment.

---

An `parameter` block supports the following:
A `parameter` block supports the following:

* `name` - (Required) The name of the configuration parameter to check.

@@ -156,6 +163,7 @@ In addition to the Arguments listed above - the following Attributes are exporte

* `id` - The ID of the Policy Virtual Machine Configuration Assignment.


## Timeouts

The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions:

0 comments on commit b9c7e09

Please sign in to comment.