From 597935908d33df84c8ad3f6068bb839585303dcd Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Tue, 19 Sep 2017 19:31:27 +0100 Subject: [PATCH] New Resource: `azurerm_app_service` (#344) * Adding azure app service resource * adding importer * adding some tests * updating tests to use testlocation() * setting tags * Resolve App Service Import Acceptance test failure * removed additional spaces which were inserted by editor * removing duplicates * adding documentation * running fmt * updating app service resource * updating app service code * updating tests * updating documentation * setting site config * adding more tests * making use of utils module * WIP * Reserved requires an App Service Environment * Fixing the Java apps * Adding tests for remote debugging * remote debugging version needs to be computed * Fixing the tests * Fixing the jetty tests * Removing linux support for the moment * Adding import tests * Handling setting the appSettings/connectionStrings correctly * Updating the documentation * Removing the updates from the create * Updating the documentation * Updating the TODO's --- azurerm/config.go | 15 +- azurerm/import_arm_app_service_test.go | 468 +++++++++ azurerm/provider.go | 1 + azurerm/resource_arm_app_service.go | 631 ++++++++++++ azurerm/resource_arm_app_service_test.go | 1120 ++++++++++++++++++++++ website/azurerm.erb | 4 + website/docs/r/app_service.html.markdown | 155 +++ 7 files changed, 2386 insertions(+), 8 deletions(-) create mode 100644 azurerm/import_arm_app_service_test.go create mode 100644 azurerm/resource_arm_app_service.go create mode 100644 azurerm/resource_arm_app_service_test.go create mode 100644 website/docs/r/app_service.html.markdown diff --git a/azurerm/config.go b/azurerm/config.go index c04712b5792b..f560bcd6cd69 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -133,12 +133,11 @@ type ArmClient struct { sqlServersClient sql.ServersClient appServicePlansClient web.AppServicePlansClient + appServicesClient web.AppsClient appInsightsClient appinsights.ComponentsClient servicePrincipalsClient graphrbac.ServicePrincipalsClient - - appsClient web.AppsClient } func withRequestLogging() autorest.SendDecorator { @@ -642,6 +641,12 @@ func (c *Config) getArmClient() (*ArmClient, error) { aspc.Sender = sender client.appServicePlansClient = aspc + ac := web.NewAppsClientWithBaseURI(endpoint, c.SubscriptionID) + setUserAgent(&ac.Client) + ac.Authorizer = auth + ac.Sender = autorest.CreateSender(withRequestLogging()) + client.appServicesClient = ac + ai := appinsights.NewComponentsClientWithBaseURI(endpoint, c.SubscriptionID) setUserAgent(&ai.Client) ai.Authorizer = auth @@ -654,12 +659,6 @@ func (c *Config) getArmClient() (*ArmClient, error) { spc.Sender = sender client.servicePrincipalsClient = spc - ac := web.NewAppsClientWithBaseURI(endpoint, c.SubscriptionID) - setUserAgent(&ac.Client) - ac.Authorizer = auth - ac.Sender = sender - client.appsClient = ac - kvc := keyvault.NewVaultsClientWithBaseURI(endpoint, c.SubscriptionID) setUserAgent(&kvc.Client) kvc.Authorizer = auth diff --git a/azurerm/import_arm_app_service_test.go b/azurerm/import_arm_app_service_test.go new file mode 100644 index 000000000000..e2bacbcbae5e --- /dev/null +++ b/azurerm/import_arm_app_service_test.go @@ -0,0 +1,468 @@ +package azurerm + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccAzureRMAppService_importBasic(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_basic(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_import32Bit(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_32Bit(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importAlwaysOn(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_alwaysOn(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importAppSettings(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_appSettings(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importClientAffinityEnabled(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_clientAffinityEnabled(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importConnectionStrings(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_connectionStrings(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importDefaultDocuments(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_defaultDocuments(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importEnabled(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_enabled(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importLocalMySql(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_localMySql(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importManagedPipelineMode(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_managedPipelineMode(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importRemoteDebugging(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_remoteDebugging(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsDotNet2(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsDotNet(ri, testLocation(), "v2.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsDotNet4(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsDotNet(ri, testLocation(), "v4.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsJava7Jetty(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.7", "JETTY", "9.3") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsJava8Jetty(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.8", "JETTY", "9.3") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsJava7Tomcat(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.7", "TOMCAT", "9.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsJava8Tomcat(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.8", "TOMCAT", "9.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsPHP7(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsPHP(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWindowsPython(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsPython(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_importWebSockets(t *testing.T) { + resourceName := "azurerm_app_service.test" + + ri := acctest.RandInt() + config := testAccAzureRMAppService_webSockets(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/azurerm/provider.go b/azurerm/provider.go index f06b6e165b25..c5e9e2c9ea29 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -71,6 +71,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "azurerm_application_insights": resourceArmApplicationInsights(), + "azurerm_app_service": resourceArmAppService(), "azurerm_app_service_plan": resourceArmAppServicePlan(), "azurerm_availability_set": resourceArmAvailabilitySet(), "azurerm_cdn_endpoint": resourceArmCdnEndpoint(), diff --git a/azurerm/resource_arm_app_service.go b/azurerm/resource_arm_app_service.go new file mode 100644 index 000000000000..adcbc368f22d --- /dev/null +++ b/azurerm/resource_arm_app_service.go @@ -0,0 +1,631 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/arm/web" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmAppService() *schema.Resource { + return &schema.Resource{ + Create: resourceArmAppServiceCreate, + Read: resourceArmAppServiceRead, + Update: resourceArmAppServiceUpdate, + Delete: resourceArmAppServiceDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "location": locationSchema(), + + "app_service_plan_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "site_config": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "always_on": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "default_documents": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "dotnet_framework_version": { + Type: schema.TypeString, + Optional: true, + Default: "v4.0", + ValidateFunc: validation.StringInSlice([]string{ + "v2.0", + "v4.0", + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "java_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "1.7", + "1.8", + }, false), + }, + + "java_container": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "JETTY", + "TOMCAT", + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "java_container_version": { + Type: schema.TypeString, + Optional: true, + }, + + "local_mysql_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "managed_pipeline_mode": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + string(web.Classic), + string(web.Integrated), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "php_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "5.5", + "5.6", + "7.0", + "7.1", + }, false), + }, + + "python_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "2.7", + "3.4", + }, false), + }, + + "remote_debugging_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "remote_debugging_version": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice([]string{ + "VS2012", + "VS2013", + "VS2015", + "VS2017", + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + + "use_32_bit_worker_process": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "websockets_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + }, + }, + }, + + "client_affinity_enabled": { + Type: schema.TypeBool, + Optional: true, + Computed: true, + + // TODO: (tombuildsstuff) support Update once the API is fixed: + // https://github.com/Azure/azure-rest-api-specs/issues/1697 + ForceNew: true, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + + // TODO: (tombuildsstuff) support Update once the API is fixed: + // https://github.com/Azure/azure-rest-api-specs/issues/1697 + ForceNew: true, + }, + + "app_settings": { + Type: schema.TypeMap, + Optional: true, + Computed: true, + }, + + "connection_string": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(web.APIHub), + string(web.Custom), + string(web.DocDb), + string(web.EventHub), + string(web.MySQL), + string(web.NotificationHub), + string(web.PostgreSQL), + string(web.RedisCache), + string(web.ServiceBus), + string(web.SQLAzure), + string(web.SQLServer), + }, true), + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + }, + }, + }, + }, + + // TODO: (tombuildsstuff) support Update once the API is fixed: + // https://github.com/Azure/azure-rest-api-specs/issues/1697 + "tags": tagsForceNewSchema(), + }, + } +} + +func resourceArmAppServiceCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + log.Printf("[INFO] preparing arguments for AzureRM App Service creation.") + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + location := d.Get("location").(string) + appServicePlanId := d.Get("app_service_plan_id").(string) + enabled := d.Get("enabled").(bool) + tags := d.Get("tags").(map[string]interface{}) + + siteConfig := expandAppServiceSiteConfig(d) + + siteEnvelope := web.Site{ + Location: &location, + Tags: expandTags(tags), + SiteProperties: &web.SiteProperties{ + ServerFarmID: utils.String(appServicePlanId), + Enabled: utils.Bool(enabled), + SiteConfig: &siteConfig, + }, + } + + if v, ok := d.GetOk("client_affinity_enabled"); ok { + enabled := v.(bool) + siteEnvelope.SiteProperties.ClientAffinityEnabled = utils.Bool(enabled) + } + + // NOTE: these seem like sensible defaults, in lieu of any better documentation. + skipDNSRegistration := false + forceDNSRegistration := false + skipCustomDomainVerification := true + ttlInSeconds := "60" + _, createErr := client.CreateOrUpdate(resGroup, name, siteEnvelope, &skipDNSRegistration, &skipCustomDomainVerification, &forceDNSRegistration, ttlInSeconds, make(chan struct{})) + err := <-createErr + if err != nil { + return err + } + + read, err := client.Get(resGroup, name) + if err != nil { + return err + } + if read.ID == nil { + return fmt.Errorf("Cannot read App Service %s (resource group %s) ID", name, resGroup) + } + + d.SetId(*read.ID) + + return resourceArmAppServiceUpdate(d, meta) +} + +func resourceArmAppServiceUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Path["sites"] + + if d.HasChange("site_config") { + // update the main configuration + siteConfig := expandAppServiceSiteConfig(d) + siteConfigResource := web.SiteConfigResource{ + SiteConfig: &siteConfig, + } + _, err := client.CreateOrUpdateConfiguration(resGroup, name, siteConfigResource) + if err != nil { + return fmt.Errorf("Error updating Configuration for App Service %q: %+v", name, err) + } + } + + if d.HasChange("app_settings") { + // update the AppSettings + appSettings := expandAppServiceAppSettings(d) + settings := web.StringDictionary{ + Properties: appSettings, + } + + _, err := client.UpdateApplicationSettings(resGroup, name, settings) + if err != nil { + return fmt.Errorf("Error updating Application Settings for App Service %q: %+v", name, err) + } + } + + if d.HasChange("connection_string") { + // update the ConnectionStrings + connectionStrings := expandAppServiceConnectionStrings(d) + properties := web.ConnectionStringDictionary{ + Properties: connectionStrings, + } + + _, err := client.UpdateConnectionStrings(resGroup, name, properties) + if err != nil { + return fmt.Errorf("Error updating Connection Strings for App Service %q: %+v", name, err) + } + } + + return resourceArmAppServiceRead(d, meta) +} + +func resourceArmAppServiceRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Path["sites"] + + resp, err := client.Get(resGroup, 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, resGroup) + d.SetId("") + return nil + } + return fmt.Errorf("Error making Read request on AzureRM App Service %q: %+v", name, err) + } + + configResp, err := client.GetConfiguration(resGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service Configuration %q: %+v", name, err) + } + + appSettingsResp, err := client.ListApplicationSettings(resGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service AppSettings %q: %+v", name, err) + } + + connectionStringsResp, err := client.ListConnectionStrings(resGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on AzureRM App Service ConnectionStrings %q: %+v", name, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resGroup) + d.Set("location", azureRMNormalizeLocation(*resp.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) + } + + 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 + } + + flattenAndSetTags(d, resp.Tags) + + return nil +} + +func resourceArmAppServiceDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).appServicesClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + resGroup := id.ResourceGroup + name := id.Path["sites"] + + log.Printf("[DEBUG] Deleting App Service %q (resource group %q)", name, resGroup) + + deleteMetrics := true + deleteEmptyServerFarm := false + skipDNSRegistration := true + resp, err := client.Delete(resGroup, name, &deleteMetrics, &deleteEmptyServerFarm, &skipDNSRegistration) + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return err + } + } + + return nil +} + +func expandAppServiceSiteConfig(d *schema.ResourceData) web.SiteConfig { + configs := d.Get("site_config").([]interface{}) + siteConfig := web.SiteConfig{} + + if len(configs) == 0 { + return siteConfig + } + + config := configs[0].(map[string]interface{}) + + if v, ok := config["always_on"]; ok { + siteConfig.AlwaysOn = utils.Bool(v.(bool)) + } + + if v, ok := config["default_documents"]; ok { + input := v.([]interface{}) + + documents := make([]string, 0) + for _, document := range input { + documents = append(documents, document.(string)) + } + + siteConfig.DefaultDocuments = &documents + } + + if v, ok := config["dotnet_framework_version"]; ok { + siteConfig.NetFrameworkVersion = utils.String(v.(string)) + } + + if v, ok := config["java_version"]; ok { + siteConfig.JavaVersion = utils.String(v.(string)) + } + + if v, ok := config["java_container"]; ok { + siteConfig.JavaContainer = utils.String(v.(string)) + } + + if v, ok := config["java_container_version"]; ok { + siteConfig.JavaContainerVersion = utils.String(v.(string)) + } + + if v, ok := config["local_mysql_enabled"]; ok { + siteConfig.LocalMySQLEnabled = utils.Bool(v.(bool)) + } + + if v, ok := config["managed_pipeline_mode"]; ok { + siteConfig.ManagedPipelineMode = web.ManagedPipelineMode(v.(string)) + } + + if v, ok := config["php_version"]; ok { + siteConfig.PhpVersion = utils.String(v.(string)) + } + + if v, ok := config["python_version"]; ok { + siteConfig.PythonVersion = utils.String(v.(string)) + } + + if v, ok := config["remote_debugging_enabled"]; ok { + siteConfig.RemoteDebuggingEnabled = utils.Bool(v.(bool)) + } + + if v, ok := config["remote_debugging_version"]; ok { + siteConfig.RemoteDebuggingVersion = utils.String(v.(string)) + } + + if v, ok := config["use_32_bit_worker_process"]; ok { + siteConfig.Use32BitWorkerProcess = utils.Bool(v.(bool)) + } + + if v, ok := config["websockets_enabled"]; ok { + siteConfig.WebSocketsEnabled = utils.Bool(v.(bool)) + } + + return siteConfig +} + +func flattenAppServiceSiteConfig(input *web.SiteConfig) []interface{} { + results := make([]interface{}, 0) + result := make(map[string]interface{}, 0) + + if input == nil { + log.Printf("[DEBUG] SiteConfig is nil") + return results + } + + if input.AlwaysOn != nil { + result["always_on"] = *input.AlwaysOn + } + + if input.DefaultDocuments != nil { + documents := make([]string, 0) + for _, document := range *input.DefaultDocuments { + documents = append(documents, document) + } + + result["default_documents"] = documents + } + + if input.NetFrameworkVersion != nil { + result["dotnet_framework_version"] = *input.NetFrameworkVersion + } + + if input.JavaVersion != nil { + result["java_version"] = *input.JavaVersion + } + + if input.JavaContainer != nil { + result["java_container"] = *input.JavaContainer + } + + if input.JavaContainerVersion != nil { + result["java_container_version"] = *input.JavaContainerVersion + } + + if input.LocalMySQLEnabled != nil { + result["local_mysql_enabled"] = *input.LocalMySQLEnabled + } + + result["managed_pipeline_mode"] = string(input.ManagedPipelineMode) + + if input.PhpVersion != nil { + result["php_version"] = *input.PhpVersion + } + + if input.PythonVersion != nil { + result["python_version"] = *input.PythonVersion + } + + if input.RemoteDebuggingEnabled != nil { + result["remote_debugging_enabled"] = *input.RemoteDebuggingEnabled + } + + if input.RemoteDebuggingVersion != nil { + result["remote_debugging_version"] = *input.RemoteDebuggingVersion + } + + if input.Use32BitWorkerProcess != nil { + result["use_32_bit_worker_process"] = *input.Use32BitWorkerProcess + } + + if input.WebSocketsEnabled != nil { + result["websockets_enabled"] = *input.WebSocketsEnabled + } + + results = append(results, result) + return results +} + +func expandAppServiceAppSettings(d *schema.ResourceData) *map[string]*string { + input := d.Get("app_settings").(map[string]interface{}) + output := make(map[string]*string, len(input)) + + for k, v := range input { + output[k] = utils.String(v.(string)) + } + + return &output +} + +func expandAppServiceConnectionStrings(d *schema.ResourceData) *map[string]*web.ConnStringValueTypePair { + input := d.Get("connection_string").([]interface{}) + output := make(map[string]*web.ConnStringValueTypePair, len(input)) + + for _, v := range input { + vals := v.(map[string]interface{}) + + csName := vals["name"].(string) + csType := vals["type"].(string) + csValue := vals["value"].(string) + + output[csName] = &web.ConnStringValueTypePair{ + Value: utils.String(csValue), + Type: web.ConnectionStringType(csType), + } + } + + return &output +} + +func flattenAppServiceConnectionStrings(input *map[string]*web.ConnStringValueTypePair) interface{} { + results := make([]interface{}, 0) + + for k, v := range *input { + result := make(map[string]interface{}, 0) + result["name"] = k + result["type"] = string(v.Type) + result["value"] = *v.Value + results = append(results, result) + } + + return results +} + +func flattenAppServiceAppSettings(input *map[string]*string) map[string]string { + output := make(map[string]string, 0) + for k, v := range *input { + output[k] = *v + } + + return output +} diff --git a/azurerm/resource_arm_app_service_test.go b/azurerm/resource_arm_app_service_test.go new file mode 100644 index 000000000000..0a15e47f23f9 --- /dev/null +++ b/azurerm/resource_arm_app_service_test.go @@ -0,0 +1,1120 @@ +package azurerm + +import ( + "fmt" + "testing" + + "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 TestAccAzureRMAppService_basic(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_basic(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_32Bit(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_32Bit(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.use_32_bit_worker_process", "true"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_alwaysOn(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_alwaysOn(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.always_on", "true"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_appSettings(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_appSettings(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "app_settings.foo", "bar"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_clientAffinityEnabled(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_clientAffinityEnabled(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "client_affinity_enabled", "true"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_connectionStrings(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_connectionStrings(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "connection_string.0.name", "Example"), + resource.TestCheckResourceAttr(resourceName, "connection_string.0.value", "some-postgresql-connection-string"), + resource.TestCheckResourceAttr(resourceName, "connection_string.0.type", "PostgreSQL"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_defaultDocuments(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_defaultDocuments(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.default_documents.0", "first.html"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.default_documents.1", "second.jsp"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.default_documents.2", "third.aspx"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_enabled(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_enabled(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "enabled", "false"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_localMySql(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_localMySql(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.local_mysql_enabled", "true"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_managedPipelineMode(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_managedPipelineMode(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.managed_pipeline_mode", "Classic"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_tagsUpdate(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_tags(ri, testLocation()) + updatedConfig := testAccAzureRMAppService_tagsUpdated(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Hello", "World"), + ), + }, + { + Config: updatedConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.Hello", "World"), + resource.TestCheckResourceAttr(resourceName, "tags.Terraform", "AcceptanceTests"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_remoteDebugging(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_remoteDebugging(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.remote_debugging_enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.remote_debugging_version", "VS2015"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsDotNet2(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsDotNet(ri, testLocation(), "v2.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.dotnet_framework_version", "v2.0"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsDotNet4(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsDotNet(ri, testLocation(), "v4.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.dotnet_framework_version", "v4.0"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsDotNetUpdate(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsDotNet(ri, testLocation(), "v2.0") + updatedConfig := testAccAzureRMAppService_windowsDotNet(ri, testLocation(), "v4.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.dotnet_framework_version", "v2.0"), + ), + }, + { + Config: updatedConfig, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.dotnet_framework_version", "v4.0"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsJava7Jetty(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.7", "JETTY", "9.3") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_version", "1.7"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container", "JETTY"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container_version", "9.3"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsJava8Jetty(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.8", "JETTY", "9.3") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_version", "1.8"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container", "JETTY"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container_version", "9.3"), + ), + }, + }, + }) +} +func TestAccAzureRMAppService_windowsJava7Tomcat(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.7", "TOMCAT", "9.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_version", "1.7"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container", "TOMCAT"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container_version", "9.0"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsJava8Tomcat(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsJava(ri, testLocation(), "1.8", "TOMCAT", "9.0") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_version", "1.8"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container", "TOMCAT"), + resource.TestCheckResourceAttr(resourceName, "site_config.0.java_container_version", "9.0"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsPHP7(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsPHP(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.php_version", "7.1"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_windowsPython(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_windowsPython(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.python_version", "3.4"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_webSockets(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := acctest.RandInt() + config := testAccAzureRMAppService_webSockets(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "site_config.0.websockets_enabled", "true"), + ), + }, + }, + }) +} + +func testCheckAzureRMAppServiceDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).appServicesClient + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_app_service" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + + resp, err := client.Get(resourceGroup, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + return err + } + + return fmt.Errorf("App Service still exists:\n%#v", resp) + } + + return nil +} + +func testCheckAzureRMAppServiceExists(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) + } + + appServiceName := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for App Service: %s", appServiceName) + } + + client := testAccProvider.Meta().(*ArmClient).appServicesClient + + resp, err := client.Get(resourceGroup, appServiceName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: App Service %q (resource group: %q) does not exist", appServiceName, resourceGroup) + } + + return fmt.Errorf("Bad: Get on appServicesClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMAppService_basic(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_alwaysOn(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + always_on = true + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_32Bit(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + use_32_bit_worker_process = true + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_appSettings(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + app_settings { + "foo" = "bar" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_clientAffinityEnabled(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + client_affinity_enabled = true +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_connectionStrings(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + connection_string { + name = "Example" + value = "some-postgresql-connection-string" + type = "PostgreSQL" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_defaultDocuments(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + default_documents = [ + "first.html", + "second.jsp", + "third.aspx", + ] + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_enabled(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + enabled = false +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_localMySql(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + local_mysql_enabled = true + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_managedPipelineMode(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + managed_pipeline_mode = "Classic" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_remoteDebugging(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + remote_debugging_enabled = true + remote_debugging_version = "VS2015" + } + + tags { + "Hello" = "World" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_tags(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + tags { + "Hello" = "World" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_tagsUpdated(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + tags { + "Hello" = "World" + "Terraform" = "AcceptanceTests" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_windowsDotNet(rInt int, location, version 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + dotnet_framework_version = "%s" + } +} +`, rInt, location, rInt, rInt, version) +} + +func testAccAzureRMAppService_windowsJava(rInt int, location, javaVersion, container, containerVersion 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + java_version = "%s" + java_container = "%s" + java_container_version = "%s" + } +} +`, rInt, location, rInt, rInt, javaVersion, container, containerVersion) +} + +func testAccAzureRMAppService_windowsPHP(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + php_version = "7.1" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_windowsPython(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + python_version = "3.4" + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_webSockets(rInt int, location 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 = "acctestAS-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_plan_id = "${azurerm_app_service_plan.test.id}" + + site_config { + websockets_enabled = true + } +} +`, rInt, location, rInt, rInt) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 77770ede3b4e..5d4f9a78e45a 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -59,6 +59,10 @@ App Service (Web Apps) Resources