From 6e25ec48d81703343d55a977d57c715748a17820 Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 14 Jan 2020 10:57:04 +0800 Subject: [PATCH 01/10] new resource: dedicated host (with delete bug) --- .../services/compute/client/client.go | 5 + .../compute/data_source_dedicated_host.go | 72 +++++ .../internal/services/compute/registration.go | 2 + .../compute/resource_arm_dedicated_host.go | 252 ++++++++++++++++++ .../resource_arm_dedicated_host_group.go | 3 +- .../tests/data_source_dedicated_host_test.go | 45 ++++ .../tests/resource_arm_dedicated_host_test.go | 235 ++++++++++++++++ .../internal/services/compute/validation.go | 10 + website/azurerm.erb | 8 + website/docs/d/dedicated_host.html.markdown | 47 ++++ website/docs/r/dedicated_host.html.markdown | 74 +++++ 11 files changed, 751 insertions(+), 2 deletions(-) create mode 100644 azurerm/internal/services/compute/data_source_dedicated_host.go create mode 100644 azurerm/internal/services/compute/resource_arm_dedicated_host.go create mode 100644 azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go create mode 100644 azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go create mode 100644 website/docs/d/dedicated_host.html.markdown create mode 100644 website/docs/r/dedicated_host.html.markdown diff --git a/azurerm/internal/services/compute/client/client.go b/azurerm/internal/services/compute/client/client.go index bc1cecefcb0e..80130b9d6e09 100644 --- a/azurerm/internal/services/compute/client/client.go +++ b/azurerm/internal/services/compute/client/client.go @@ -8,6 +8,7 @@ import ( type Client struct { AvailabilitySetsClient *compute.AvailabilitySetsClient + DedicatedHostsClient *compute.DedicatedHostsClient DedicatedHostGroupsClient *compute.DedicatedHostGroupsClient DisksClient *compute.DisksClient DiskEncryptionSetsClient *compute.DiskEncryptionSetsClient @@ -32,6 +33,9 @@ func NewClient(o *common.ClientOptions) *Client { availabilitySetsClient := compute.NewAvailabilitySetsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&availabilitySetsClient.Client, o.ResourceManagerAuthorizer) + dedicatedHostsClient := compute.NewDedicatedHostsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&dedicatedHostsClient.Client, o.ResourceManagerAuthorizer) + dedicatedHostGroupsClient := compute.NewDedicatedHostGroupsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&dedicatedHostGroupsClient.Client, o.ResourceManagerAuthorizer) @@ -88,6 +92,7 @@ func NewClient(o *common.ClientOptions) *Client { return &Client{ AvailabilitySetsClient: &availabilitySetsClient, + DedicatedHostsClient: &dedicatedHostsClient, DedicatedHostGroupsClient: &dedicatedHostGroupsClient, DisksClient: &disksClient, DiskEncryptionSetsClient: &diskEncryptionSetsClient, diff --git a/azurerm/internal/services/compute/data_source_dedicated_host.go b/azurerm/internal/services/compute/data_source_dedicated_host.go new file mode 100644 index 000000000000..acd1ed219958 --- /dev/null +++ b/azurerm/internal/services/compute/data_source_dedicated_host.go @@ -0,0 +1,72 @@ +package compute + +import ( + "fmt" + "time" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "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/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmDedicatedHost() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmDedicatedHostRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateDedicatedHostName(), + }, + + "location": azure.SchemaLocationForDataSource(), + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "host_group_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateDedicatedHostGroupName(), + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DedicatedHostsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroupName := d.Get("resource_group_name").(string) + hostGroupName := d.Get("host_group_name").(string) + + resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: Dedicated Host %q (Host Group Name %q / Resource Group %q) was not found", name, hostGroupName, resourceGroupName) + } + return fmt.Errorf("Error reading Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + + d.SetId(*resp.ID) + d.Set("name", name) + d.Set("resource_group_name", resourceGroupName) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + d.Set("host_group_name", hostGroupName) + + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/internal/services/compute/registration.go b/azurerm/internal/services/compute/registration.go index 263de4f7f94a..dd275ba5c2bc 100644 --- a/azurerm/internal/services/compute/registration.go +++ b/azurerm/internal/services/compute/registration.go @@ -16,6 +16,7 @@ func (r Registration) Name() string { func (r Registration) SupportedDataSources() map[string]*schema.Resource { return map[string]*schema.Resource{ "azurerm_availability_set": dataSourceArmAvailabilitySet(), + "azurerm_dedicated_host": dataSourceArmDedicatedHost(), "azurerm_dedicated_host_group": dataSourceArmDedicatedHostGroup(), "azurerm_disk_encryption_set": dataSourceArmDiskEncryptionSet(), "azurerm_managed_disk": dataSourceArmManagedDisk(), @@ -34,6 +35,7 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { func (r Registration) SupportedResources() map[string]*schema.Resource { resources := map[string]*schema.Resource{ "azurerm_availability_set": resourceArmAvailabilitySet(), + "azurerm_dedicated_host": resourceArmDedicatedHost(), "azurerm_dedicated_host_group": resourceArmDedicatedHostGroup(), "azurerm_disk_encryption_set": resourceArmDiskEncryptionSet(), "azurerm_image": resourceArmImage(), diff --git a/azurerm/internal/services/compute/resource_arm_dedicated_host.go b/azurerm/internal/services/compute/resource_arm_dedicated_host.go new file mode 100644 index 000000000000..b370b0d6c427 --- /dev/null +++ b/azurerm/internal/services/compute/resource_arm_dedicated_host.go @@ -0,0 +1,252 @@ +package compute + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/go-azure-helpers/response" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmDedicatedHost() *schema.Resource { + return &schema.Resource{ + Create: resourceArmDedicatedHostCreate, + Read: resourceArmDedicatedHostRead, + Update: resourceArmDedicatedHostUpdate, + Delete: resourceArmDedicatedHostDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateDedicatedHostName(), + }, + + "location": azure.SchemaLocation(), + + "resource_group_name": azure.SchemaResourceGroupName(), + + "host_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateDedicatedHostGroupName(), + }, + + // In order to follow convention for both protal and azure cli, `sku` here means + // sku name only. + "sku": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "DSv3-Type1", + "ESv3-Type1", + "FSv2-Type2", + }, false), + }, + + "platform_fault_domain": { + Type: schema.TypeInt, + ForceNew: true, + Required: true, + }, + + "auto_replace_on_failure": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "license_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(compute.DedicatedHostLicenseTypesNone), + string(compute.DedicatedHostLicenseTypesWindowsServerHybrid), + string(compute.DedicatedHostLicenseTypesWindowsServerPerpetual), + }, false), + Default: string(compute.DedicatedHostLicenseTypesNone), + }, + + "tags": tags.Schema(), + }, + } +} + +func resourceArmDedicatedHostCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DedicatedHostsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroupName := d.Get("resource_group_name").(string) + hostGroupName := d.Get("host_group_name").(string) + + if features.ShouldResourcesBeImported() && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for present of existing Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + } + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_dedicated_host", *existing.ID) + } + } + + location := azure.NormalizeLocation(d.Get("location").(string)) + t := d.Get("tags").(map[string]interface{}) + parameters := compute.DedicatedHost{ + Location: utils.String(location), + DedicatedHostProperties: &compute.DedicatedHostProperties{ + AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), + LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), + }, + Sku: &compute.Sku{ + Name: utils.String(d.Get("sku").(string)), + }, + Tags: tags.Expand(t), + } + if platformFaultDomain, ok := d.GetOk("platform_fault_domain"); ok { + parameters.DedicatedHostProperties.PlatformFaultDomain = utils.Int32(int32(platformFaultDomain.(int))) + } + + future, err := client.CreateOrUpdate(ctx, resourceGroupName, hostGroupName, name, parameters) + if err != nil { + return fmt.Errorf("Error creating Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + + resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + if err != nil { + return fmt.Errorf("Error retrieving Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + if resp.ID == nil { + return fmt.Errorf("Cannot read Dedicated Host %q (Host Group Name %q / Resource Group %q) ID", name, hostGroupName, resourceGroupName) + } + d.SetId(*resp.ID) + + return resourceArmDedicatedHostRead(d, meta) +} + +func resourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DedicatedHostsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroupName := id.ResourceGroup + hostGroupName := id.Path["hostGroups"] + name := id.Path["hosts"] + + resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Dedicated Host %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("Error reading Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resourceGroupName) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + d.Set("host_group_name", hostGroupName) + d.Set("sku", resp.Sku.Name) + if props := resp.DedicatedHostProperties; props != nil { + d.Set("platform_fault_domain", props.PlatformFaultDomain) + d.Set("auto_replace_on_failure", props.AutoReplaceOnFailure) + d.Set("license_type", props.LicenseType) + } + + return tags.FlattenAndSet(d, resp.Tags) +} + +func resourceArmDedicatedHostUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DedicatedHostsClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + resourceGroupName := d.Get("resource_group_name").(string) + hostGroupName := d.Get("host_group_name").(string) + t := d.Get("tags").(map[string]interface{}) + + parameters := compute.DedicatedHostUpdate{ + DedicatedHostProperties: &compute.DedicatedHostProperties{ + AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), + LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), + }, + Tags: tags.Expand(t), + } + + future, err := client.Update(ctx, resourceGroupName, hostGroupName, name, parameters) + if err != nil { + return fmt.Errorf("Error updating Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for update of Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + + return resourceArmDedicatedHostRead(d, meta) +} + +func resourceArmDedicatedHostDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Compute.DedicatedHostsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroupName := id.ResourceGroup + hostGroupName := id.Path["hostGroups"] + name := id.Path["hosts"] + + future, err := client.Delete(ctx, resourceGroupName, hostGroupName, name) + if err != nil { + return fmt.Errorf("Error deleting Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("Error waiting for deleting Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + } + } + + return nil +} diff --git a/azurerm/internal/services/compute/resource_arm_dedicated_host_group.go b/azurerm/internal/services/compute/resource_arm_dedicated_host_group.go index 161bf07a0bb4..9c12d070cfd3 100644 --- a/azurerm/internal/services/compute/resource_arm_dedicated_host_group.go +++ b/azurerm/internal/services/compute/resource_arm_dedicated_host_group.go @@ -3,7 +3,6 @@ package compute import ( "fmt" "log" - "regexp" "time" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -43,7 +42,7 @@ func resourceArmDedicatedHostGroup() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[^_\W][\w-.]{0,78}[\w]$`), ""), + ValidateFunc: validateDedicatedHostGroupName(), }, "location": azure.SchemaLocation(), diff --git a/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go b/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go new file mode 100644 index 000000000000..0635ea8fcb9a --- /dev/null +++ b/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go @@ -0,0 +1,45 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccDataSourceAzureRMDedicatedHost_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceDedicatedHost_basic(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), + resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), + resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), + ), + }, + }, + }) +} + +func testAccDataSourceDedicatedHost_basic(data acceptance.TestData) string { + config := testAccAzureRMDedicatedHost_basic(data) + return fmt.Sprintf(` +%s + +data "azurerm_dedicated_host" "test" { + name = azurerm_dedicated_host.test.name + resource_group_name = azurerm_dedicated_host.test.resource_group_name + host_group_name = azurerm_dedicated_host.test.host_group_name +} +`, config) +} diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go new file mode 100644 index 000000000000..cd0cca0b946b --- /dev/null +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -0,0 +1,235 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMDedicatedHost_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMDedicatedHost_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), + resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), + resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMDedicatedHost_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMDedicatedHost_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), + resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), + resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", ""), + resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), + resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesWindowsServerHybrid)), + resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMDedicatedHost_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMDedicatedHost_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), + resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), + ), + }, + { + Config: testAccAzureRMDedicatedHost_complete(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesWindowsServerHybrid)), + resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), + ), + }, + }, + }) +} + +func TestAccAzureRMDedicatedHost_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + data := acceptance.BuildTestData(t, "azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMDedicatedHost_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMDedicatedHost_requiresImport), + }, + }) +} + +func testCheckAzureRMDedicatedHostExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Dedicated Host not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroupName := rs.Primary.Attributes["resource_group_name"] + hostGroupName := rs.Primary.Attributes["host_group_name"] + + client := acceptance.AzureProvider.Meta().(*clients.Client).Compute.DedicatedHostsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + if resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, ""); err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Dedicated Host %q (Host Group Name %q / Resource Group %q) does not exist", name, hostGroupName, resourceGroupName) + } + return fmt.Errorf("Bad: Get on Compute.DedicatedHostsClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMDedicatedHostDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Compute.DedicatedHostsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_dedicated_host" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroupName := rs.Primary.Attributes["resource_group_name"] + hostGroupName := rs.Primary.Attributes["host_group_name"] + + if resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, ""); err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Get on Compute.DedicatedHostsClient: %+v", err) + } + } + + return nil + } + + return nil +} + +func testAccAzureRMDedicatedHost_basic(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-compute-%d" + location = "%s" +} + +resource "azurerm_dedicated_host_group" "test" { + name = "acctestDHG-compute-%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + platform_fault_domain_count = 2 +} + + +resource "azurerm_dedicated_host" "test" { + name = "acctestDH-compute-%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + host_group_name = azurerm_dedicated_host_group.test.name + sku = "DSv3-Type1" + platform_fault_domain = 1 +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) +} + +func testAccAzureRMDedicatedHost_complete(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-compute-%d" + location = "%s" +} + +resource "azurerm_dedicated_host_group" "test" { + name = "acctestDHG-compute-%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + platform_fault_domain_count = 2 +} + + +resource "azurerm_dedicated_host" "test" { + name = "acctestDH-compute-%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + host_group_name = azurerm_dedicated_host_group.test.name + sku = "DSv3-Type1" + platform_fault_domain = 1 + license_type = Windows_Server_Hybrid + auto_replace_on_failure = false +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) +} + +func testAccAzureRMDedicatedHost_requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s +resource "azurerm_dedicated_host" "import" { + name = azurerm_dedicated_host.test.name + resource_group_name = azurerm_dedicated_host.test.resource_group_name + location = azurerm_dedicated_host.test.location + host_group_name = azurerm_dedicated_host.test.host_group_name + sku = azurerm_dedicated_host.test.sku + platform_fault_domain = azurerm_dedicated_host.test.platform_fault_domain +} +`, testAccAzureRMDedicatedHost_basic(data)) +} diff --git a/azurerm/internal/services/compute/validation.go b/azurerm/internal/services/compute/validation.go index 287c285c3395..2f2e56e9b4db 100644 --- a/azurerm/internal/services/compute/validation.go +++ b/azurerm/internal/services/compute/validation.go @@ -4,6 +4,8 @@ import ( "fmt" "regexp" "strings" + + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func ValidateLinuxName(i interface{}, k string) (warnings []string, errors []error) { @@ -103,3 +105,11 @@ func validateDiskSizeGB(v interface{}, _ string) (warnings []string, errors []er } return warnings, errors } + +func validateDedicatedHostGroupName() func(i interface{}, k string) (warnings []string, errors []error) { + return validation.StringMatch(regexp.MustCompile(`^[^_\W][\w-.]{0,78}[\w]$`), "") +} + +func validateDedicatedHostName() func(i interface{}, k string) (warnings []string, errors []error) { + return validateDedicatedHostGroupName() +} diff --git a/website/azurerm.erb b/website/azurerm.erb index b485474d72e3..45745f5158f3 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -170,6 +170,10 @@ azurerm_data_lake_store +
  • + azurerm_dedicated_host +
  • +
  • azurerm_dedicated_host_group
  • @@ -889,6 +893,10 @@ azurerm_availability_set +
  • + azurerm_dedicated_host +
  • +
  • azurerm_dedicated_host_group
  • diff --git a/website/docs/d/dedicated_host.html.markdown b/website/docs/d/dedicated_host.html.markdown new file mode 100644 index 000000000000..044a4509c976 --- /dev/null +++ b/website/docs/d/dedicated_host.html.markdown @@ -0,0 +1,47 @@ +--- +subcategory: "Compute" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dedicated_host" +sidebar_current: "docs-azurerm-datasource-dedicated-host" +description: |- + Gets information about an existing Dedicated Host +--- + +# Data Source: azurerm_dedicated_host + +Use this data source to access information about an existing Dedicated Host. + +## Example Usage + +```hcl +data "azurerm_dedicated_host" "example" { + name = "example-dh" + resource_group_name = "example-rg" + host_group_name = "example-dhg" +} + +output "dedicated_host_id" { + value = "${data.azurerm_dedicated_host.example.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the Dedicated Host. + +* `resource_group_name` - (Required) Specifies the name of the resource group the Dedicated Host is located in. + +* `host_group_name` - (Required) Specifies the name of the Dedicated Host Group the Dedicated Host is located in. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of Dedicated Host. + +* `location` - The location where the Dedicated Host exists. + +* `tags` - A mapping of tags assigned to the Dedicated Host. + diff --git a/website/docs/r/dedicated_host.html.markdown b/website/docs/r/dedicated_host.html.markdown new file mode 100644 index 000000000000..07ee93868005 --- /dev/null +++ b/website/docs/r/dedicated_host.html.markdown @@ -0,0 +1,74 @@ +--- +subcategory: "Compute" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_dedicated_host" +sidebar_current: "docs-azurerm-resource-dedicated-host" +description: |- + Manage an Dedicated Host. +--- + +# azurerm_dedicated_host + +Manage an Dedicated Host. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-rg" + location = "West US" +} + +resource "azurerm_dedicated_host_group" "example" { + name = "example-dhg" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + platform_fault_domain_count = 2 +} + + +resource "azurerm_dedicated_host" "example" { + name = "example-dh" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + host_group_name = azurerm_dedicated_host_group.example.name + sku = "DSv3-Type1" + platform_fault_domain = 1 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specify the name of the Dedicated Host. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which to create the Dedicated Host. Changing this forces a new resource to be created. + +* `location` - (Required) Specify the supported Azure location where the resource exists. Changing this forces a new resource to be created. + +* `host_group_name` - (Required) Specify the name of the Dedicated Host Group in which to create the Dedicated Host. Changing this forces a new resource to be created. + +* `sku` - (Required) Specify the sku name of the Dedicated Host. Possible values are `DSv3-Type1`, `ESv3-Type1`, `FSv2-Type2`. Changing this forces a new resource to be created. + +* `platform_fault_domain` - (Required) Specify the fault domain of the Dedicated Host Group in which to create the Dedicated Host. Changing this forces a new resource to be created. + +* `auto_replace_on_failure` - (Optional) Specifies whether the Dedicated Host should be replaced automatically in case of a failure. The value is defaulted to `true` when not provided. + +* `license_type` - (Optional) Specifies the software license type that will be applied to the VMs deployed on the Dedicated Host. Possible values are: `None`, `Windows_Server_Hybrid`, `Windows_Server_Perpetual`. The value is defaulted to `None` when not provided. + +* `tags` - (Optional) A mapping of tags to assign to the resource. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Dedicated Host. + +## Import + +Dedicated Host can be imported using the `resource id`, e.g. + +```shell +$ terraform import azurerm_dedicated_host.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/host1 +``` From eb0077b196585c3f619262ce03a03c41f290a3f4 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 15 Jan 2020 17:17:43 +0800 Subject: [PATCH 02/10] fix test --- .../compute/tests/data_source_dedicated_host_test.go | 7 +------ .../compute/tests/resource_arm_dedicated_host_test.go | 8 +++----- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go b/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go index 0635ea8fcb9a..483469e28867 100644 --- a/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go @@ -6,8 +6,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" ) @@ -21,10 +19,7 @@ func TestAccDataSourceAzureRMDedicatedHost_basic(t *testing.T) { { Config: testAccDataSourceDedicatedHost_basic(data), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), - resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), - resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), + resource.TestCheckResourceAttrSet(data.ResourceName, "id"), ), }, }, diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go index cd0cca0b946b..fe95a15f81d4 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -51,9 +51,7 @@ func TestAccAzureRMDedicatedHost_complete(t *testing.T) { Config: testAccAzureRMDedicatedHost_complete(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMDedicatedHostExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), - resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), - resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", ""), + resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesWindowsServerHybrid)), resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), @@ -214,7 +212,7 @@ resource "azurerm_dedicated_host" "test" { host_group_name = azurerm_dedicated_host_group.test.name sku = "DSv3-Type1" platform_fault_domain = 1 - license_type = Windows_Server_Hybrid + license_type = "Windows_Server_Hybrid" auto_replace_on_failure = false } `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) From 8b4d13207a089f0c5371a3a1e89cc270a25359b4 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 15 Jan 2020 17:17:56 +0800 Subject: [PATCH 03/10] workaround for delete bug --- .../compute/resource_arm_dedicated_host.go | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/azurerm/internal/services/compute/resource_arm_dedicated_host.go b/azurerm/internal/services/compute/resource_arm_dedicated_host.go index b370b0d6c427..4ba02b30f346 100644 --- a/azurerm/internal/services/compute/resource_arm_dedicated_host.go +++ b/azurerm/internal/services/compute/resource_arm_dedicated_host.go @@ -1,10 +1,13 @@ package compute import ( + "context" "fmt" "log" "time" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/go-azure-helpers/response" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -248,5 +251,42 @@ func resourceArmDedicatedHostDelete(d *schema.ResourceData, meta interface{}) er } } + // API has bug, which appears to be eventually consistent. Tracked by this issue: https://github.com/Azure/azure-rest-api-specs/issues/8137 + log.Printf("[DEBUG] Waiting for Dedicated Host %q (Host Group Name %q / Resource Group %q) to disappear", name, hostGroupName, resourceGroupName) + stateConf := &resource.StateChangeConf{ + Pending: []string{"Exists"}, + Target: []string{"NotFound"}, + Refresh: dedicatedHostDeletedRefreshFunc(ctx, client, id), + MinTimeout: 5 * time.Second, + ContinuousTargetOccurence: 5, + } + + if features.SupportsCustomTimeouts() { + stateConf.Timeout = d.Timeout(schema.TimeoutDelete) + } else { + stateConf.Timeout = 10 * time.Minute + } + + if _, err = stateConf.WaitForState(); err != nil { + return fmt.Errorf("Error waiting for Dedicated Host %q (Host Group Name %q / Resource Group %q) to become available: %+v", name, hostGroupName, resourceGroupName, err) + } + return nil } + +func dedicatedHostDeletedRefreshFunc(ctx context.Context, client *compute.DedicatedHostsClient, id *azure.ResourceID) resource.StateRefreshFunc { + resourceGroupName := id.ResourceGroup + hostGroupName := id.Path["hostGroups"] + name := id.Path["hosts"] + return func() (interface{}, string, error) { + res, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + if err != nil { + if utils.ResponseWasNotFound(res.Response) { + return "NotFound", "NotFound", nil + } + return nil, "", fmt.Errorf("Error issuing read request in dedicatedHostDeletedRefreshFunc: %+v", err) + } + + return res, "Exists", nil + } +} From 8d297b85b21c60d8c8204f89162175bb4823c6b2 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 16 Jan 2020 10:01:34 +0800 Subject: [PATCH 04/10] format terraform blocks --- .../tests/resource_arm_dedicated_host_test.go | 58 +++++++++---------- website/docs/r/dedicated_host.html.markdown | 20 +++---- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go index fe95a15f81d4..5326c7f2b597 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -167,25 +167,25 @@ func testCheckAzureRMDedicatedHostDestroy(s *terraform.State) error { func testAccAzureRMDedicatedHost_basic(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { - name = "acctestRG-compute-%d" - location = "%s" + name = "acctestRG-compute-%d" + location = "%s" } resource "azurerm_dedicated_host_group" "test" { - name = "acctestDHG-compute-%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - platform_fault_domain_count = 2 + name = "acctestDHG-compute-%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + platform_fault_domain_count = 2 } resource "azurerm_dedicated_host" "test" { - name = "acctestDH-compute-%s" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - host_group_name = azurerm_dedicated_host_group.test.name - sku = "DSv3-Type1" - platform_fault_domain = 1 + name = "acctestDH-compute-%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + host_group_name = azurerm_dedicated_host_group.test.name + sku = "DSv3-Type1" + platform_fault_domain = 1 } `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) } @@ -198,22 +198,22 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_dedicated_host_group" "test" { - name = "acctestDHG-compute-%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - platform_fault_domain_count = 2 + name = "acctestDHG-compute-%s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + platform_fault_domain_count = 2 } resource "azurerm_dedicated_host" "test" { - name = "acctestDH-compute-%s" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - host_group_name = azurerm_dedicated_host_group.test.name - sku = "DSv3-Type1" - platform_fault_domain = 1 - license_type = "Windows_Server_Hybrid" - auto_replace_on_failure = false + name = "acctestDH-compute-%s" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + host_group_name = azurerm_dedicated_host_group.test.name + sku = "DSv3-Type1" + platform_fault_domain = 1 + license_type = "Windows_Server_Hybrid" + auto_replace_on_failure = false } `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) } @@ -222,11 +222,11 @@ func testAccAzureRMDedicatedHost_requiresImport(data acceptance.TestData) string return fmt.Sprintf(` %s resource "azurerm_dedicated_host" "import" { - name = azurerm_dedicated_host.test.name - resource_group_name = azurerm_dedicated_host.test.resource_group_name - location = azurerm_dedicated_host.test.location - host_group_name = azurerm_dedicated_host.test.host_group_name - sku = azurerm_dedicated_host.test.sku + name = azurerm_dedicated_host.test.name + resource_group_name = azurerm_dedicated_host.test.resource_group_name + location = azurerm_dedicated_host.test.location + host_group_name = azurerm_dedicated_host.test.host_group_name + sku = azurerm_dedicated_host.test.sku platform_fault_domain = azurerm_dedicated_host.test.platform_fault_domain } `, testAccAzureRMDedicatedHost_basic(data)) diff --git a/website/docs/r/dedicated_host.html.markdown b/website/docs/r/dedicated_host.html.markdown index 07ee93868005..3e2e94cc0eea 100644 --- a/website/docs/r/dedicated_host.html.markdown +++ b/website/docs/r/dedicated_host.html.markdown @@ -20,20 +20,20 @@ resource "azurerm_resource_group" "example" { } resource "azurerm_dedicated_host_group" "example" { - name = "example-dhg" - resource_group_name = azurerm_resource_group.example.name - location = azurerm_resource_group.example.location - platform_fault_domain_count = 2 + name = "example-dhg" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + platform_fault_domain_count = 2 } resource "azurerm_dedicated_host" "example" { - name = "example-dh" - location = azurerm_resource_group.example.location - resource_group_name = azurerm_resource_group.example.name - host_group_name = azurerm_dedicated_host_group.example.name - sku = "DSv3-Type1" - platform_fault_domain = 1 + name = "example-dh" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + host_group_name = azurerm_dedicated_host_group.example.name + sku = "DSv3-Type1" + platform_fault_domain = 1 } ``` From dbbb213b0d2185ede57eb630545f910396fde9c4 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 16 Jan 2020 15:05:04 +0800 Subject: [PATCH 05/10] remove `sidebar_current` --- website/docs/d/dedicated_host.html.markdown | 1 - website/docs/r/dedicated_host.html.markdown | 1 - 2 files changed, 2 deletions(-) diff --git a/website/docs/d/dedicated_host.html.markdown b/website/docs/d/dedicated_host.html.markdown index 044a4509c976..43e6e46953ad 100644 --- a/website/docs/d/dedicated_host.html.markdown +++ b/website/docs/d/dedicated_host.html.markdown @@ -2,7 +2,6 @@ subcategory: "Compute" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_dedicated_host" -sidebar_current: "docs-azurerm-datasource-dedicated-host" description: |- Gets information about an existing Dedicated Host --- diff --git a/website/docs/r/dedicated_host.html.markdown b/website/docs/r/dedicated_host.html.markdown index 3e2e94cc0eea..38178cf4b07e 100644 --- a/website/docs/r/dedicated_host.html.markdown +++ b/website/docs/r/dedicated_host.html.markdown @@ -2,7 +2,6 @@ subcategory: "Compute" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_dedicated_host" -sidebar_current: "docs-azurerm-resource-dedicated-host" description: |- Manage an Dedicated Host. --- From da92921cf956a9897fcfb7c7627b1cf0c45b6cd5 Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 21 Jan 2020 09:55:55 +0800 Subject: [PATCH 06/10] Modify per review comment Includes: - custom parser function - rename `sku` to `sku_name` - multi-line code to oneline - increase each timeout of state polling for eventual consistency from 5sec to 10 sec, to alleviate --- .../services/compute/parse/dedicated_host.go | 38 ++++++++ .../compute/parse/dedicated_host_test.go | 90 +++++++++++++++++++ .../compute/resource_arm_dedicated_host.go | 65 ++++++-------- .../tests/resource_arm_dedicated_host_test.go | 33 ++++--- website/docs/r/dedicated_host.html.markdown | 4 +- 5 files changed, 177 insertions(+), 53 deletions(-) create mode 100644 azurerm/internal/services/compute/parse/dedicated_host.go create mode 100644 azurerm/internal/services/compute/parse/dedicated_host_test.go diff --git a/azurerm/internal/services/compute/parse/dedicated_host.go b/azurerm/internal/services/compute/parse/dedicated_host.go new file mode 100644 index 000000000000..23acd2ff569d --- /dev/null +++ b/azurerm/internal/services/compute/parse/dedicated_host.go @@ -0,0 +1,38 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type DedicatedHostId struct { + ResourceGroup string + HostGroup string + Name string +} + +func DedicatedHostID(input string) (*DedicatedHostId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Dedicated Host ID %q: %+v", input, err) + } + + server := DedicatedHostId{ + ResourceGroup: id.ResourceGroup, + } + + if server.HostGroup, err = id.PopSegment("hostGroups"); err != nil { + return nil, err + } + + if server.Name, err = id.PopSegment("hosts"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &server, nil +} diff --git a/azurerm/internal/services/compute/parse/dedicated_host_test.go b/azurerm/internal/services/compute/parse/dedicated_host_test.go new file mode 100644 index 000000000000..39fa5f9c6744 --- /dev/null +++ b/azurerm/internal/services/compute/parse/dedicated_host_test.go @@ -0,0 +1,90 @@ +package parse + +import ( + "testing" +) + +func TestDedicatedHostID(t *testing.T) { + testData := []struct { + Name string + Input string + ExpectedOK bool + ExpectedValue *DedicatedHostId + }{ + { + Name: "Empty", + Input: "", + ExpectedOK: false, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + ExpectedOK: false, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + ExpectedOK: false, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + ExpectedOK: false, + }, + { + Name: "Missing Host Group Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", + ExpectedOK: false, + }, + { + Name: "Host Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/", + ExpectedOK: false, + }, + { + Name: "Missing Host Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/", + ExpectedOK: false, + }, + { + Name: "Host ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/host1", + ExpectedOK: true, + ExpectedValue: &DedicatedHostId{ + ResourceGroup: "resGroup1", + HostGroup: "group1", + Name: "host1", + }, + }, + { + Name: "Wrong Casing", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/Hosts/host1", + ExpectedOK: false, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := DedicatedHostID(v.Input) + if err != nil { + if v.ExpectedOK == false { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.ExpectedValue.Name { + t.Fatalf("Expected %q but got %q for Name", v.ExpectedValue.Name, actual.Name) + } + + if actual.HostGroup != v.ExpectedValue.HostGroup { + t.Fatalf("Expected %q but got %q for HostGroup", v.ExpectedValue.HostGroup, actual.HostGroup) + } + + if actual.ResourceGroup != v.ExpectedValue.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.ExpectedValue.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/compute/resource_arm_dedicated_host.go b/azurerm/internal/services/compute/resource_arm_dedicated_host.go index 4ba02b30f346..68f2b05e0c6d 100644 --- a/azurerm/internal/services/compute/resource_arm_dedicated_host.go +++ b/azurerm/internal/services/compute/resource_arm_dedicated_host.go @@ -11,6 +11,8 @@ import ( "github.com/hashicorp/go-azure-helpers/response" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -30,9 +32,10 @@ func resourceArmDedicatedHost() *schema.Resource { Update: resourceArmDedicatedHostUpdate, Delete: resourceArmDedicatedHostDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.DedicatedHostID(id) + return err + }), Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(30 * time.Minute), @@ -60,9 +63,9 @@ func resourceArmDedicatedHost() *schema.Resource { ValidateFunc: validateDedicatedHostGroupName(), }, - // In order to follow convention for both protal and azure cli, `sku` here means + // In order to follow convention for both protal and azure cli, `sku_name` here means // sku name only. - "sku": { + "sku_name": { Type: schema.TypeString, ForceNew: true, Required: true, @@ -122,18 +125,16 @@ func resourceArmDedicatedHostCreate(d *schema.ResourceData, meta interface{}) er } } - location := azure.NormalizeLocation(d.Get("location").(string)) - t := d.Get("tags").(map[string]interface{}) parameters := compute.DedicatedHost{ - Location: utils.String(location), + Location: utils.String(azure.NormalizeLocation(d.Get("location").(string))), DedicatedHostProperties: &compute.DedicatedHostProperties{ AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), }, Sku: &compute.Sku{ - Name: utils.String(d.Get("sku").(string)), + Name: utils.String(d.Get("sku_name").(string)), }, - Tags: tags.Expand(t), + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } if platformFaultDomain, ok := d.GetOk("platform_fault_domain"); ok { parameters.DedicatedHostProperties.PlatformFaultDomain = utils.Int32(int32(platformFaultDomain.(int))) @@ -164,31 +165,28 @@ func resourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) erro ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.DedicatedHostID(d.Id()) if err != nil { return err } - resourceGroupName := id.ResourceGroup - hostGroupName := id.Path["hostGroups"] - name := id.Path["hosts"] - resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + resp, err := client.Get(ctx, id.ResourceGroup, id.HostGroup, id.Name, "") if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[INFO] Dedicated Host %q does not exist - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("Error reading Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + return fmt.Errorf("Error reading Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } - d.Set("name", name) - d.Set("resource_group_name", resourceGroupName) + d.Set("name", resp.Name) + d.Set("resource_group_name", id.ResourceGroup) if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } - d.Set("host_group_name", hostGroupName) - d.Set("sku", resp.Sku.Name) + d.Set("host_group_name", id.HostGroup) + d.Set("sku_name", resp.Sku.Name) if props := resp.DedicatedHostProperties; props != nil { d.Set("platform_fault_domain", props.PlatformFaultDomain) d.Set("auto_replace_on_failure", props.AutoReplaceOnFailure) @@ -206,14 +204,13 @@ func resourceArmDedicatedHostUpdate(d *schema.ResourceData, meta interface{}) er name := d.Get("name").(string) resourceGroupName := d.Get("resource_group_name").(string) hostGroupName := d.Get("host_group_name").(string) - t := d.Get("tags").(map[string]interface{}) parameters := compute.DedicatedHostUpdate{ DedicatedHostProperties: &compute.DedicatedHostProperties{ AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), }, - Tags: tags.Expand(t), + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } future, err := client.Update(ctx, resourceGroupName, hostGroupName, name, parameters) @@ -232,32 +229,29 @@ func resourceArmDedicatedHostDelete(d *schema.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.DedicatedHostID(d.Id()) if err != nil { return err } - resourceGroupName := id.ResourceGroup - hostGroupName := id.Path["hostGroups"] - name := id.Path["hosts"] - future, err := client.Delete(ctx, resourceGroupName, hostGroupName, name) + future, err := client.Delete(ctx, id.ResourceGroup, id.HostGroup, id.Name) if err != nil { - return fmt.Errorf("Error deleting Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + return fmt.Errorf("Error deleting Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { if !response.WasNotFound(future.Response()) { - return fmt.Errorf("Error waiting for deleting Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + return fmt.Errorf("Error waiting for deleting Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } } // API has bug, which appears to be eventually consistent. Tracked by this issue: https://github.com/Azure/azure-rest-api-specs/issues/8137 - log.Printf("[DEBUG] Waiting for Dedicated Host %q (Host Group Name %q / Resource Group %q) to disappear", name, hostGroupName, resourceGroupName) + log.Printf("[DEBUG] Waiting for Dedicated Host %q (Host Group Name %q / Resource Group %q) to disappear", id.Name, id.HostGroup, id.ResourceGroup) stateConf := &resource.StateChangeConf{ Pending: []string{"Exists"}, Target: []string{"NotFound"}, Refresh: dedicatedHostDeletedRefreshFunc(ctx, client, id), - MinTimeout: 5 * time.Second, + MinTimeout: 10 * time.Second, ContinuousTargetOccurence: 5, } @@ -268,18 +262,15 @@ func resourceArmDedicatedHostDelete(d *schema.ResourceData, meta interface{}) er } if _, err = stateConf.WaitForState(); err != nil { - return fmt.Errorf("Error waiting for Dedicated Host %q (Host Group Name %q / Resource Group %q) to become available: %+v", name, hostGroupName, resourceGroupName, err) + return fmt.Errorf("Error waiting for Dedicated Host %q (Host Group Name %q / Resource Group %q) to become available: %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } return nil } -func dedicatedHostDeletedRefreshFunc(ctx context.Context, client *compute.DedicatedHostsClient, id *azure.ResourceID) resource.StateRefreshFunc { - resourceGroupName := id.ResourceGroup - hostGroupName := id.Path["hostGroups"] - name := id.Path["hosts"] +func dedicatedHostDeletedRefreshFunc(ctx context.Context, client *compute.DedicatedHostsClient, id *parse.DedicatedHostId) resource.StateRefreshFunc { return func() (interface{}, string, error) { - res, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") + res, err := client.Get(ctx, id.ResourceGroup, id.HostGroup, id.Name, "") if err != nil { if utils.ResponseWasNotFound(res.Response) { return "NotFound", "NotFound", nil diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go index 5326c7f2b597..7171e5a618b9 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -2,6 +2,7 @@ package tests import ( "fmt" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" "testing" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" @@ -31,7 +32,7 @@ func TestAccAzureRMDedicatedHost_basic(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), + resource.TestCheckResourceAttr(data.ResourceName, "sku_name", "DSv3-Type1"), ), }, data.ImportStep(), @@ -52,7 +53,7 @@ func TestAccAzureRMDedicatedHost_complete(t *testing.T) { Check: resource.ComposeTestCheckFunc( testCheckAzureRMDedicatedHostExists(data.ResourceName), resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "sku", "DSv3-Type1"), + resource.TestCheckResourceAttr(data.ResourceName, "sku_name", "DSv3-Type1"), resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesWindowsServerHybrid)), resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), ), @@ -78,6 +79,7 @@ func TestAccAzureRMDedicatedHost_update(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), ), }, + data.ImportStep(), { Config: testAccAzureRMDedicatedHost_complete(data), Check: resource.ComposeTestCheckFunc( @@ -86,6 +88,7 @@ func TestAccAzureRMDedicatedHost_update(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), ), }, + data.ImportStep(), }, }) } @@ -121,16 +124,17 @@ func testCheckAzureRMDedicatedHostExists(resourceName string) resource.TestCheck return fmt.Errorf("Dedicated Host not found: %s", resourceName) } - name := rs.Primary.Attributes["name"] - resourceGroupName := rs.Primary.Attributes["resource_group_name"] - hostGroupName := rs.Primary.Attributes["host_group_name"] + id, err := parse.DedicatedHostID(rs.Primary.ID) + if err != nil { + return err + } client := acceptance.AzureProvider.Meta().(*clients.Client).Compute.DedicatedHostsClient ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext - if resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, ""); err != nil { + if resp, err := client.Get(ctx, id.ResourceGroup, id.HostGroup, id.Name, ""); err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: Dedicated Host %q (Host Group Name %q / Resource Group %q) does not exist", name, hostGroupName, resourceGroupName) + return fmt.Errorf("Bad: Dedicated Host %q (Host Group Name %q / Resource Group %q) does not exist", id.Name, id.HostGroup, id.ResourceGroup) } return fmt.Errorf("Bad: Get on Compute.DedicatedHostsClient: %+v", err) } @@ -148,11 +152,12 @@ func testCheckAzureRMDedicatedHostDestroy(s *terraform.State) error { continue } - name := rs.Primary.Attributes["name"] - resourceGroupName := rs.Primary.Attributes["resource_group_name"] - hostGroupName := rs.Primary.Attributes["host_group_name"] + id, err := parse.DedicatedHostID(rs.Primary.ID) + if err != nil { + return err + } - if resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, ""); err != nil { + if resp, err := client.Get(ctx, id.ResourceGroup, id.HostGroup, id.Name, ""); err != nil { if !utils.ResponseWasNotFound(resp.Response) { return fmt.Errorf("Bad: Get on Compute.DedicatedHostsClient: %+v", err) } @@ -184,7 +189,7 @@ resource "azurerm_dedicated_host" "test" { location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name host_group_name = azurerm_dedicated_host_group.test.name - sku = "DSv3-Type1" + sku_name = "DSv3-Type1" platform_fault_domain = 1 } `, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) @@ -210,7 +215,7 @@ resource "azurerm_dedicated_host" "test" { location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name host_group_name = azurerm_dedicated_host_group.test.name - sku = "DSv3-Type1" + sku_name = "DSv3-Type1" platform_fault_domain = 1 license_type = "Windows_Server_Hybrid" auto_replace_on_failure = false @@ -226,7 +231,7 @@ resource "azurerm_dedicated_host" "import" { resource_group_name = azurerm_dedicated_host.test.resource_group_name location = azurerm_dedicated_host.test.location host_group_name = azurerm_dedicated_host.test.host_group_name - sku = azurerm_dedicated_host.test.sku + sku_name = azurerm_dedicated_host.test.sku_name platform_fault_domain = azurerm_dedicated_host.test.platform_fault_domain } `, testAccAzureRMDedicatedHost_basic(data)) diff --git a/website/docs/r/dedicated_host.html.markdown b/website/docs/r/dedicated_host.html.markdown index 38178cf4b07e..0a88550bc27b 100644 --- a/website/docs/r/dedicated_host.html.markdown +++ b/website/docs/r/dedicated_host.html.markdown @@ -31,7 +31,7 @@ resource "azurerm_dedicated_host" "example" { location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name host_group_name = azurerm_dedicated_host_group.example.name - sku = "DSv3-Type1" + sku_name = "DSv3-Type1" platform_fault_domain = 1 } ``` @@ -48,7 +48,7 @@ The following arguments are supported: * `host_group_name` - (Required) Specify the name of the Dedicated Host Group in which to create the Dedicated Host. Changing this forces a new resource to be created. -* `sku` - (Required) Specify the sku name of the Dedicated Host. Possible values are `DSv3-Type1`, `ESv3-Type1`, `FSv2-Type2`. Changing this forces a new resource to be created. +* `sku_name` - (Required) Specify the sku name of the Dedicated Host. Possible values are `DSv3-Type1`, `ESv3-Type1`, `FSv2-Type2`. Changing this forces a new resource to be created. * `platform_fault_domain` - (Required) Specify the fault domain of the Dedicated Host Group in which to create the Dedicated Host. Changing this forces a new resource to be created. From 0b76451c16a5a72eb7c52e518f8d1e8e7afdee97 Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 21 Jan 2020 16:43:21 +0800 Subject: [PATCH 07/10] goimport --- .../services/compute/tests/resource_arm_dedicated_host_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go index 7171e5a618b9..8f42a171033f 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -2,9 +2,10 @@ package tests import ( "fmt" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" "testing" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" + "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" From 09b8b7225a98708c746061ed9a3a8ecc5df46dc3 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 22 Jan 2020 09:43:43 +0800 Subject: [PATCH 08/10] modify per second review --- .../services/compute/resource_arm_dedicated_host.go | 2 -- .../compute/tests/resource_arm_dedicated_host_test.go | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/azurerm/internal/services/compute/resource_arm_dedicated_host.go b/azurerm/internal/services/compute/resource_arm_dedicated_host.go index 68f2b05e0c6d..5b2da6b16a29 100644 --- a/azurerm/internal/services/compute/resource_arm_dedicated_host.go +++ b/azurerm/internal/services/compute/resource_arm_dedicated_host.go @@ -63,8 +63,6 @@ func resourceArmDedicatedHost() *schema.Resource { ValidateFunc: validateDedicatedHostGroupName(), }, - // In order to follow convention for both protal and azure cli, `sku_name` here means - // sku name only. "sku_name": { Type: schema.TypeString, ForceNew: true, diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go index 8f42a171033f..046b730cb4fb 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -178,7 +178,7 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_dedicated_host_group" "test" { - name = "acctestDHG-compute-%s" + name = "acctest-DHG-%s" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location platform_fault_domain_count = 2 @@ -186,7 +186,7 @@ resource "azurerm_dedicated_host_group" "test" { resource "azurerm_dedicated_host" "test" { - name = "acctestDH-compute-%s" + name = "acctest-DH-%s" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name host_group_name = azurerm_dedicated_host_group.test.name @@ -204,7 +204,7 @@ resource "azurerm_resource_group" "test" { } resource "azurerm_dedicated_host_group" "test" { - name = "acctestDHG-compute-%s" + name = "acctest-DHG-%s" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location platform_fault_domain_count = 2 @@ -212,7 +212,7 @@ resource "azurerm_dedicated_host_group" "test" { resource "azurerm_dedicated_host" "test" { - name = "acctestDH-compute-%s" + name = "acctest-DH-%s" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name host_group_name = azurerm_dedicated_host_group.test.name From a75065275433d1704cb91d515a8ac2cf151e7755 Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 22 Jan 2020 10:01:09 +0800 Subject: [PATCH 09/10] modify testcase naming --- .../compute/parse/dedicated_host_test.go | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/azurerm/internal/services/compute/parse/dedicated_host_test.go b/azurerm/internal/services/compute/parse/dedicated_host_test.go index 39fa5f9c6744..3747e4a498a8 100644 --- a/azurerm/internal/services/compute/parse/dedicated_host_test.go +++ b/azurerm/internal/services/compute/parse/dedicated_host_test.go @@ -6,60 +6,60 @@ import ( func TestDedicatedHostID(t *testing.T) { testData := []struct { - Name string - Input string - ExpectedOK bool - ExpectedValue *DedicatedHostId + Name string + Input string + Error bool + Expect *DedicatedHostId }{ { - Name: "Empty", - Input: "", - ExpectedOK: false, + Name: "Empty", + Input: "", + Error: true, }, { - Name: "No Resource Groups Segment", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000", - ExpectedOK: false, + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Error: true, }, { - Name: "No Resource Groups Value", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", - ExpectedOK: false, + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Error: true, }, { - Name: "Resource Group ID", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", - ExpectedOK: false, + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + Error: true, }, { - Name: "Missing Host Group Value", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", - ExpectedOK: false, + Name: "Missing Host Group Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", + Error: true, }, { - Name: "Host Group ID", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/", - ExpectedOK: false, + Name: "Host Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/", + Error: true, }, { - Name: "Missing Host Value", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/", - ExpectedOK: false, + Name: "Missing Host Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/", + Error: true, }, { - Name: "Host ID", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/host1", - ExpectedOK: true, - ExpectedValue: &DedicatedHostId{ + Name: "Host ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/host1", + Error: false, + Expect: &DedicatedHostId{ ResourceGroup: "resGroup1", HostGroup: "group1", Name: "host1", }, }, { - Name: "Wrong Casing", - Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/Hosts/host1", - ExpectedOK: false, + Name: "Wrong Casing", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1/Hosts/host1", + Error: true, }, } @@ -68,23 +68,23 @@ func TestDedicatedHostID(t *testing.T) { actual, err := DedicatedHostID(v.Input) if err != nil { - if v.ExpectedOK == false { + if v.Error { continue } t.Fatalf("Expected a value but got an error: %s", err) } - if actual.Name != v.ExpectedValue.Name { - t.Fatalf("Expected %q but got %q for Name", v.ExpectedValue.Name, actual.Name) + if actual.Name != v.Expect.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name) } - if actual.HostGroup != v.ExpectedValue.HostGroup { - t.Fatalf("Expected %q but got %q for HostGroup", v.ExpectedValue.HostGroup, actual.HostGroup) + if actual.HostGroup != v.Expect.HostGroup { + t.Fatalf("Expected %q but got %q for HostGroup", v.Expect.HostGroup, actual.HostGroup) } - if actual.ResourceGroup != v.ExpectedValue.ResourceGroup { - t.Fatalf("Expected %q but got %q for Resource Group", v.ExpectedValue.ResourceGroup, actual.ResourceGroup) + if actual.ResourceGroup != v.Expect.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup) } } } From a323a710bc1415fabfc66a5d281a23a8ba8b2876 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 24 Jan 2020 15:51:34 +0100 Subject: [PATCH 10/10] r/dedicated_host: fixing comments from code review --- .../compute/data_source_dedicated_host.go | 14 +- .../compute/parse/dedicated_host_group.go | 33 +++ .../parse/dedicated_host_group_test.go | 75 +++++++ .../compute/resource_arm_dedicated_host.go | 70 ++++--- .../tests/data_source_dedicated_host_test.go | 9 +- .../tests/resource_arm_dedicated_host_test.go | 191 +++++++++++++----- .../compute/validate/dedicated_host.go | 22 ++ .../compute/validate/dedicated_host_group.go | 22 ++ website/docs/d/dedicated_host.html.markdown | 12 +- website/docs/r/dedicated_host.html.markdown | 36 ++-- 10 files changed, 373 insertions(+), 111 deletions(-) create mode 100644 azurerm/internal/services/compute/parse/dedicated_host_group.go create mode 100644 azurerm/internal/services/compute/parse/dedicated_host_group_test.go create mode 100644 azurerm/internal/services/compute/validate/dedicated_host.go create mode 100644 azurerm/internal/services/compute/validate/dedicated_host_group.go diff --git a/azurerm/internal/services/compute/data_source_dedicated_host.go b/azurerm/internal/services/compute/data_source_dedicated_host.go index acd1ed219958..34a048b4e5b0 100644 --- a/azurerm/internal/services/compute/data_source_dedicated_host.go +++ b/azurerm/internal/services/compute/data_source_dedicated_host.go @@ -28,16 +28,16 @@ func dataSourceArmDedicatedHost() *schema.Resource { ValidateFunc: validateDedicatedHostName(), }, - "location": azure.SchemaLocationForDataSource(), - - "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), - - "host_group_name": { + "dedicated_host_group_name": { Type: schema.TypeString, Required: true, ValidateFunc: validateDedicatedHostGroupName(), }, + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "location": azure.SchemaLocationForDataSource(), + "tags": tags.SchemaDataSource(), }, } @@ -50,7 +50,7 @@ func dataSourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) er name := d.Get("name").(string) resourceGroupName := d.Get("resource_group_name").(string) - hostGroupName := d.Get("host_group_name").(string) + hostGroupName := d.Get("dedicated_host_group_name").(string) resp, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") if err != nil { @@ -66,7 +66,7 @@ func dataSourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) er if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } - d.Set("host_group_name", hostGroupName) + d.Set("dedicated_host_group_name", hostGroupName) return tags.FlattenAndSet(d, resp.Tags) } diff --git a/azurerm/internal/services/compute/parse/dedicated_host_group.go b/azurerm/internal/services/compute/parse/dedicated_host_group.go new file mode 100644 index 000000000000..d4b847cfc39b --- /dev/null +++ b/azurerm/internal/services/compute/parse/dedicated_host_group.go @@ -0,0 +1,33 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type DedicatedHostGroupId struct { + ResourceGroup string + Name string +} + +func DedicatedHostGroupID(input string) (*DedicatedHostGroupId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Dedicated Host Group ID %q: %+v", input, err) + } + + server := DedicatedHostGroupId{ + ResourceGroup: id.ResourceGroup, + } + + if server.Name, err = id.PopSegment("hostGroups"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &server, nil +} diff --git a/azurerm/internal/services/compute/parse/dedicated_host_group_test.go b/azurerm/internal/services/compute/parse/dedicated_host_group_test.go new file mode 100644 index 000000000000..d02416904e8d --- /dev/null +++ b/azurerm/internal/services/compute/parse/dedicated_host_group_test.go @@ -0,0 +1,75 @@ +package parse + +import ( + "testing" +) + +func TestDedicatedHostGroupID(t *testing.T) { + testData := []struct { + Name string + Input string + Error bool + Expect *DedicatedHostGroupId + }{ + { + Name: "Empty", + Input: "", + Error: true, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Error: true, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Error: true, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + Error: true, + }, + { + Name: "Missing Host Group Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/", + Error: true, + }, + { + Name: "Host Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/hostGroups/group1", + Error: false, + Expect: &DedicatedHostGroupId{ + ResourceGroup: "resGroup1", + Name: "group1", + }, + }, + { + Name: "Wrong Casing", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Compute/HostGroups/group1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := DedicatedHostGroupID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.Expect.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name) + } + + if actual.ResourceGroup != v.Expect.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/compute/resource_arm_dedicated_host.go b/azurerm/internal/services/compute/resource_arm_dedicated_host.go index 5b2da6b16a29..dfa334e9fa22 100644 --- a/azurerm/internal/services/compute/resource_arm_dedicated_host.go +++ b/azurerm/internal/services/compute/resource_arm_dedicated_host.go @@ -7,6 +7,7 @@ import ( "time" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/validate" "github.com/hashicorp/go-azure-helpers/response" @@ -54,13 +55,11 @@ func resourceArmDedicatedHost() *schema.Resource { "location": azure.SchemaLocation(), - "resource_group_name": azure.SchemaResourceGroupName(), - - "host_group_name": { + "dedicated_host_group_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateDedicatedHostGroupName(), + ValidateFunc: validate.DedicatedHostGroupID, }, "sku_name": { @@ -108,8 +107,13 @@ func resourceArmDedicatedHostCreate(d *schema.ResourceData, meta interface{}) er defer cancel() name := d.Get("name").(string) - resourceGroupName := d.Get("resource_group_name").(string) - hostGroupName := d.Get("host_group_name").(string) + dedicatedHostGroupId, err := parse.DedicatedHostGroupID(d.Get("dedicated_host_group_id").(string)) + if err != nil { + return err + } + + resourceGroupName := dedicatedHostGroupId.ResourceGroup + hostGroupName := dedicatedHostGroupId.Name if features.ShouldResourcesBeImported() && d.IsNewResource() { existing, err := client.Get(ctx, resourceGroupName, hostGroupName, name, "") @@ -128,15 +132,13 @@ func resourceArmDedicatedHostCreate(d *schema.ResourceData, meta interface{}) er DedicatedHostProperties: &compute.DedicatedHostProperties{ AutoReplaceOnFailure: utils.Bool(d.Get("auto_replace_on_failure").(bool)), LicenseType: compute.DedicatedHostLicenseTypes(d.Get("license_type").(string)), + PlatformFaultDomain: utils.Int32(int32(d.Get("platform_fault_domain").(int))), }, Sku: &compute.Sku{ Name: utils.String(d.Get("sku_name").(string)), }, Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - if platformFaultDomain, ok := d.GetOk("platform_fault_domain"); ok { - parameters.DedicatedHostProperties.PlatformFaultDomain = utils.Int32(int32(platformFaultDomain.(int))) - } future, err := client.CreateOrUpdate(ctx, resourceGroupName, hostGroupName, name, parameters) if err != nil { @@ -151,7 +153,7 @@ func resourceArmDedicatedHostCreate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error retrieving Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) } if resp.ID == nil { - return fmt.Errorf("Cannot read Dedicated Host %q (Host Group Name %q / Resource Group %q) ID", name, hostGroupName, resourceGroupName) + return fmt.Errorf("Cannot read ID for Dedicated Host %q (Host Group Name %q / Resource Group %q)", name, hostGroupName, resourceGroupName) } d.SetId(*resp.ID) @@ -159,7 +161,8 @@ func resourceArmDedicatedHostCreate(d *schema.ResourceData, meta interface{}) er } func resourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Compute.DedicatedHostsClient + groupsClient := meta.(*clients.Client).Compute.DedicatedHostGroupsClient + hostsClient := meta.(*clients.Client).Compute.DedicatedHostsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -168,27 +171,44 @@ func resourceArmDedicatedHostRead(d *schema.ResourceData, meta interface{}) erro return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.HostGroup, id.Name, "") + group, err := groupsClient.Get(ctx, id.ResourceGroup, id.HostGroup) + if err != nil { + if utils.ResponseWasNotFound(group.Response) { + log.Printf("[INFO] Parent Dedicated Host Group %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving Dedicated Host Group %q (Resource Group %q): %+v", id.HostGroup, id.ResourceGroup, err) + } + + resp, err := hostsClient.Get(ctx, id.ResourceGroup, id.HostGroup, id.Name, "") if err != nil { if utils.ResponseWasNotFound(resp.Response) { log.Printf("[INFO] Dedicated Host %q does not exist - removing from state", d.Id()) d.SetId("") return nil } - return fmt.Errorf("Error reading Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) + + return fmt.Errorf("Error retrieving Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } d.Set("name", resp.Name) - d.Set("resource_group_name", id.ResourceGroup) + d.Set("dedicated_host_group_id", group.ID) + if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } - d.Set("host_group_name", id.HostGroup) d.Set("sku_name", resp.Sku.Name) if props := resp.DedicatedHostProperties; props != nil { - d.Set("platform_fault_domain", props.PlatformFaultDomain) d.Set("auto_replace_on_failure", props.AutoReplaceOnFailure) d.Set("license_type", props.LicenseType) + + platformFaultDomain := 0 + if props.PlatformFaultDomain != nil { + platformFaultDomain = int(*props.PlatformFaultDomain) + } + d.Set("platform_fault_domain", platformFaultDomain) } return tags.FlattenAndSet(d, resp.Tags) @@ -199,9 +219,10 @@ func resourceArmDedicatedHostUpdate(d *schema.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - name := d.Get("name").(string) - resourceGroupName := d.Get("resource_group_name").(string) - hostGroupName := d.Get("host_group_name").(string) + id, err := parse.DedicatedHostID(d.Id()) + if err != nil { + return err + } parameters := compute.DedicatedHostUpdate{ DedicatedHostProperties: &compute.DedicatedHostProperties{ @@ -211,12 +232,12 @@ func resourceArmDedicatedHostUpdate(d *schema.ResourceData, meta interface{}) er Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.Update(ctx, resourceGroupName, hostGroupName, name, parameters) + future, err := client.Update(ctx, id.ResourceGroup, id.HostGroup, id.Name, parameters) if err != nil { - return fmt.Errorf("Error updating Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + return fmt.Errorf("Error updating Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("Error waiting for update of Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", name, hostGroupName, resourceGroupName, err) + return fmt.Errorf("Error waiting for update of Dedicated Host %q (Host Group Name %q / Resource Group %q): %+v", id.Name, id.HostGroup, id.ResourceGroup, err) } return resourceArmDedicatedHostRead(d, meta) @@ -250,7 +271,7 @@ func resourceArmDedicatedHostDelete(d *schema.ResourceData, meta interface{}) er Target: []string{"NotFound"}, Refresh: dedicatedHostDeletedRefreshFunc(ctx, client, id), MinTimeout: 10 * time.Second, - ContinuousTargetOccurence: 5, + ContinuousTargetOccurence: 10, } if features.SupportsCustomTimeouts() { @@ -273,7 +294,8 @@ func dedicatedHostDeletedRefreshFunc(ctx context.Context, client *compute.Dedica if utils.ResponseWasNotFound(res.Response) { return "NotFound", "NotFound", nil } - return nil, "", fmt.Errorf("Error issuing read request in dedicatedHostDeletedRefreshFunc: %+v", err) + + return nil, "", fmt.Errorf("Error polling to check if the Dedicated Host has been deleted: %+v", err) } return res, "Exists", nil diff --git a/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go b/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go index 483469e28867..a896d2df5fbd 100644 --- a/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/data_source_dedicated_host_test.go @@ -19,7 +19,8 @@ func TestAccDataSourceAzureRMDedicatedHost_basic(t *testing.T) { { Config: testAccDataSourceDedicatedHost_basic(data), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(data.ResourceName, "id"), + resource.TestCheckResourceAttrSet(data.ResourceName, "location"), + resource.TestCheckResourceAttrSet(data.ResourceName, "tags.%"), ), }, }, @@ -32,9 +33,9 @@ func testAccDataSourceDedicatedHost_basic(data acceptance.TestData) string { %s data "azurerm_dedicated_host" "test" { - name = azurerm_dedicated_host.test.name - resource_group_name = azurerm_dedicated_host.test.resource_group_name - host_group_name = azurerm_dedicated_host.test.host_group_name + name = azurerm_dedicated_host.test.name + dedicated_host_group_name = azurerm_dedicated_host_group.test.name + resource_group_name = azurerm_dedicated_host_group.test.resource_group_name } `, config) } diff --git a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go index 046b730cb4fb..b3ab2b154960 100644 --- a/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go +++ b/azurerm/internal/services/compute/tests/resource_arm_dedicated_host_test.go @@ -6,7 +6,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" - "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-07-01/compute" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" @@ -30,10 +29,82 @@ func TestAccAzureRMDedicatedHost_basic(t *testing.T) { Config: testAccAzureRMDedicatedHost_basic(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMDedicatedHostExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), - resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), - resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "sku_name", "DSv3-Type1"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMDedicatedHost_autoReplaceOnFailure(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + // Enabled + Config: testAccAzureRMDedicatedHost_autoReplaceOnFailure(data, true), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + // Disabled + Config: testAccAzureRMDedicatedHost_autoReplaceOnFailure(data, false), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + // Enabled + Config: testAccAzureRMDedicatedHost_autoReplaceOnFailure(data, true), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMDedicatedHost_licenseType(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_dedicated_host", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMDedicatedHostDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMDedicatedHost_licenceType(data, "None"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMDedicatedHost_licenceType(data, "Windows_Server_Hybrid"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMDedicatedHost_licenceType(data, "Windows_Server_Perpetual"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMDedicatedHost_licenceType(data, "None"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMDedicatedHostExists(data.ResourceName), ), }, data.ImportStep(), @@ -53,10 +124,6 @@ func TestAccAzureRMDedicatedHost_complete(t *testing.T) { Config: testAccAzureRMDedicatedHost_complete(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMDedicatedHostExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "platform_fault_domain", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "sku_name", "DSv3-Type1"), - resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesWindowsServerHybrid)), - resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), ), }, data.ImportStep(), @@ -76,8 +143,6 @@ func TestAccAzureRMDedicatedHost_update(t *testing.T) { Config: testAccAzureRMDedicatedHost_basic(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMDedicatedHostExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesNone)), - resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "true"), ), }, data.ImportStep(), @@ -85,8 +150,6 @@ func TestAccAzureRMDedicatedHost_update(t *testing.T) { Config: testAccAzureRMDedicatedHost_complete(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMDedicatedHostExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "license_type", string(compute.DedicatedHostLicenseTypesWindowsServerHybrid)), - resource.TestCheckResourceAttr(data.ResourceName, "auto_replace_on_failure", "false"), ), }, data.ImportStep(), @@ -171,69 +234,95 @@ func testCheckAzureRMDedicatedHostDestroy(s *terraform.State) error { } func testAccAzureRMDedicatedHost_basic(data acceptance.TestData) string { + template := testAccAzureRMDedicatedHost_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-compute-%d" - location = "%s" -} +%s -resource "azurerm_dedicated_host_group" "test" { - name = "acctest-DHG-%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - platform_fault_domain_count = 2 +resource "azurerm_dedicated_host" "test" { + name = "acctest-DH-%d" + location = azurerm_resource_group.test.location + dedicated_host_group_id = azurerm_dedicated_host_group.test.id + sku_name = "DSv3-Type1" + platform_fault_domain = 1 +} +`, template, data.RandomInteger) } +func testAccAzureRMDedicatedHost_autoReplaceOnFailure(data acceptance.TestData, replace bool) string { + template := testAccAzureRMDedicatedHost_template(data) + return fmt.Sprintf(` +%s resource "azurerm_dedicated_host" "test" { - name = "acctest-DH-%s" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - host_group_name = azurerm_dedicated_host_group.test.name - sku_name = "DSv3-Type1" - platform_fault_domain = 1 + name = "acctest-DH-%d" + location = azurerm_resource_group.test.location + dedicated_host_group_id = azurerm_dedicated_host_group.test.id + sku_name = "DSv3-Type1" + platform_fault_domain = 1 + auto_replace_on_failure = %t } -`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) +`, template, data.RandomInteger, replace) } -func testAccAzureRMDedicatedHost_complete(data acceptance.TestData) string { +func testAccAzureRMDedicatedHost_licenceType(data acceptance.TestData, licenseType string) string { + template := testAccAzureRMDedicatedHost_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-compute-%d" - location = "%s" -} +%s -resource "azurerm_dedicated_host_group" "test" { - name = "acctest-DHG-%s" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - platform_fault_domain_count = 2 +resource "azurerm_dedicated_host" "test" { + name = "acctest-DH-%d" + location = azurerm_resource_group.test.location + dedicated_host_group_id = azurerm_dedicated_host_group.test.id + sku_name = "DSv3-Type1" + platform_fault_domain = 1 + license_type = %q +} +`, template, data.RandomInteger, licenseType) } +func testAccAzureRMDedicatedHost_complete(data acceptance.TestData) string { + template := testAccAzureRMDedicatedHost_template(data) + return fmt.Sprintf(` +%s resource "azurerm_dedicated_host" "test" { - name = "acctest-DH-%s" + name = "acctest-DH-%d" location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - host_group_name = azurerm_dedicated_host_group.test.name + dedicated_host_group_id = azurerm_dedicated_host_group.test.id sku_name = "DSv3-Type1" platform_fault_domain = 1 license_type = "Windows_Server_Hybrid" auto_replace_on_failure = false } -`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomString) +`, template, data.RandomInteger) } func testAccAzureRMDedicatedHost_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMDedicatedHost_basic(data) return fmt.Sprintf(` %s resource "azurerm_dedicated_host" "import" { - name = azurerm_dedicated_host.test.name - resource_group_name = azurerm_dedicated_host.test.resource_group_name - location = azurerm_dedicated_host.test.location - host_group_name = azurerm_dedicated_host.test.host_group_name - sku_name = azurerm_dedicated_host.test.sku_name - platform_fault_domain = azurerm_dedicated_host.test.platform_fault_domain -} -`, testAccAzureRMDedicatedHost_basic(data)) + name = azurerm_dedicated_host.test.name + location = azurerm_dedicated_host.test.location + dedicated_host_group_id = azurerm_dedicated_host.test.dedicated_host_group_id + sku_name = azurerm_dedicated_host.test.sku_name + platform_fault_domain = azurerm_dedicated_host.test.platform_fault_domain +} +`, template) +} + +func testAccAzureRMDedicatedHost_template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-compute-%d" + location = "%s" +} + +resource "azurerm_dedicated_host_group" "test" { + name = "acctest-DHG-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + platform_fault_domain_count = 2 +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } diff --git a/azurerm/internal/services/compute/validate/dedicated_host.go b/azurerm/internal/services/compute/validate/dedicated_host.go new file mode 100644 index 000000000000..148e77a6dffa --- /dev/null +++ b/azurerm/internal/services/compute/validate/dedicated_host.go @@ -0,0 +1,22 @@ +package validate + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" +) + +func DedicatedHostID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.DedicatedHostID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/azurerm/internal/services/compute/validate/dedicated_host_group.go b/azurerm/internal/services/compute/validate/dedicated_host_group.go new file mode 100644 index 000000000000..b5964eb82c03 --- /dev/null +++ b/azurerm/internal/services/compute/validate/dedicated_host_group.go @@ -0,0 +1,22 @@ +package validate + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/compute/parse" +) + +func DedicatedHostGroupID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.DedicatedHostGroupID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/website/docs/d/dedicated_host.html.markdown b/website/docs/d/dedicated_host.html.markdown index 43e6e46953ad..0ca46f0fe4a3 100644 --- a/website/docs/d/dedicated_host.html.markdown +++ b/website/docs/d/dedicated_host.html.markdown @@ -14,13 +14,13 @@ Use this data source to access information about an existing Dedicated Host. ```hcl data "azurerm_dedicated_host" "example" { - name = "example-dh" - resource_group_name = "example-rg" - host_group_name = "example-dhg" + name = "example-host" + dedicated_host_group_name = "example-host-group" + resource_group_name = "example-resources" } output "dedicated_host_id" { - value = "${data.azurerm_dedicated_host.example.id}" + value = data.azurerm_dedicated_host.example.id } ``` @@ -30,9 +30,9 @@ The following arguments are supported: * `name` - (Required) Specifies the name of the Dedicated Host. -* `resource_group_name` - (Required) Specifies the name of the resource group the Dedicated Host is located in. +* `dedicated_host_group_name` - (Required) Specifies the name of the Dedicated Host Group the Dedicated Host is located in. -* `host_group_name` - (Required) Specifies the name of the Dedicated Host Group the Dedicated Host is located in. +* `resource_group_name` - (Required) Specifies the name of the resource group the Dedicated Host is located in. ## Attributes Reference diff --git a/website/docs/r/dedicated_host.html.markdown b/website/docs/r/dedicated_host.html.markdown index 0a88550bc27b..eddc788e39b4 100644 --- a/website/docs/r/dedicated_host.html.markdown +++ b/website/docs/r/dedicated_host.html.markdown @@ -3,36 +3,34 @@ subcategory: "Compute" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_dedicated_host" description: |- - Manage an Dedicated Host. + Manage a Dedicated Host within a Dedicated Host Group. --- # azurerm_dedicated_host -Manage an Dedicated Host. +Manage a Dedicated Host within a Dedicated Host Group. ## Example Usage ```hcl resource "azurerm_resource_group" "example" { - name = "example-rg" - location = "West US" + name = "example-resourcs" + location = "West Europe" } resource "azurerm_dedicated_host_group" "example" { - name = "example-dhg" + name = "example-host-group" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location platform_fault_domain_count = 2 } - resource "azurerm_dedicated_host" "example" { - name = "example-dh" - location = azurerm_resource_group.example.location - resource_group_name = azurerm_resource_group.example.name - host_group_name = azurerm_dedicated_host_group.example.name - sku_name = "DSv3-Type1" - platform_fault_domain = 1 + name = "example-host" + location = azurerm_resource_group.example.location + dedicated_host_group_id = azurerm_dedicated_host_group.example.id + sku_name = "DSv3-Type1" + platform_fault_domain = 1 } ``` @@ -40,21 +38,21 @@ resource "azurerm_dedicated_host" "example" { The following arguments are supported: -* `name` - (Required) Specify the name of the Dedicated Host. Changing this forces a new resource to be created. +* `name` - (Required) Specifies the name of this Dedicated Host. Changing this forces a new resource to be created. -* `resource_group_name` - (Required) The name of the resource group in which to create the Dedicated Host. Changing this forces a new resource to be created. +* `dedicated_host_group_id` - (Required) Specifies the ID of the Dedicated Host Group where the Dedicated Host should exist. Changing this forces a new resource to be created. * `location` - (Required) Specify the supported Azure location where the resource exists. Changing this forces a new resource to be created. -* `host_group_name` - (Required) Specify the name of the Dedicated Host Group in which to create the Dedicated Host. Changing this forces a new resource to be created. - * `sku_name` - (Required) Specify the sku name of the Dedicated Host. Possible values are `DSv3-Type1`, `ESv3-Type1`, `FSv2-Type2`. Changing this forces a new resource to be created. * `platform_fault_domain` - (Required) Specify the fault domain of the Dedicated Host Group in which to create the Dedicated Host. Changing this forces a new resource to be created. -* `auto_replace_on_failure` - (Optional) Specifies whether the Dedicated Host should be replaced automatically in case of a failure. The value is defaulted to `true` when not provided. +--- + +* `auto_replace_on_failure` - (Optional) Should the Dedicated Host automatically be replaced in case of a Hardware Failure? Defaults to `true`. -* `license_type` - (Optional) Specifies the software license type that will be applied to the VMs deployed on the Dedicated Host. Possible values are: `None`, `Windows_Server_Hybrid`, `Windows_Server_Perpetual`. The value is defaulted to `None` when not provided. +* `license_type` - (Optional) Specifies the software license type that will be applied to the VMs deployed on the Dedicated Host. Possible values are `None`, `Windows_Server_Hybrid` and `Windows_Server_Perpetual`. Defaults to `None`. * `tags` - (Optional) A mapping of tags to assign to the resource. @@ -66,7 +64,7 @@ The following attributes are exported: ## Import -Dedicated Host can be imported using the `resource id`, e.g. +Dedicated Hosts can be imported using the `resource id`, e.g. ```shell $ terraform import azurerm_dedicated_host.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Compute/hostGroups/group1/hosts/host1