From 657679cbfa4c07dab5664c5eae4bc90c14dbdd2f Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Thu, 5 Apr 2018 11:31:10 +0200 Subject: [PATCH] New Data Source: `azurerm_app_service` (#1071) * New Data Source: `azurerm_app_service` ``` $ acctests azurerm TestAccDataSourceAzureRMAppService_ === RUN TestAccDataSourceAzureRMAppService_basic --- PASS: TestAccDataSourceAzureRMAppService_basic (253.82s) === RUN TestAccDataSourceAzureRMAppService_tags --- PASS: TestAccDataSourceAzureRMAppService_tags (111.16s) === RUN TestAccDataSourceAzureRMAppService_clientAppAffinityDisabled --- PASS: TestAccDataSourceAzureRMAppService_clientAppAffinityDisabled (103.34s) === RUN TestAccDataSourceAzureRMAppService_siteConfig --- PASS: TestAccDataSourceAzureRMAppService_siteConfig (107.17s) === RUN TestAccDataSourceAzureRMAppService_appSettings --- PASS: TestAccDataSourceAzureRMAppService_appSettings (143.14s) === RUN TestAccDataSourceAzureRMAppService_connectionString --- PASS: TestAccDataSourceAzureRMAppService_connectionString (125.71s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm 844.388s ``` * Sorting the app service fields by name * Updating the tone of language to match a data source * Updating the Data Source test to match the name of the Resource test --- azurerm/data_source_app_service.go | 291 ++++++++++++++++++ azurerm/data_source_app_service_test.go | 199 ++++++++++++ azurerm/provider.go | 1 + azurerm/resource_arm_app_service.go | 19 +- website/azurerm.erb | 4 + website/docs/d/app_service.html.markdown | 94 ++++++ website/docs/d/app_service_plan.html.markdown | 2 +- website/docs/r/app_service.html.markdown | 6 +- 8 files changed, 603 insertions(+), 13 deletions(-) create mode 100644 azurerm/data_source_app_service.go create mode 100644 azurerm/data_source_app_service_test.go create mode 100644 website/docs/d/app_service.html.markdown diff --git a/azurerm/data_source_app_service.go b/azurerm/data_source_app_service.go new file mode 100644 index 000000000000..a7278d0597ec --- /dev/null +++ b/azurerm/data_source_app_service.go @@ -0,0 +1,291 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmAppService() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmAppServiceRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": resourceGroupNameDiffSuppressSchema(), + + "location": locationForDataSourceSchema(), + + "app_service_plan_id": { + Type: schema.TypeString, + Computed: true, + }, + + "site_config": { + Type: schema.TypeList, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "always_on": { + Type: schema.TypeBool, + Computed: true, + }, + + "default_documents": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "dotnet_framework_version": { + Type: schema.TypeString, + Computed: true, + }, + + "java_version": { + Type: schema.TypeString, + Computed: true, + }, + + "java_container": { + Type: schema.TypeString, + Computed: true, + }, + + "java_container_version": { + Type: schema.TypeString, + Computed: true, + }, + + "local_mysql_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "managed_pipeline_mode": { + Type: schema.TypeString, + Computed: true, + }, + + "php_version": { + Type: schema.TypeString, + Computed: true, + }, + + "python_version": { + Type: schema.TypeString, + Computed: true, + }, + + "remote_debugging_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "remote_debugging_version": { + Type: schema.TypeString, + Computed: true, + }, + + "scm_type": { + Type: schema.TypeString, + Computed: true, + }, + + "use_32_bit_worker_process": { + Type: schema.TypeBool, + Computed: true, + }, + + "websockets_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + + "client_affinity_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "app_settings": { + Type: schema.TypeMap, + Computed: true, + }, + + "connection_string": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "value": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "tags": tagsForDataSourceSchema(), + + "site_credential": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "username": { + Type: schema.TypeString, + Computed: true, + }, + "password": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + }, + }, + }, + }, + + "default_site_hostname": { + Type: schema.TypeString, + Computed: true, + }, + + "outbound_ip_addresses": { + Type: schema.TypeString, + Computed: true, + }, + "source_control": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repo_url": { + Type: schema.TypeString, + Computed: true, + }, + "branch": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} +func dataSourceArmAppServiceRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + resourceGroup := d.Get("resource_group_name").(string) + name := d.Get("name").(string) + + ctx := meta.(*ArmClient).StopContext + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] App Service %q (resource group %q) was not found - removing from state", name, resourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on AzureRM App Service %q: %+v", name, err) + } + + configResp, err := client.GetConfiguration(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service Configuration %q: %+v", name, err) + } + + appSettingsResp, err := client.ListApplicationSettings(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service AppSettings %q: %+v", name, err) + } + + connectionStringsResp, err := client.ListConnectionStrings(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service ConnectionStrings %q: %+v", name, err) + } + + scmResp, err := client.GetSourceControl(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service Source Control %q: %+v", name, err) + } + + siteCredFuture, err := client.ListPublishingCredentials(ctx, resourceGroup, name) + if err != nil { + return err + } + err = siteCredFuture.WaitForCompletion(ctx, client.Client) + if err != nil { + return err + } + siteCredResp, err := siteCredFuture.Result(client) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service Site Credential %q: %+v", name, err) + } + + d.SetId(*resp.ID) + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azureRMNormalizeLocation(*location)) + } + + if props := resp.SiteProperties; props != nil { + d.Set("app_service_plan_id", props.ServerFarmID) + d.Set("client_affinity_enabled", props.ClientAffinityEnabled) + d.Set("enabled", props.Enabled) + d.Set("default_site_hostname", props.DefaultHostName) + d.Set("outbound_ip_addresses", props.OutboundIPAddresses) + } + + if err := d.Set("app_settings", flattenAppServiceAppSettings(appSettingsResp.Properties)); err != nil { + return err + } + if err := d.Set("connection_string", flattenAppServiceConnectionStrings(connectionStringsResp.Properties)); err != nil { + return err + } + + siteConfig := flattenAppServiceSiteConfig(configResp.SiteConfig) + if err := d.Set("site_config", siteConfig); err != nil { + return err + } + + scm := flattenAppServiceSourceControl(scmResp.SiteSourceControlProperties) + if err := d.Set("source_control", scm); err != nil { + return err + } + + siteCred := flattenAppServiceSiteCredential(siteCredResp.UserProperties) + if err := d.Set("site_credential", siteCred); err != nil { + return err + } + + flattenAndSetTags(d, resp.Tags) + + return nil +} diff --git a/azurerm/data_source_app_service_test.go b/azurerm/data_source_app_service_test.go new file mode 100644 index 000000000000..fe5fb97606f6 --- /dev/null +++ b/azurerm/data_source_app_service_test.go @@ -0,0 +1,199 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAzureRMAppService_basic(t *testing.T) { + dataSourceName := "data.azurerm_app_service.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_basic(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "app_service_plan_id"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "0"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMAppService_tags(t *testing.T) { + dataSourceName := "data.azurerm_app_service.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_tags(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.Hello", "World"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMAppService_clientAppAffinityDisabled(t *testing.T) { + dataSourceName := "data.azurerm_app_service.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_clientAffinityDisabled(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "client_affinity_enabled", "false"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMAppService_32Bit(t *testing.T) { + dataSourceName := "data.azurerm_app_service.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_32Bit(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "site_config.0.use_32_bit_worker_process", "true"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMAppService_appSettings(t *testing.T) { + dataSourceName := "data.azurerm_app_service.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_appSettings(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "app_settings.foo", "bar"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMAppService_connectionString(t *testing.T) { + dataSourceName := "data.azurerm_app_service.test" + rInt := acctest.RandInt() + location := testLocation() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_connectionStrings(rInt, location), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "connection_string.0.name", "Example"), + resource.TestCheckResourceAttr(dataSourceName, "connection_string.0.value", "some-postgresql-connection-string"), + resource.TestCheckResourceAttr(dataSourceName, "connection_string.0.type", "PostgreSQL"), + ), + }, + }, + }) +} + +func testAccDataSourceAppService_basic(rInt int, location string) string { + config := testAccAzureRMAppService_basic(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_app_service.test.resource_group_name}" +} +`, config) +} + +func testAccDataSourceAppService_tags(rInt int, location string) string { + config := testAccAzureRMAppService_tags(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_app_service.test.resource_group_name}" +} +`, config) +} + +func testAccDataSourceAppService_clientAffinityDisabled(rInt int, location string) string { + config := testAccAzureRMAppService_clientAffinityDisabled(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_app_service.test.resource_group_name}" +} +`, config) +} + +func testAccDataSourceAppService_32Bit(rInt int, location string) string { + config := testAccAzureRMAppService_32Bit(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_app_service.test.resource_group_name}" +} +`, config) +} + +func testAccDataSourceAppService_appSettings(rInt int, location string) string { + config := testAccAzureRMAppService_appSettings(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_app_service.test.resource_group_name}" +} +`, config) +} + +func testAccDataSourceAppService_connectionStrings(rInt int, location string) string { + config := testAccAzureRMAppService_connectionStrings(rInt, location) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = "${azurerm_app_service.test.name}" + resource_group_name = "${azurerm_app_service.test.resource_group_name}" +} +`, config) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index dc8d6dd61a68..a0c9b1ac75c7 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -78,6 +78,7 @@ func Provider() terraform.ResourceProvider { DataSourcesMap: map[string]*schema.Resource{ "azurerm_application_security_group": dataSourceArmApplicationSecurityGroup(), + "azurerm_app_service": dataSourceArmAppService(), "azurerm_app_service_plan": dataSourceAppServicePlan(), "azurerm_builtin_role_definition": dataSourceArmBuiltInRoleDefinition(), "azurerm_client_config": dataSourceArmClientConfig(), diff --git a/azurerm/resource_arm_app_service.go b/azurerm/resource_arm_app_service.go index 44d31200f18f..10864b23bee0 100644 --- a/azurerm/resource_arm_app_service.go +++ b/azurerm/resource_arm_app_service.go @@ -150,6 +150,16 @@ func resourceArmAppService() *schema.Resource { DiffSuppressFunc: ignoreCaseDiffSuppressFunc, }, + "scm_type": { + Type: schema.TypeString, + Optional: true, + Default: string(web.ScmTypeNone), + ValidateFunc: validation.StringInSlice([]string{ + string(web.ScmTypeNone), + string(web.ScmTypeLocalGit), + }, false), + }, + "use_32_bit_worker_process": { Type: schema.TypeBool, Optional: true, @@ -161,15 +171,6 @@ func resourceArmAppService() *schema.Resource { Optional: true, Computed: true, }, - "scm_type": { - Type: schema.TypeString, - Optional: true, - Default: string(web.ScmTypeNone), - ValidateFunc: validation.StringInSlice([]string{ - string(web.ScmTypeNone), - string(web.ScmTypeLocalGit), - }, false), - }, }, }, }, diff --git a/website/azurerm.erb b/website/azurerm.erb index 1f61a8335205..031ab7b6fbf2 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -31,6 +31,10 @@ azurerm_application_security_group + > + azurerm_app_service + + > azurerm_app_service_plan diff --git a/website/docs/d/app_service.html.markdown b/website/docs/d/app_service.html.markdown new file mode 100644 index 000000000000..0e57109bcd85 --- /dev/null +++ b/website/docs/d/app_service.html.markdown @@ -0,0 +1,94 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_app_service" +sidebar_current: "docs-azurerm-datasource-app-service-x" +description: |- + Get information about an App Service. +--- + +# Data Source: azurerm_app_service + +Use this data source to obtain information about an App Service. + +## Example Usage + +```hcl +data "azurerm_app_service" "test" { + name = "search-app-service" + resource_group_name = "search-service" +} + +output "app_service_id" { + value = "${data.azurerm_app_service.test.id}" +} +``` + +## Argument Reference + +* `name` - (Required) The name of the App Service. + +* `resource_group_name` - (Required) The Name of the Resource Group where the App Service exists. + +## Attributes Reference + +* `id` - The ID of the App Service. + +* `location` - The Azure location where the App Service exists. + +* `app_service_plan_id` - The ID of the App Service Plan within which the App Service exists. + +* `app_settings` - A key-value pair of App Settings for the App Service. + +* `connection_string` - An `connection_string` block as defined below. + +* `client_affinity_enabled` - Does the App Service send session affinity cookies, which route client requests in the same session to the same instance? + +* `enabled` - Is the App Service Enabled? + +* `site_config` - A `site_config` object as defined below. + +* `tags` - A mapping of tags to assign to the resource. + +--- + +`connection_string` supports the following: + +* `name` - The name of the Connection String. + +* `type` - The type of the Connection String. + +* `value` - The value for the Connection String. + +--- + +`site_config` supports the following: + +* `always_on` - Is the app be loaded at all times? + +* `default_documents` - The ordering of default documents to load, if an address isn't specified. + +* `dotnet_framework_version` - The version of the .net framework's CLR used in this App Service. + +* `java_version` - The version of Java in use. + +* `java_container` - The Java Container in use. + +* `java_container_version` - The version of the Java Container in use. + +* `local_mysql_enabled` - Is "MySQL In App" Enabled? This runs a local MySQL instance with your app and shares resources from the App Service plan. + +* `managed_pipeline_mode` - The Managed Pipeline Mode used in this App Service. + +* `php_version` - The version of PHP used in this App Service. + +* `python_version` - The version of Python used in this App Service. + +* `remote_debugging_enabled` - Is Remote Debugging Enabled in this App Service? + +* `remote_debugging_version` - Which version of Visual Studio is the Remote Debugger compatible with? + +* `scm_type` - The type of Source Control enabled for this App Service. + +* `use_32_bit_worker_process` - Does the App Service run in 32 bit mode, rather than 64 bit mode? + +* `websockets_enabled` - Are WebSockets enabled for this App Service? diff --git a/website/docs/d/app_service_plan.html.markdown b/website/docs/d/app_service_plan.html.markdown index f4da3b39e881..581e623ff156 100644 --- a/website/docs/d/app_service_plan.html.markdown +++ b/website/docs/d/app_service_plan.html.markdown @@ -14,7 +14,7 @@ Use this data source to obtain information about an App Service Plan (formerly k ```hcl data "azurerm_app_service_plan" "test" { - name = "search-app-service" + name = "search-app-service-plan" resource_group_name = "search-service" } diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index d187bec6f979..d032cf74b1c3 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -109,9 +109,9 @@ resource "azurerm_app_service" "test" { The following arguments are supported: -* `name` - (Required) Specifies the name of the App Service Plan component. Changing this forces a new resource to be created. +* `name` - (Required) Specifies the name of the App Service. Changing this forces a new resource to be created. -* `resource_group_name` - (Required) The name of the resource group in which to create the App Service Plan component. +* `resource_group_name` - (Required) The name of the resource group in which to create the App Service. * `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. @@ -158,13 +158,13 @@ The following arguments are supported: * `python_version` - (Optional) The version of Python to use in this App Service. Possible values are `2.7` and `3.4`. * `remote_debugging_enabled` - (Optional) Is Remote Debugging Enabled? Defaults to `false`. * `remote_debugging_version` - (Optional) Which version of Visual Studio should the Remote Debugger be compatible with? Possible values are `VS2012`, `VS2013`, `VS2015` and `VS2017`. +* `scm_type` - (Optional) The type of Source Control enabled for this App Service. Possible values include `None` and `LocalGit`. Defaults to `None`. * `use_32_bit_worker_process` - (Optional) Should the App Service run in 32 bit mode, rather than 64 bit mode? ~> **NOTE:** when using an App Service Plan in the `Free` or `Shared` Tiers `use_32_bit_worker_process` must be set to `true`. * `websockets_enabled` - (Optional) Should WebSockets be enabled? -* `scm_type` - (Optional) The type of Source Control enabled for this App Service. Possible values include `None` and `LocalGit`. Defaults to `None`. ~> **NOTE:** Additional Source Control types will be added in the future, once support for them has been added in the Azure SDK for Go.