diff --git a/azurerm/helpers/azure/app_service.go b/azurerm/helpers/azure/app_service.go index c8a5ff6d3de3..20c9e6356cc9 100644 --- a/azurerm/helpers/azure/app_service.go +++ b/azurerm/helpers/azure/app_service.go @@ -485,6 +485,7 @@ func SchemaAppServiceLogsConfig() *schema.Schema { "application_logs": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -520,6 +521,35 @@ func SchemaAppServiceLogsConfig() *schema.Schema { }, }, }, + "http_logs": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file_system": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "retention_in_mb": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(25, 100), + }, + "retention_in_days": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(0), + }, + }, + }, + }, + }, + }, + }, }, }, } @@ -1094,14 +1124,13 @@ func FlattenAppServiceLogs(input *web.SiteLogsConfigProperties) []interface{} { result := make(map[string]interface{}) + appLogs := make([]interface{}, 0) if input.ApplicationLogs != nil { - appLogs := make([]interface{}, 0) appLogsItem := make(map[string]interface{}) + blobStorage := make([]interface{}, 0) if blobStorageInput := input.ApplicationLogs.AzureBlobStorage; blobStorageInput != nil { - blobStorage := make([]interface{}, 0) - blobStorageItem := make(map[string]interface{}) blobStorageItem["level"] = string(blobStorageInput.Level) @@ -1114,15 +1143,42 @@ func FlattenAppServiceLogs(input *web.SiteLogsConfigProperties) []interface{} { blobStorageItem["retention_in_days"] = *blobStorageInput.RetentionInDays } - blobStorage = append(blobStorage, blobStorageItem) - - appLogsItem["azure_blob_storage"] = blobStorage + // The API returns a non nil application logs object when other logs are specified so we'll check that this structure is empty before adding it to the statefile. + if blobStorageInput.SasURL != nil && *blobStorageInput.SasURL != "" { + blobStorage = append(blobStorage, blobStorageItem) + } } - + appLogsItem["azure_blob_storage"] = blobStorage appLogs = append(appLogs, appLogsItem) + } + result["application_logs"] = appLogs + + httpLogs := make([]interface{}, 0) + if input.HTTPLogs != nil { + httpLogsItem := make(map[string]interface{}) + + fileSystem := make([]interface{}, 0) + if fileSystemInput := input.HTTPLogs.FileSystem; fileSystemInput != nil { + + fileSystemItem := make(map[string]interface{}) - result["application_logs"] = appLogs + if fileSystemInput.RetentionInDays != nil { + fileSystemItem["retention_in_days"] = *fileSystemInput.RetentionInDays + } + + if fileSystemInput.RetentionInMb != nil { + fileSystemItem["retention_in_mb"] = *fileSystemInput.RetentionInMb + } + + // The API returns a non nil filesystem logs object when other logs are specified so we'll check that this is disabled before adding it to the statefile. + if fileSystemInput.Enabled != nil && *fileSystemInput.Enabled { + fileSystem = append(fileSystem, fileSystemItem) + } + } + httpLogsItem["file_system"] = fileSystem + httpLogs = append(httpLogs, httpLogsItem) } + result["http_logs"] = httpLogs return append(results, result) } @@ -1161,6 +1217,30 @@ func ExpandAppServiceLogs(input interface{}) web.SiteLogsConfigProperties { } } + if v, ok := config["http_logs"]; ok { + httpLogsConfigs := v.([]interface{}) + + for _, config := range httpLogsConfigs { + httpLogsConfig := config.(map[string]interface{}) + + logs.HTTPLogs = &web.HTTPLogsConfig{} + + if v, ok := httpLogsConfig["file_system"]; ok { + fileSystemConfigs := v.([]interface{}) + + for _, config := range fileSystemConfigs { + fileSystemConfig := config.(map[string]interface{}) + + logs.HTTPLogs.FileSystem = &web.FileSystemHTTPLogsConfig{ + RetentionInMb: utils.Int32(int32(fileSystemConfig["retention_in_mb"].(int))), + RetentionInDays: utils.Int32(int32(fileSystemConfig["retention_in_days"].(int))), + Enabled: utils.Bool(true), + } + } + } + } + } + return logs } diff --git a/azurerm/resource_arm_app_service_test.go b/azurerm/resource_arm_app_service_test.go index f14ef12af364..d045b947784c 100644 --- a/azurerm/resource_arm_app_service_test.go +++ b/azurerm/resource_arm_app_service_test.go @@ -955,6 +955,69 @@ func TestAccAzureRMAppService_applicationBlobStorageLogs(t *testing.T) { }) } +func TestAccAzureRMAppService_httpFileSystemLogs(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := tf.AccRandTimeInt() + config := testAccAzureRMAppService_httpFileSystemLogs(ri, testLocation()) + config2 := testAccAzureRMAppService_basic(ri, testLocation()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: config2, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAppService_httpFileSystemAndStorageBlobLogs(t *testing.T) { + resourceName := "azurerm_app_service.test" + ri := tf.AccRandTimeInt() + rs := acctest.RandString(5) + config := testAccAzureRMAppService_httpFileSystemAndStorageBlobLogs(ri, rs, testLocation()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAzureRMAppService_managedPipelineMode(t *testing.T) { resourceName := "azurerm_app_service.test" ri := tf.AccRandTimeInt() @@ -3172,6 +3235,72 @@ resource "azurerm_app_service" "test" { `, rInt, location, rInt, rInt) } +func testAccAzureRMAppService_httpFileSystemLogs(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}" + + logs { + http_logs { + file_system { + retention_in_days = 4 + retention_in_mb = 25 + } + } + } +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMAppService_httpFileSystemAndStorageBlobLogs(rInt int, rString string, location string) string { + template := testAccAzureRMAppService_backupTemplate(rInt, rString, location) + return fmt.Sprintf(` +%s + +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}" + + logs { + application_logs { + azure_blob_storage { + level = "Information" + sas_url = "https://${azurerm_storage_account.test.name}.blob.core.windows.net/${azurerm_storage_container.test.name}${data.azurerm_storage_account_sas.test.sas}&sr=b" + retention_in_days = 3 + } + } + http_logs { + file_system { + retention_in_days = 4 + retention_in_mb = 25 + } + } + } +} +`, template, rInt) +} + func testAccAzureRMAppService_managedPipelineMode(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index 1c2a107b9e0c..846aaadc4683 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -135,6 +135,8 @@ A `logs` block supports the following: * `application_logs` - (Optional) An `application_logs` block as defined below. +* `http_logs` - (Optional) An `http_logs` block as defined below. + --- An `application_logs` block supports the following: @@ -153,6 +155,14 @@ An `azure_blob_storage` block supports the following: --- +An `http_logs` block supports the following: + +* `retention_in_days` - (Required) The number of days to retain logs for. + +* `retention_in_mb` - (Required) The maximum size in megabytes that http log files can use before being removed. + +--- + A `site_config` block supports the following: * `always_on` - (Optional) Should the app be loaded at all times? Defaults to `false`.