From fbbab251f8270b2a3a8696d378233a9554966a58 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 6 Apr 2018 16:32:26 +0200 Subject: [PATCH] New Resource: `azurerm_app_service_custom_hostname_binding` Tests pass: ``` $ acctests azurerm TestAccAzureRMAppServiceCustomHostnameBinding === RUN TestAccAzureRMAppServiceCustomHostnameBinding === RUN TestAccAzureRMAppServiceCustomHostnameBinding/basic === RUN TestAccAzureRMAppServiceCustomHostnameBinding/basic/basic === RUN TestAccAzureRMAppServiceCustomHostnameBinding/basic/import --- PASS: TestAccAzureRMAppServiceCustomHostnameBinding (223.11s) --- PASS: TestAccAzureRMAppServiceCustomHostnameBinding/basic (223.10s) --- PASS: TestAccAzureRMAppServiceCustomHostnameBinding/basic/basic (124.19s) --- PASS: TestAccAzureRMAppServiceCustomHostnameBinding/basic/import (98.92s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 223.140s ``` --- ...t_arm_app_service_hostname_binding_test.go | 68 +++++++++ azurerm/provider.go | 1 + ...arm_app_service_custom_hostname_binding.go | 124 ++++++++++++++++ ...pp_service_custom_hostname_binding_test.go | 134 ++++++++++++++++++ website/azurerm.erb | 6 +- ...vice_custom_hostname_binding.html.markdown | 79 +++++++++++ 6 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 azurerm/import_arm_app_service_hostname_binding_test.go create mode 100644 azurerm/resource_arm_app_service_custom_hostname_binding.go create mode 100644 azurerm/resource_arm_app_service_custom_hostname_binding_test.go create mode 100644 website/docs/r/app_service_custom_hostname_binding.html.markdown diff --git a/azurerm/import_arm_app_service_hostname_binding_test.go b/azurerm/import_arm_app_service_hostname_binding_test.go new file mode 100644 index 000000000000..9e51fcf61401 --- /dev/null +++ b/azurerm/import_arm_app_service_hostname_binding_test.go @@ -0,0 +1,68 @@ +package azurerm + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccAzureRMAppServiceCustomHostnameBinding(t *testing.T) { + // NOTE: this is a combined test rather than separate split out tests due to + // the app service name being shared (so the tests don't conflict with each other) + testCases := map[string]map[string]func(t *testing.T){ + "basic": { + "basic": testAccAzureRMAppServiceCustomHostnameBinding_basic, + "import": testAccAzureRMAppServiceCustomHostnameBinding_import, + }, + } + + for group, m := range testCases { + m := m + t.Run(group, func(t *testing.T) { + for name, tc := range m { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } + }) + } +} + +func testAccAzureRMAppServiceCustomHostnameBinding_import(t *testing.T) { + appServiceEnvVariable := "ARM_TEST_APP_SERVICE" + appServiceEnv := os.Getenv(appServiceEnvVariable) + if appServiceEnv == "" { + t.Skipf("Skipping as %q is not specified", appServiceEnvVariable) + } + + domainEnvVariable := "ARM_TEST_DOMAIN" + domainEnv := os.Getenv(domainEnvVariable) + if domainEnv == "" { + t.Skipf("Skipping as %q is not specified", domainEnvVariable) + } + + resourceName := "azurerm_app_service_custom_hostname_binding.test" + + ri := acctest.RandInt() + location := testLocation() + config := testAccAzureRMAppServiceCustomHostnameBinding_basicConfig(ri, location, appServiceEnv, domainEnv) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceCustomHostnameBindingDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index a0c9b1ac75c7..b2749c080419 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -113,6 +113,7 @@ func Provider() terraform.ResourceProvider { "azurerm_app_service": resourceArmAppService(), "azurerm_app_service_plan": resourceArmAppServicePlan(), "azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(), + "azurerm_app_service_custom_hostname_binding": resourceArmAppServiceCustomHostnameBinding(), "azurerm_app_service_slot": resourceArmAppServiceSlot(), "azurerm_automation_account": resourceArmAutomationAccount(), "azurerm_automation_credential": resourceArmAutomationCredential(), diff --git a/azurerm/resource_arm_app_service_custom_hostname_binding.go b/azurerm/resource_arm_app_service_custom_hostname_binding.go new file mode 100644 index 000000000000..5e2fb2d3f38e --- /dev/null +++ b/azurerm/resource_arm_app_service_custom_hostname_binding.go @@ -0,0 +1,124 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2016-09-01/web" + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmAppServiceCustomHostnameBinding() *schema.Resource { + return &schema.Resource{ + Create: resourceArmAppServiceCustomHostnameBindingCreate, + Read: resourceArmAppServiceCustomHostnameBindingRead, + Delete: resourceArmAppServiceCustomHostnameBindingDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "hostname": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": resourceGroupNameSchema(), + + "app_service_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceArmAppServiceCustomHostnameBindingCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + ctx := meta.(*ArmClient).StopContext + + log.Printf("[INFO] preparing arguments for App Service Hostname Binding creation.") + + resourceGroup := d.Get("resource_group_name").(string) + appServiceName := d.Get("app_service_name").(string) + hostname := d.Get("hostname").(string) + + properties := web.HostNameBinding{ + HostNameBindingProperties: &web.HostNameBindingProperties{ + SiteName: utils.String(appServiceName), + }, + } + _, err := client.CreateOrUpdateHostNameBinding(ctx, resourceGroup, appServiceName, hostname, properties) + if err != nil { + return err + } + + read, err := client.GetHostNameBinding(ctx, resourceGroup, appServiceName, hostname) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Cannot read Hostname Binding %q (App Service %q / Resource Group %q) ID", hostname, appServiceName, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceArmAppServiceCustomHostnameBindingRead(d, meta) +} + +func resourceArmAppServiceCustomHostnameBindingRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + appServiceName := id.Path["sites"] + hostname := id.Path["hostNameBindings"] + + ctx := meta.(*ArmClient).StopContext + resp, err := client.GetHostNameBinding(ctx, resourceGroup, appServiceName, hostname) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] App Service Hostname Binding %q (App Service %q / Resource Group %q) was not found - removing from state", hostname, appServiceName, resourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on App Service Hostname Binding %q (App Service %q / Resource Group %q): %+v", hostname, appServiceName, resourceGroup, err) + } + + d.Set("hostname", hostname) + d.Set("app_service_name", appServiceName) + d.Set("resource_group_name", resourceGroup) + + return nil +} + +func resourceArmAppServiceCustomHostnameBindingDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + appServiceName := id.Path["sites"] + hostname := id.Path["hostNameBindings"] + + log.Printf("[DEBUG] Deleting App Service Hostname Binding %q (App Service %q / Resource Group %q)", hostname, appServiceName, resGroup) + + ctx := meta.(*ArmClient).StopContext + resp, err := client.DeleteHostNameBinding(ctx, resGroup, appServiceName, hostname) + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return err + } + } + + return nil +} diff --git a/azurerm/resource_arm_app_service_custom_hostname_binding_test.go b/azurerm/resource_arm_app_service_custom_hostname_binding_test.go new file mode 100644 index 000000000000..7ab2b0c6fbbb --- /dev/null +++ b/azurerm/resource_arm_app_service_custom_hostname_binding_test.go @@ -0,0 +1,134 @@ +package azurerm + +import ( + "fmt" + "testing" + + "os" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func testAccAzureRMAppServiceCustomHostnameBinding_basic(t *testing.T) { + appServiceEnvVariable := "ARM_TEST_APP_SERVICE" + appServiceEnv := os.Getenv(appServiceEnvVariable) + if appServiceEnv == "" { + t.Skipf("Skipping as %q is not specified", appServiceEnvVariable) + } + + domainEnvVariable := "ARM_TEST_DOMAIN" + domainEnv := os.Getenv(domainEnvVariable) + if domainEnv == "" { + t.Skipf("Skipping as %q is not specified", domainEnvVariable) + } + + resourceName := "azurerm_app_service_custom_hostname_binding.test" + ri := acctest.RandInt() + location := testLocation() + config := testAccAzureRMAppServiceCustomHostnameBinding_basicConfig(ri, location, appServiceEnv, domainEnv) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceCustomHostnameBindingDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceCustomHostnameBindingExists(resourceName), + ), + }, + }, + }) +} + +func testCheckAzureRMAppServiceCustomHostnameBindingDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).appServicesClient + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_app_service_custom_hostname_binding" { + continue + } + + resourceGroup := rs.Primary.Attributes["resource_group_name"] + appServiceName := rs.Primary.Attributes["app_service_name"] + hostname := rs.Primary.Attributes["hostname"] + + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.GetHostNameBinding(ctx, resourceGroup, appServiceName, hostname) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + return err + } + + return nil + } + + return nil +} + +func testCheckAzureRMAppServiceCustomHostnameBindingExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + resourceGroup := rs.Primary.Attributes["resource_group_name"] + appServiceName := rs.Primary.Attributes["app_service_name"] + hostname := rs.Primary.Attributes["hostname"] + + client := testAccProvider.Meta().(*ArmClient).appServicesClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.GetHostNameBinding(ctx, resourceGroup, appServiceName, hostname) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Hostname Binding %q (App Service %q / Resource Group: %q) does not exist", hostname, appServiceName, resourceGroup) + } + + return fmt.Errorf("Bad: Get on appServicesClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMAppServiceCustomHostnameBinding_basicConfig(rInt int, location string, appServiceName string, domain string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "%s" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" +} + +resource "azurerm_app_service_custom_hostname_binding" "test" { + hostname = "%s" + app_service_name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, rInt, location, rInt, appServiceName, domain) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 031ab7b6fbf2..526a13a74afe 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -156,7 +156,11 @@ > - azurerm_app_service_active_slot + azurerm_app_service_active_slot + + + > + azurerm_app_service_custom_hostname_binding > diff --git a/website/docs/r/app_service_custom_hostname_binding.html.markdown b/website/docs/r/app_service_custom_hostname_binding.html.markdown new file mode 100644 index 000000000000..3f5b9b28ed61 --- /dev/null +++ b/website/docs/r/app_service_custom_hostname_binding.html.markdown @@ -0,0 +1,79 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_app_service_custom_hostname_binding" +sidebar_current: "docs-azurerm-resource-app-service-custom-hostname-binding" +description: |- + Manages a Hostname Binding within an App Service. + +--- + +# azurerm_app_service_custom_hostname_binding + +Manages a Hostname Binding within an App Service. + +## Example Usage + +```hcl +resource "random_id" "server" { + keepers = { + azi_id = 1 + } + + byte_length = 8 +} + +resource "azurerm_resource_group" "test" { + name = "some-resource-group" + location = "West Europe" +} + +resource "azurerm_app_service_plan" "test" { + name = "some-app-service-plan" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "${random_id.server.hex}" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" +} + +resource "azurerm_app_service_custom_hostname_binding" "test" { + hostname = "www.mywebsite.com" + app_service_name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `hostname` - (Required) Specifies the Custom Hostname to use for the App Service, example `www.example.com`. Changing this forces a new resource to be created. + +~> **NOTE:** A CNAME needs to be configured from this Hostname to the Azure Website - otherwise Azure will reject the Hostname Binding. + +* `app_service_name` - (Required) The name of the App Service in which to add the Custom Hostname Binding. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which the App Service exists. Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the App Service Custom Hostname Binding + +## Import + +App Service Custom Hostname Bindings can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_app_service_custom_hostname_binding.mywebsite /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/sites/instance1/hostNameBindings/mywebsite.com +```