From b79bdc613adc78789bb3417514562e9b569d317e Mon Sep 17 00:00:00 2001 From: evoio Date: Thu, 5 Sep 2019 03:22:31 +0100 Subject: [PATCH] Add Proximity Placement Group Resources + Support (#4020) (fixes #4127) --- .../data_source_proximity_placement_group.go | 54 ++++ ...a_source_proximity_placement_group_test.go | 43 +++ azurerm/helpers/azure/location.go | 1 + azurerm/internal/services/compute/client.go | 57 ++-- azurerm/provider.go | 2 + azurerm/resource_arm_availability_set.go | 23 ++ azurerm/resource_arm_availability_set_test.go | 67 ++++- .../resource_arm_proximity_placement_group.go | 124 ++++++++ ...urce_arm_proximity_placement_group_test.go | 275 ++++++++++++++++++ azurerm/resource_arm_virtual_machine.go | 26 +- .../resource_arm_virtual_machine_scale_set.go | 22 ++ ...urce_arm_virtual_machine_scale_set_test.go | 115 ++++++++ azurerm/resource_arm_virtual_machine_test.go | 133 ++++++++- .../d/proximity_placement_group.html.markdown | 38 +++ website/docs/r/availability_set.html.markdown | 2 + .../r/proximity_placement_group.html.markdown | 65 +++++ website/docs/r/virtual_machine.html.markdown | 2 + .../r/virtual_machine_scale_set.html.markdown | 2 + 18 files changed, 1012 insertions(+), 39 deletions(-) create mode 100644 azurerm/data_source_proximity_placement_group.go create mode 100644 azurerm/data_source_proximity_placement_group_test.go create mode 100644 azurerm/resource_arm_proximity_placement_group.go create mode 100644 azurerm/resource_arm_proximity_placement_group_test.go create mode 100644 website/docs/d/proximity_placement_group.html.markdown create mode 100644 website/docs/r/proximity_placement_group.html.markdown diff --git a/azurerm/data_source_proximity_placement_group.go b/azurerm/data_source_proximity_placement_group.go new file mode 100644 index 000000000000..cc1d184ca0dd --- /dev/null +++ b/azurerm/data_source_proximity_placement_group.go @@ -0,0 +1,54 @@ +package azurerm + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmProximityPlacementGroup() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmProximityPlacementGroupRead, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.NoZeroValues, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmProximityPlacementGroupRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := meta.(*ArmClient).StopContext + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Proximity Placement Group %q (Resource Group %q) was not found", name, resourceGroup) + } + + return fmt.Errorf("Error making Read request on Proximity Placement Group %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*resp.ID) + + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/data_source_proximity_placement_group_test.go b/azurerm/data_source_proximity_placement_group_test.go new file mode 100644 index 000000000000..c0faa49ff11b --- /dev/null +++ b/azurerm/data_source_proximity_placement_group_test.go @@ -0,0 +1,43 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccProximityPlacementGroupDataSource_basic(t *testing.T) { + dataSourceName := "data.azurerm_proximity_placement_group.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccProximityPlacementGroupDataSource_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "location"), + resource.TestCheckResourceAttrSet(dataSourceName, "name"), + resource.TestCheckResourceAttrSet(dataSourceName, "resource_group_name"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "2"), + ), + }, + }, + }) +} + +func testAccProximityPlacementGroupDataSource_basic(rInt int, location string) string { + return fmt.Sprintf(` +%s + +data "azurerm_proximity_placement_group" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + name = "${azurerm_proximity_placement_group.test.name}" +} +`, testAccProximityPlacementGroup_withTags(rInt, location)) +} diff --git a/azurerm/helpers/azure/location.go b/azurerm/helpers/azure/location.go index 64c6bb78732d..c2d0341aaefa 100644 --- a/azurerm/helpers/azure/location.go +++ b/azurerm/helpers/azure/location.go @@ -27,6 +27,7 @@ func SchemaLocationOptional() *schema.Schema { } } +// todo should we change this to SchemaLocationComputed func SchemaLocationForDataSource() *schema.Schema { return &schema.Schema{ Type: schema.TypeString, diff --git a/azurerm/internal/services/compute/client.go b/azurerm/internal/services/compute/client.go index 8b6d64359be7..b04c662c6406 100644 --- a/azurerm/internal/services/compute/client.go +++ b/azurerm/internal/services/compute/client.go @@ -6,19 +6,20 @@ import ( ) type Client struct { - AvailabilitySetsClient *compute.AvailabilitySetsClient - DisksClient *compute.DisksClient - GalleriesClient *compute.GalleriesClient - GalleryImagesClient *compute.GalleryImagesClient - GalleryImageVersionsClient *compute.GalleryImageVersionsClient - ImagesClient *compute.ImagesClient - SnapshotsClient *compute.SnapshotsClient - UsageClient *compute.UsageClient - VMExtensionImageClient *compute.VirtualMachineExtensionImagesClient - VMExtensionClient *compute.VirtualMachineExtensionsClient - VMScaleSetClient *compute.VirtualMachineScaleSetsClient - VMClient *compute.VirtualMachinesClient - VMImageClient *compute.VirtualMachineImagesClient + AvailabilitySetsClient *compute.AvailabilitySetsClient + DisksClient *compute.DisksClient + GalleriesClient *compute.GalleriesClient + GalleryImagesClient *compute.GalleryImagesClient + GalleryImageVersionsClient *compute.GalleryImageVersionsClient + ProximityPlacementGroupsClient *compute.ProximityPlacementGroupsClient + ImagesClient *compute.ImagesClient + SnapshotsClient *compute.SnapshotsClient + UsageClient *compute.UsageClient + VMExtensionImageClient *compute.VirtualMachineExtensionImagesClient + VMExtensionClient *compute.VirtualMachineExtensionsClient + VMScaleSetClient *compute.VirtualMachineScaleSetsClient + VMClient *compute.VirtualMachinesClient + VMImageClient *compute.VirtualMachineImagesClient } func BuildClient(o *common.ClientOptions) *Client { @@ -41,6 +42,9 @@ func BuildClient(o *common.ClientOptions) *Client { ImagesClient := compute.NewImagesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&ImagesClient.Client, o.ResourceManagerAuthorizer) + ProximityPlacementGroupsClient := compute.NewProximityPlacementGroupsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&ProximityPlacementGroupsClient.Client, o.ResourceManagerAuthorizer) + SnapshotsClient := compute.NewSnapshotsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&SnapshotsClient.Client, o.ResourceManagerAuthorizer) @@ -63,18 +67,19 @@ func BuildClient(o *common.ClientOptions) *Client { o.ConfigureClient(&VMClient.Client, o.ResourceManagerAuthorizer) return &Client{ - AvailabilitySetsClient: &AvailabilitySetsClient, - DisksClient: &DisksClient, - GalleriesClient: &GalleriesClient, - GalleryImagesClient: &GalleryImagesClient, - GalleryImageVersionsClient: &GalleryImageVersionsClient, - ImagesClient: &ImagesClient, - SnapshotsClient: &SnapshotsClient, - UsageClient: &UsageClient, - VMExtensionImageClient: &VMExtensionImageClient, - VMExtensionClient: &VMExtensionClient, - VMScaleSetClient: &VMScaleSetClient, - VMClient: &VMClient, - VMImageClient: &VMImageClient, + AvailabilitySetsClient: &AvailabilitySetsClient, + DisksClient: &DisksClient, + GalleriesClient: &GalleriesClient, + GalleryImagesClient: &GalleryImagesClient, + GalleryImageVersionsClient: &GalleryImageVersionsClient, + ImagesClient: &ImagesClient, + ProximityPlacementGroupsClient: &ProximityPlacementGroupsClient, + SnapshotsClient: &SnapshotsClient, + UsageClient: &UsageClient, + VMExtensionImageClient: &VMExtensionImageClient, + VMExtensionClient: &VMExtensionClient, + VMScaleSetClient: &VMScaleSetClient, + VMClient: &VMClient, + VMImageClient: &VMImageClient, } } diff --git a/azurerm/provider.go b/azurerm/provider.go index 332e82ae169b..6a06bbad37a8 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -92,6 +92,7 @@ func Provider() terraform.ResourceProvider { "azurerm_notification_hub": dataSourceNotificationHub(), "azurerm_platform_image": dataSourceArmPlatformImage(), "azurerm_policy_definition": dataSourceArmPolicyDefinition(), + "azurerm_proximity_placement_group": dataSourceArmProximityPlacementGroup(), "azurerm_public_ip": dataSourceArmPublicIP(), "azurerm_public_ips": dataSourceArmPublicIPs(), "azurerm_recovery_services_vault": dataSourceArmRecoveryServicesVault(), @@ -332,6 +333,7 @@ func Provider() terraform.ResourceProvider { "azurerm_private_dns_zone": resourceArmPrivateDnsZone(), "azurerm_private_dns_a_record": resourceArmPrivateDnsARecord(), "azurerm_private_dns_cname_record": resourceArmPrivateDnsCNameRecord(), + "azurerm_proximity_placement_group": resourceArmProximityPlacementGroup(), "azurerm_public_ip": resourceArmPublicIp(), "azurerm_public_ip_prefix": resourceArmPublicIpPrefix(), "azurerm_recovery_network_mapping": resourceArmRecoveryServicesNetworkMapping(), diff --git a/azurerm/resource_arm_availability_set.go b/azurerm/resource_arm_availability_set.go index 255bb168234a..f0b38cdab81b 100644 --- a/azurerm/resource_arm_availability_set.go +++ b/azurerm/resource_arm_availability_set.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" @@ -59,6 +60,18 @@ func resourceArmAvailabilitySet() *schema.Resource { ForceNew: true, }, + "proximity_placement_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + + // We have to ignore case due to incorrect capitalisation of resource group name in + // proximity placement group ID in the response we get from the API request + // + // todo can be removed when https://github.com/Azure/azure-sdk-for-go/issues/5699 is fixed + DiffSuppressFunc: suppress.CaseDifference, + }, + "tags": tags.Schema(), }, } @@ -102,6 +115,12 @@ func resourceArmAvailabilitySetCreateUpdate(d *schema.ResourceData, meta interfa Tags: tags.Expand(t), } + if v, ok := d.GetOk("proximity_placement_group_id"); ok { + availSet.AvailabilitySetProperties.ProximityPlacementGroup = &compute.SubResource{ + ID: utils.String(v.(string)), + } + } + if managed { n := "Aligned" availSet.Sku = &compute.Sku{ @@ -151,6 +170,10 @@ func resourceArmAvailabilitySetRead(d *schema.ResourceData, meta interface{}) er if props := resp.AvailabilitySetProperties; props != nil { d.Set("platform_update_domain_count", props.PlatformUpdateDomainCount) d.Set("platform_fault_domain_count", props.PlatformFaultDomainCount) + + if proximityPlacementGroup := props.ProximityPlacementGroup; proximityPlacementGroup != nil { + d.Set("proximity_placement_group_id", proximityPlacementGroup.ID) + } } return tags.FlattenAndSet(d, resp.Tags) diff --git a/azurerm/resource_arm_availability_set_test.go b/azurerm/resource_arm_availability_set_test.go index 40fe47c26bf8..c2abff1d1757 100644 --- a/azurerm/resource_arm_availability_set_test.go +++ b/azurerm/resource_arm_availability_set_test.go @@ -2,6 +2,7 @@ package azurerm import ( "fmt" + "net/http" "testing" "github.com/hashicorp/terraform/helper/resource" @@ -132,6 +133,32 @@ func TestAccAzureRMAvailabilitySet_withTags(t *testing.T) { }) } +func TestAccAzureRMAvailabilitySet_withPPG(t *testing.T) { + resourceName := "azurerm_availability_set.test" + ri := tf.AccRandTimeInt() + config := testAccAzureRMAvailabilitySet_withPPG(ri, testLocation()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAvailabilitySetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAvailabilitySetExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "proximity_placement_group_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAzureRMAvailabilitySet_withDomainCounts(t *testing.T) { resourceName := "azurerm_availability_set.test" ri := tf.AccRandTimeInt() @@ -193,21 +220,24 @@ func testCheckAzureRMAvailabilitySetExists(resourceName string) resource.TestChe return fmt.Errorf("Not found: %s", resourceName) } - availSetName := rs.Primary.Attributes["name"] + // Name of the actual scale set + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for availability set: %s", availSetName) + return fmt.Errorf("Bad: no resource group found in state for availability set: %s", name) } client := testAccProvider.Meta().(*ArmClient).compute.AvailabilitySetsClient ctx := testAccProvider.Meta().(*ArmClient).StopContext - resp, err := client.Get(ctx, resourceGroup, availSetName) + + vmss, err := client.Get(ctx, resourceGroup, name) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Availability Set %q (resource group: %q) does not exist", availSetName, resourceGroup) - } + return fmt.Errorf("Bad: Get on vmScaleSetClient: %+v", err) + } - return fmt.Errorf("Bad: Get on availSetClient: %+v", err) + if vmss.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: VirtualMachineScaleSet %q (resource group: %q) does not exist", name, resourceGroup) } return nil @@ -334,6 +364,29 @@ resource "azurerm_availability_set" "test" { `, rInt, location, rInt) } +func testAccAzureRMAvailabilitySet_withPPG(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_proximity_placement_group" "test" { + name = "acctestPPG-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_availability_set" "test" { + name = "acctestavset-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + proximity_placement_group_id = "${azurerm_proximity_placement_group.test.id}" +} +`, rInt, location, rInt, rInt) +} + func testAccAzureRMAvailabilitySet_withDomainCounts(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/azurerm/resource_arm_proximity_placement_group.go b/azurerm/resource_arm_proximity_placement_group.go new file mode 100644 index 000000000000..a32a04d0c876 --- /dev/null +++ b/azurerm/resource_arm_proximity_placement_group.go @@ -0,0 +1,124 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-06-01/compute" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmProximityPlacementGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceArmProximityPlacementGroupCreateUpdate, + Read: resourceArmProximityPlacementGroupRead, + Update: resourceArmProximityPlacementGroupCreateUpdate, + Delete: resourceArmProximityPlacementGroupDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "tags": tags.Schema(), + }, + } +} + +func resourceArmProximityPlacementGroupCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := meta.(*ArmClient).StopContext + + log.Printf("[INFO] preparing arguments for AzureRM Proximity Placement Group creation.") + + name := d.Get("name").(string) + resourceGroup := d.Get("resource_group_name").(string) + + if requireResourcesToBeImported && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing Proximity Placement Group %q (Resource Group %q): %s", name, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_proximity_placement_group", *existing.ID) + } + } + + ppg := compute.ProximityPlacementGroup{ + Name: &name, + Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + + resp, err := client.CreateOrUpdate(ctx, resourceGroup, name, ppg) + if err != nil { + return err + } + + d.SetId(*resp.ID) + + return resourceArmProximityPlacementGroupRead(d, meta) +} + +func resourceArmProximityPlacementGroupRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["proximityPlacementGroups"] + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on Proximity Placement Group %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmProximityPlacementGroupDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["proximityPlacementGroups"] + + _, err = client.Delete(ctx, resGroup, name) + return err +} diff --git a/azurerm/resource_arm_proximity_placement_group_test.go b/azurerm/resource_arm_proximity_placement_group_test.go new file mode 100644 index 000000000000..48b60c8f1eaf --- /dev/null +++ b/azurerm/resource_arm_proximity_placement_group_test.go @@ -0,0 +1,275 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccProximityPlacementGroup_basic(t *testing.T) { + resourceName := "azurerm_proximity_placement_group.test" + ri := tf.AccRandTimeInt() + config := testAccProximityPlacementGroup_basic(ri, testLocation()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMProximityPlacementGroupDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMProximityPlacementGroupExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccProximityPlacementGroup_requiresImport(t *testing.T) { + if !requireResourcesToBeImported { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_proximity_placement_group.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMProximityPlacementGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccProximityPlacementGroup_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMProximityPlacementGroupExists(resourceName), + ), + }, + { + Config: testAccProximityPlacementGroup_requiresImport(ri, location), + ExpectError: testRequiresImportError("azurerm_proximity_placement_group"), + }, + }, + }) +} + +func TestAccProximityPlacementGroup_disappears(t *testing.T) { + resourceName := "azurerm_proximity_placement_group.test" + ri := tf.AccRandTimeInt() + config := testAccProximityPlacementGroup_basic(ri, testLocation()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMProximityPlacementGroupDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMProximityPlacementGroupExists(resourceName), + testCheckAzureRMProximityPlacementGroupDisappears(resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccProximityPlacementGroup_withTags(t *testing.T) { + resourceName := "azurerm_proximity_placement_group.test" + ri := tf.AccRandTimeInt() + location := testLocation() + preConfig := testAccProximityPlacementGroup_withTags(ri, location) + postConfig := testAccProximityPlacementGroup_withUpdatedTags(ri, location) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMProximityPlacementGroupDestroy, + Steps: []resource.TestStep{ + { + Config: preConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMProximityPlacementGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.environment", "Production"), + resource.TestCheckResourceAttr(resourceName, "tags.cost_center", "MSFT"), + ), + }, + { + Config: postConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMProximityPlacementGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.environment", "staging"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMProximityPlacementGroupExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + ppgName := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for proximity placement group: %s", ppgName) + } + + client := testAccProvider.Meta().(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.Get(ctx, resourceGroup, ppgName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Availability Set %q (resource group: %q) does not exist", ppgName, resourceGroup) + } + + return fmt.Errorf("Bad: Get on Proximity Placement Groups Client: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMProximityPlacementGroupDisappears(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + ppgName := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for proximity placement group: %s", ppgName) + } + + client := testAccProvider.Meta().(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.Delete(ctx, resourceGroup, ppgName) + if err != nil { + if !response.WasNotFound(resp.Response) { + return fmt.Errorf("Bad: Delete on Proximity Placement Groups Client: %+v", err) + } + } + + return nil + } +} + +func testCheckAzureRMProximityPlacementGroupDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_proximity_placement_group" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + client := testAccProvider.Meta().(*ArmClient).compute.ProximityPlacementGroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + return err + } + + return fmt.Errorf("Proximity placement group still exists:\n%#v", resp.ProximityPlacementGroupProperties) + } + + return nil +} + +func testAccProximityPlacementGroup_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_proximity_placement_group" "test" { + name = "acctestPPG-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, rInt, location, rInt) +} + +func testAccProximityPlacementGroup_requiresImport(rInt int, location string) string { + template := testAccProximityPlacementGroup_basic(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_proximity_placement_group" "import" { + name = "${azurerm_proximity_placement_group.test.name}" + location = "${azurerm_proximity_placement_group.test.location}" + resource_group_name = "${azurerm_proximity_placement_group.test.resource_group_name}" +} +`, template) +} + +func testAccProximityPlacementGroup_withTags(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_proximity_placement_group" "test" { + name = "acctestPPG-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + tags = { + environment = "Production" + cost_center = "MSFT" + } +} +`, rInt, location, rInt) +} + +func testAccProximityPlacementGroup_withUpdatedTags(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_proximity_placement_group" "test" { + name = "acctestPPG-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + tags = { + environment = "staging" + } +} +`, rInt, location, rInt) +} diff --git a/azurerm/resource_arm_virtual_machine.go b/azurerm/resource_arm_virtual_machine.go index 2dd473b2ab6b..bfa4eb7b91ad 100644 --- a/azurerm/resource_arm_virtual_machine.go +++ b/azurerm/resource_arm_virtual_machine.go @@ -85,6 +85,18 @@ func resourceArmVirtualMachine() *schema.Resource { ConflictsWith: []string{"zones"}, }, + "proximity_placement_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + + // We have to ignore case due to incorrect capitalisation of resource group name in + // proximity placement group ID in the response we get from the API request + // + // todo can be removed when https://github.com/Azure/azure-sdk-for-go/issues/5699 is fixed + DiffSuppressFunc: suppress.CaseDifference, + }, + "identity": { Type: schema.TypeList, Optional: true, @@ -672,6 +684,12 @@ func resourceArmVirtualMachineCreateUpdate(d *schema.ResourceData, meta interfac properties.AvailabilitySet = &availSet } + if v, ok := d.GetOk("proximity_placement_group_id"); ok { + properties.ProximityPlacementGroup = &compute.SubResource{ + ID: utils.String(v.(string)), + } + } + vm := compute.VirtualMachine{ Name: &name, Location: &location, @@ -774,10 +792,16 @@ func resourceArmVirtualMachineRead(d *schema.ResourceData, meta interface{}) err if props := resp.VirtualMachineProperties; props != nil { if availabilitySet := props.AvailabilitySet; availabilitySet != nil { - // TODO: why is this being lower-cased? + // Lowercase due to incorrect capitalisation of resource group name in + // availability set ID in response from get VM API request + // todo can be removed when https://github.com/Azure/azure-sdk-for-go/issues/5699 is fixed d.Set("availability_set_id", strings.ToLower(*availabilitySet.ID)) } + if proximityPlacementGroup := props.ProximityPlacementGroup; proximityPlacementGroup != nil { + d.Set("proximity_placement_group_id", proximityPlacementGroup.ID) + } + if profile := props.HardwareProfile; profile != nil { d.Set("vm_size", profile.VMSize) } diff --git a/azurerm/resource_arm_virtual_machine_scale_set.go b/azurerm/resource_arm_virtual_machine_scale_set.go index f3b0fe341ed6..198bdec879bf 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set.go +++ b/azurerm/resource_arm_virtual_machine_scale_set.go @@ -747,6 +747,18 @@ func resourceArmVirtualMachineScaleSet() *schema.Resource { Set: resourceArmVirtualMachineScaleSetExtensionHash, }, + "proximity_placement_group_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + + // We have to ignore case due to incorrect capitalisation of resource group name in + // proximity placement group ID in the response we get from the API request + // + // todo can be removed when https://github.com/Azure/azure-sdk-for-go/issues/5699 is fixed + DiffSuppressFunc: suppress.CaseDifference, + }, + "tags": tags.Schema(), }, @@ -857,6 +869,12 @@ func resourceArmVirtualMachineScaleSetCreateUpdate(d *schema.ResourceData, meta } } + if v, ok := d.GetOk("proximity_placement_group_id"); ok { + scaleSetProps.ProximityPlacementGroup = &compute.SubResource{ + ID: utils.String(v.(string)), + } + } + properties := compute.VirtualMachineScaleSet{ Name: &name, Location: &location, @@ -952,6 +970,10 @@ func resourceArmVirtualMachineScaleSetRead(d *schema.ResourceData, meta interfac return fmt.Errorf("[DEBUG] Error setting Virtual Machine Scale Set Rolling Upgrade Policy error: %#v", err) } } + + if proximityPlacementGroup := properties.ProximityPlacementGroup; proximityPlacementGroup != nil { + d.Set("proximity_placement_group_id", proximityPlacementGroup.ID) + } } d.Set("overprovision", properties.Overprovision) d.Set("single_placement_group", properties.SinglePlacementGroup) diff --git a/azurerm/resource_arm_virtual_machine_scale_set_test.go b/azurerm/resource_arm_virtual_machine_scale_set_test.go index cd9687ee06b5..209b07b1090e 100644 --- a/azurerm/resource_arm_virtual_machine_scale_set_test.go +++ b/azurerm/resource_arm_virtual_machine_scale_set_test.go @@ -124,6 +124,26 @@ func TestAccAzureRMVirtualMachineScaleSet_standardSSD(t *testing.T) { }) } +func TestAccAzureRMVirtualMachineScaleSet_withPPG(t *testing.T) { + resourceName := "azurerm_virtual_machine_scale_set.test" + ri := tf.AccRandTimeInt() + config := testAccAzureRMVirtualMachineScaleSet_withPPG(ri, testLocation()) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineScaleSetExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "proximity_placement_group_id"), + ), + }, + }, + }) +} + func TestAccAzureRMVirtualMachineScaleSet_basicPublicIP(t *testing.T) { resourceName := "azurerm_virtual_machine_scale_set.test" ri := tf.AccRandTimeInt() @@ -1861,6 +1881,101 @@ resource "azurerm_virtual_machine_scale_set" "test" { `, rInt, location) } +func testAccAzureRMVirtualMachineScaleSet_withPPG(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%[1]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 = "acctsub-%[1]d" + 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_storage_account" "test" { + name = "accsa%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags = { + environment = "staging" + } +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "private" +} + +resource "azurerm_proximity_placement_group" "test" { + name = "accPPG-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_virtual_machine_scale_set" "test" { + name = "acctvmss-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + upgrade_policy_mode = "Manual" + single_placement_group = false + + sku { + name = "Standard_D1_v2" + tier = "Standard" + capacity = 2 + } + + os_profile { + computer_name_prefix = "testvm-%[1]d" + admin_username = "myadmin" + admin_password = "Passwword1234" + } + + network_profile { + name = "TestNetworkProfile-%[1]d" + primary = true + + ip_configuration { + name = "TestIPConfiguration" + primary = true + subnet_id = "${azurerm_subnet.test.id}" + } + } + + storage_profile_os_disk { + name = "" + caching = "ReadWrite" + create_option = "FromImage" + managed_disk_type = "StandardSSD_LRS" + } + + storage_profile_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + proximity_placement_group_id = "${azurerm_proximity_placement_group.test.id}" +} +`, rInt, location) +} + func testAccAzureRMVirtualMachineScaleSet_basicPublicIP(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/azurerm/resource_arm_virtual_machine_test.go b/azurerm/resource_arm_virtual_machine_test.go index 4e2528871724..6f967b816bb3 100644 --- a/azurerm/resource_arm_virtual_machine_test.go +++ b/azurerm/resource_arm_virtual_machine_test.go @@ -15,8 +15,8 @@ import ( ) func TestAccAzureRMVirtualMachine_winTimeZone(t *testing.T) { - resourceName := "azurerm_virtual_machine.test" var vm compute.VirtualMachine + resourceName := "azurerm_virtual_machine.test" ri := tf.AccRandTimeInt() config := testAccAzureRMVirtualMachine_winTimeZone(ri, testLocation()) resource.ParallelTest(t, resource.TestCase{ @@ -27,7 +27,7 @@ func TestAccAzureRMVirtualMachine_winTimeZone(t *testing.T) { { Config: config, Check: resource.ComposeTestCheckFunc( - testCheckAzureRMVirtualMachineExists("azurerm_virtual_machine.test", &vm), + testCheckAzureRMVirtualMachineExists(resourceName, &vm), resource.TestCheckResourceAttr(resourceName, "os_profile_windows_config.59207889.timezone", "Pacific Standard Time"), ), }, @@ -43,7 +43,7 @@ func TestAccAzureRMVirtualMachine_SystemAssignedIdentity(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + CheckDestroy: testCheckAzureRMVirtualMachineDestroy, Steps: []resource.TestStep{ { Config: config, @@ -67,7 +67,7 @@ func TestAccAzureRMVirtualMachine_UserAssignedIdentity(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + CheckDestroy: testCheckAzureRMVirtualMachineDestroy, Steps: []resource.TestStep{ { Config: config, @@ -91,7 +91,7 @@ func TestAccAzureRMVirtualMachine_multipleAssignedIdentity(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testCheckAzureRMVirtualMachineScaleSetDestroy, + CheckDestroy: testCheckAzureRMVirtualMachineDestroy, Steps: []resource.TestStep{ { Config: config, @@ -106,6 +106,28 @@ func TestAccAzureRMVirtualMachine_multipleAssignedIdentity(t *testing.T) { }) } +func TestAccAzureRMVirtualMachine_withPPG(t *testing.T) { + var vm compute.VirtualMachine + resourceName := "azurerm_virtual_machine.test" + ri := tf.AccRandTimeInt() + rs := acctest.RandString(14) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMVirtualMachineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMVirtualMachinePPG(ri, testLocation(), rs), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMVirtualMachineExists(resourceName, &vm), + resource.TestCheckResourceAttrSet(resourceName, "proximity_placement_group_id"), + ), + }, + }, + }) +} + func testCheckAzureRMVirtualMachineExists(resourceName string, vm *compute.VirtualMachine) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API @@ -550,3 +572,104 @@ resource "azurerm_virtual_machine" "test" { } `, rInt, location, rInt, rInt, rInt, rInt, rString, rInt, rInt) } + +func testAccAzureRMVirtualMachinePPG(rInt int, location string, rString string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%[1]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 = "acctsub-%[1]d" + 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 = "acctni-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + ip_configuration { + name = "testconfiguration1" + subnet_id = "${azurerm_subnet.test.id}" + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_storage_account" "test" { + name = "accsa%[1]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags = { + environment = "staging" + } +} + +resource "azurerm_storage_container" "test" { + name = "vhds" + resource_group_name = "${azurerm_resource_group.test.name}" + storage_account_name = "${azurerm_storage_account.test.name}" + container_access_type = "private" +} + +resource "azurerm_proximity_placement_group" "test" { + name = "accPPG-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_virtual_machine" "test" { + name = "acctvm-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + network_interface_ids = ["${azurerm_network_interface.test.id}"] + vm_size = "Standard_D1_v2" + + storage_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + storage_os_disk { + name = "myosdisk1" + vhd_uri = "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd" + caching = "ReadWrite" + create_option = "FromImage" + disk_size_gb = "45" + } + + os_profile { + computer_name = "hn%[1]d" + admin_username = "testadmin" + admin_password = "Password1234!" + } + + os_profile_linux_config { + disable_password_authentication = false + } + + proximity_placement_group_id = "${azurerm_proximity_placement_group.test.id}" + + tags = { + environment = "Production" + cost-center = "Ops" + } +} +`, rInt, location) +} diff --git a/website/docs/d/proximity_placement_group.html.markdown b/website/docs/d/proximity_placement_group.html.markdown new file mode 100644 index 000000000000..372a0d07f115 --- /dev/null +++ b/website/docs/d/proximity_placement_group.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_proximity_placement_group" +sidebar_current: "docs-azurerm-datasource-proximity-placement-group" +description: |- + Gets information about an existing Proximity Placement Group. +--- + +# Data Source: azurerm_proximity_placement_group + +Use this data source to access information about an existing Proximity Placement Group. + +## Example Usage + +```hcl +data "azurerm_proximity_placement_group" "example" { + name = "tf-appsecuritygroup" + resource_group_name = "my-resource-group" +} + +output "proximity_placement_group_id" { + value = "${data.azurerm_proximity_placement_group.example.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - The name of the Proximity Placement Group. + +* `resource_group_name` - The name of the resource group in which the Proximity Placement Group exists. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Proximity Placement Group. diff --git a/website/docs/r/availability_set.html.markdown b/website/docs/r/availability_set.html.markdown index 8aad2e8e1c3e..4dffa5a7ad0d 100644 --- a/website/docs/r/availability_set.html.markdown +++ b/website/docs/r/availability_set.html.markdown @@ -48,6 +48,8 @@ The following arguments are supported: ~> **NOTE:** The number of Fault Domains varies depending on which Azure Region you're using - [a list can be found here](https://github.com/MicrosoftDocs/azure-docs/blob/master/includes/managed-disks-common-fault-domain-region-list.md). +* `proximity_placement_group_id` - (Optional) The ID of the Proximity Placement Group to which this Virtual Machine should be assigned. Changing this forces a new resource to be created + * `managed` - (Optional) Specifies whether the availability set is managed or not. Possible values are `true` (to specify aligned) or `false` (to specify classic). Default is `false`. * `tags` - (Optional) A mapping of tags to assign to the resource. diff --git a/website/docs/r/proximity_placement_group.html.markdown b/website/docs/r/proximity_placement_group.html.markdown new file mode 100644 index 000000000000..53b0a15ecb7d --- /dev/null +++ b/website/docs/r/proximity_placement_group.html.markdown @@ -0,0 +1,65 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_proximity_placement_group" +sidebar_current: "docs-azurerm-resource-compute-proximity-placement-group" +description: |- + Manages a proximity placement group for virtual machines, virtual machine scale sets and availability sets. + +--- + +# azurerm_proximity_placement_group + +Manages a proximity placement group for virtual machines, virtual machine scale sets and availability sets. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "resourceGroup1" + location = "West US" +} + +resource "azurerm_proximity_placement_group" "example" { + name = "exampleProximityPlacementGroup" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + + tags = { + environment = "Production" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the availability set. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which to create the availability set. Changing this forces a new resource to be created. + +* `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. + +* `tags` - (Optional) A mapping of tags to assign to the resource. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The Proximity Placement Group ID. + +* `name` - The name of the Proximity Placement Group. + +* `location` - The location of the Proximity Placement Group. + +* `resource_group_name` - The name of the resource group in which the Proximity Placement Group exists. + +* `tags` - The tags attached to the Proximity Placement Group. + +## Import + +Proximity Placement Groups can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_proximity_placement_group.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/example-rg/providers/Microsoft.Compute/proximityPlacementGroups/example-ppg +``` diff --git a/website/docs/r/virtual_machine.html.markdown b/website/docs/r/virtual_machine.html.markdown index 61ef25512a2b..79087877e668 100644 --- a/website/docs/r/virtual_machine.html.markdown +++ b/website/docs/r/virtual_machine.html.markdown @@ -134,6 +134,8 @@ The following arguments are supported: * `primary_network_interface_id` - (Optional) The ID of the Network Interface (which must be attached to the Virtual Machine) which should be the Primary Network Interface for this Virtual Machine. +* `proximity_placement_group_id` - (Optional) The ID of the Proximity Placement Group to which this Virtual Machine should be assigned. Changing this forces a new resource to be created + * `storage_data_disk` - (Optional) One or more `storage_data_disk` blocks. ~> **Please Note:** Data Disks can also be attached either using this block or [the `azurerm_virtual_machine_data_disk_attachment` resource](virtual_machine_data_disk_attachment.html) - but not both. diff --git a/website/docs/r/virtual_machine_scale_set.html.markdown b/website/docs/r/virtual_machine_scale_set.html.markdown index 5c6001cb2978..1e871c78681c 100644 --- a/website/docs/r/virtual_machine_scale_set.html.markdown +++ b/website/docs/r/virtual_machine_scale_set.html.markdown @@ -275,6 +275,8 @@ The following arguments are supported: * `os_profile_linux_config` - (Required, when a linux machine) A Linux config block as documented below. +* `proximity_placement_group_id` - (Optional) The ID of the Proximity Placement Group to which this Virtual Machine should be assigned. Changing this forces a new resource to be created + * `sku` - (Required) A sku block as documented below. * `storage_profile_os_disk` - (Required) A storage profile os disk block as documented below