From f75f12191cd110ed253fcfc92d82ccab363dcd21 Mon Sep 17 00:00:00 2001 From: Tracy Holmes Date: Tue, 29 Oct 2019 14:01:32 -0500 Subject: [PATCH 01/19] adds new resource file w/ initial changes --- ...resource_arm_advanced_threat_protection.go | 624 ++++++++++++++++++ 1 file changed, 624 insertions(+) create mode 100644 azurerm/resource_arm_advanced_threat_protection.go diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go new file mode 100644 index 000000000000..500bcad7721b --- /dev/null +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -0,0 +1,624 @@ +package azurerm + +import ( + "fmt" + "log" + "net/http" + "regexp" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/v1.0/security" + "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" + azautorest "github.com/Azure/go-autorest/autorest" + "github.com/hashicorp/go-getter/helper/url" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "github.com/tombuildsstuff/giovanni/storage/2018-11-09/queue/queues" +) + +const blobStorageAccountDefaultAccessTier = "Hot" + +func resourceArmAdvancedThreatProtection() *schema.Resource { + return &schema.Resource{ + Create: resourceArmAdvancedThreatProtectionCreate, + Read: resourceArmAdvancedThreatProtectionRead, + Update: resourceArmAdvancedThreatProtectionUpdate, + + MigrateState: resourceStorageAccountMigrateState, + SchemaVersion: 2, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateArmStorageAccountName, + }, + + "resource_group_name": azure.SchemaResourceGroupNameDiffSuppress(), + + "location": azure.SchemaLocation(), + }, + } +} + +func resourceArmAdvancedThreatProtectionCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Storage.AccountsClient + advancedThreatProtectionClient := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient + ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) + defer cancel() + + storageAccountName := d.Get("name").(string) + resourceGroupName := d.Get("resource_group_name").(string) + + if features.ShouldResourcesBeImported() { + existing, err := client.GetProperties(ctx, resourceGroupName, storageAccountName, "") + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing Storage Account %q (Resource Group %q): %s", storageAccountName, resourceGroupName, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_storage_account", *existing.ID) + } + } + + accountKind := d.Get("account_kind").(string) + location := azure.NormalizeLocation(d.Get("location").(string)) + t := d.Get("tags").(map[string]interface{}) + enableBlobEncryption := d.Get("enable_blob_encryption").(bool) + enableFileEncryption := d.Get("enable_file_encryption").(bool) + enableHTTPSTrafficOnly := d.Get("enable_https_traffic_only").(bool) + isHnsEnabled := d.Get("is_hns_enabled").(bool) + + accountTier := d.Get("account_tier").(string) + replicationType := d.Get("account_replication_type").(string) + storageType := fmt.Sprintf("%s_%s", accountTier, replicationType) + storageAccountEncryptionSource := d.Get("account_encryption_source").(string) + + parameters := storage.AccountCreateParameters{ + Location: &location, + Sku: &storage.Sku{ + Name: storage.SkuName(storageType), + }, + Tags: tags.Expand(t), + Kind: storage.Kind(accountKind), + AccountPropertiesCreateParameters: &storage.AccountPropertiesCreateParameters{ + Encryption: &storage.Encryption{ + Services: &storage.EncryptionServices{ + Blob: &storage.EncryptionService{ + Enabled: utils.Bool(enableBlobEncryption), + }, + File: &storage.EncryptionService{ + Enabled: utils.Bool(enableFileEncryption), + }}, + KeySource: storage.KeySource(storageAccountEncryptionSource), + }, + EnableHTTPSTrafficOnly: &enableHTTPSTrafficOnly, + NetworkRuleSet: expandStorageAccountNetworkRules(d), + IsHnsEnabled: &isHnsEnabled, + }, + } + + if _, ok := d.GetOk("identity"); ok { + storageAccountIdentity := expandAzureRmStorageAccountIdentity(d) + parameters.Identity = storageAccountIdentity + } + + if _, ok := d.GetOk("custom_domain"); ok { + parameters.CustomDomain = expandStorageAccountCustomDomain(d) + } + + // BlobStorage does not support ZRS + if accountKind == string(storage.BlobStorage) { + if string(parameters.Sku.Name) == string(storage.StandardZRS) { + return fmt.Errorf("A `account_replication_type` of `ZRS` isn't supported for Blob Storage accounts.") + } + } + + // AccessTier is only valid for BlobStorage, StorageV2, and FileStorage accounts + if accountKind == string(storage.BlobStorage) || accountKind == string(storage.StorageV2) || accountKind == string(storage.FileStorage) { + accessTier, ok := d.GetOk("access_tier") + if !ok { + // default to "Hot" + accessTier = blobStorageAccountDefaultAccessTier + } + + parameters.AccountPropertiesCreateParameters.AccessTier = storage.AccessTier(accessTier.(string)) + } else { + if isHnsEnabled { + return fmt.Errorf("`is_hns_enabled` can only be used with account kinds `StorageV2` and `BlobStorage`") + } + } + + // AccountTier must be Premium for FileStorage + if accountKind == string(storage.FileStorage) { + if string(parameters.Sku.Tier) == string(storage.StandardLRS) { + return fmt.Errorf("A `account_tier` of `Standard` is not supported for FileStorage accounts.") + } + } + + // Create + future, err := client.Create(ctx, resourceGroupName, storageAccountName, parameters) + if err != nil { + return fmt.Errorf("Error creating Azure Storage Account %q: %+v", storageAccountName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for Azure Storage Account %q to be created: %+v", storageAccountName, err) + } + + account, err := client.GetProperties(ctx, resourceGroupName, storageAccountName, "") + if err != nil { + return fmt.Errorf("Error retrieving Azure Storage Account %q: %+v", storageAccountName, err) + } + + if account.ID == nil { + return fmt.Errorf("Cannot read Storage Account %q (resource group %q) ID", + storageAccountName, resourceGroupName) + } + log.Printf("[INFO] storage account %q ID: %q", storageAccountName, *account.ID) + d.SetId(*account.ID) + + // TODO: deprecate & split this out into it's own resource in 2.0 + // as this is not available in all regions, and presumably off by default + // lets only try to set this value when true + // TODO in 2.0 switch to guarding this with d.GetOkExists() ? + if v := d.Get("enable_advanced_threat_protection").(bool); v { + advancedThreatProtectionSetting := security.AdvancedThreatProtectionSetting{ + AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ + IsEnabled: utils.Bool(v), + }, + } + + if _, err = advancedThreatProtectionClient.Create(ctx, d.Id(), advancedThreatProtectionSetting); err != nil { + return fmt.Errorf("Error updating Azure Storage Account enable_advanced_threat_protection %q: %+v", storageAccountName, err) + } + } + + if val, ok := d.GetOk("queue_properties"); ok { + storageClient := meta.(*ArmClient).Storage + account, err := storageClient.FindAccount(ctx, storageAccountName) + if err != nil { + return fmt.Errorf("Error retrieving Account %q: %s", storageAccountName, err) + } + if account == nil { + return fmt.Errorf("Unable to locate Storage Account %q!", storageAccountName) + } + + queueClient, err := storageClient.QueuesClient(ctx, *account) + if err != nil { + return fmt.Errorf("Error building Queues Client: %s", err) + } + + queueProperties, err := expandQueueProperties(val.([]interface{})) + if err != nil { + return fmt.Errorf("Error expanding `queue_properties` for Azure Storage Account %q: %+v", storageAccountName, err) + } + + if _, err = queueClient.SetServiceProperties(ctx, storageAccountName, queueProperties); err != nil { + return fmt.Errorf("Error updating Azure Storage Account `queue_properties` %q: %+v", storageAccountName, err) + } + } + + return resourceArmAdvancedThreatProtectionRead(d, meta) +} + +// resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined +// and idempotent operation for CreateOrUpdate. In particular updating all of the parameters +// available requires a call to Update per parameter... +func resourceArmAdvancedThreatProtectionUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Storage.AccountsClient + advancedThreatProtectionClient := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient + ctx, cancel := timeouts.ForUpdate(meta.(*ArmClient).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + storageAccountName := id.Path["storageAccounts"] + resourceGroupName := id.ResourceGroup + + accountTier := d.Get("account_tier").(string) + replicationType := d.Get("account_replication_type").(string) + storageType := fmt.Sprintf("%s_%s", accountTier, replicationType) + accountKind := d.Get("account_kind").(string) + + if accountKind == string(storage.BlobStorage) { + if storageType == string(storage.StandardZRS) { + return fmt.Errorf("A `account_replication_type` of `ZRS` isn't supported for Blob Storage accounts.") + } + } + + d.Partial(true) + + if d.HasChange("account_replication_type") { + sku := storage.Sku{ + Name: storage.SkuName(storageType), + } + + opts := storage.AccountUpdateParameters{ + Sku: &sku, + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account type %q: %+v", storageAccountName, err) + } + + d.SetPartial("account_replication_type") + } + + if d.HasChange("access_tier") { + accessTier := d.Get("access_tier").(string) + + opts := storage.AccountUpdateParameters{ + AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ + AccessTier: storage.AccessTier(accessTier), + }, + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account access_tier %q: %+v", storageAccountName, err) + } + + d.SetPartial("access_tier") + } + + if d.HasChange("tags") { + t := d.Get("tags").(map[string]interface{}) + + opts := storage.AccountUpdateParameters{ + Tags: tags.Expand(t), + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account tags %q: %+v", storageAccountName, err) + } + + d.SetPartial("tags") + } + + if d.HasChange("enable_blob_encryption") || d.HasChange("enable_file_encryption") { + encryptionSource := d.Get("account_encryption_source").(string) + + opts := storage.AccountUpdateParameters{ + AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ + Encryption: &storage.Encryption{ + Services: &storage.EncryptionServices{}, + KeySource: storage.KeySource(encryptionSource), + }, + }, + } + + if d.HasChange("enable_blob_encryption") { + enableEncryption := d.Get("enable_blob_encryption").(bool) + opts.Encryption.Services.Blob = &storage.EncryptionService{ + Enabled: utils.Bool(enableEncryption), + } + + d.SetPartial("enable_blob_encryption") + } + + if d.HasChange("enable_file_encryption") { + enableEncryption := d.Get("enable_file_encryption").(bool) + opts.Encryption.Services.File = &storage.EncryptionService{ + Enabled: utils.Bool(enableEncryption), + } + d.SetPartial("enable_file_encryption") + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account Encryption %q: %+v", storageAccountName, err) + } + } + + if d.HasChange("custom_domain") { + opts := storage.AccountUpdateParameters{ + AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ + CustomDomain: expandStorageAccountCustomDomain(d), + }, + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account Custom Domain %q: %+v", storageAccountName, err) + } + } + + if d.HasChange("enable_https_traffic_only") { + enableHTTPSTrafficOnly := d.Get("enable_https_traffic_only").(bool) + + opts := storage.AccountUpdateParameters{ + AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ + EnableHTTPSTrafficOnly: &enableHTTPSTrafficOnly, + }, + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account enable_https_traffic_only %q: %+v", storageAccountName, err) + } + + d.SetPartial("enable_https_traffic_only") + } + + if d.HasChange("identity") { + opts := storage.AccountUpdateParameters{ + Identity: expandAzureRmStorageAccountIdentity(d), + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account identity %q: %+v", storageAccountName, err) + } + } + + if d.HasChange("network_rules") { + opts := storage.AccountUpdateParameters{ + AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ + NetworkRuleSet: expandStorageAccountNetworkRules(d), + }, + } + + if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account network_rules %q: %+v", storageAccountName, err) + } + + d.SetPartial("network_rules") + } + + if d.HasChange("enable_advanced_threat_protection") { + opts := security.AdvancedThreatProtectionSetting{ + AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ + IsEnabled: utils.Bool(d.Get("enable_advanced_threat_protection").(bool)), + }, + } + + if _, err := advancedThreatProtectionClient.Create(ctx, d.Id(), opts); err != nil { + return fmt.Errorf("Error updating Azure Storage Account enable_advanced_threat_protection %q: %+v", storageAccountName, err) + } + + d.SetPartial("enable_advanced_threat_protection") + } + + if d.HasChange("queue_properties") { + storageClient := meta.(*ArmClient).Storage + account, err := storageClient.FindAccount(ctx, storageAccountName) + if err != nil { + return fmt.Errorf("Error retrieving Account %q: %s", storageAccountName, err) + } + if account == nil { + return fmt.Errorf("Unable to locate Storage Account %q!", storageAccountName) + } + + queueClient, err := storageClient.QueuesClient(ctx, *account) + if err != nil { + return fmt.Errorf("Error building Queues Client: %s", err) + } + + queueProperties, err := expandQueueProperties(d.Get("queue_properties").([]interface{})) + if err != nil { + return fmt.Errorf("Error expanding `queue_properties` for Azure Storage Account %q: %+v", storageAccountName, err) + } + + if _, err = queueClient.SetServiceProperties(ctx, storageAccountName, queueProperties); err != nil { + return fmt.Errorf("Error updating Azure Storage Account `queue_properties` %q: %+v", storageAccountName, err) + } + + d.SetPartial("queue_properties") + } + + d.Partial(false) + return resourceArmAdvancedThreatProtectionRead(d, meta) +} + +func resourceArmAdvancedThreatProtectionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).Storage.AccountsClient + advancedThreatProtectionClient := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient + endpointSuffix := meta.(*ArmClient).environment.StorageEndpointSuffix + ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + name := id.Path["storageAccounts"] + resGroup := id.ResourceGroup + + resp, err := client.GetProperties(ctx, resGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %+v", name, err) + } + + // handle the user not having permissions to list the keys + d.Set("primary_connection_string", "") + d.Set("secondary_connection_string", "") + d.Set("primary_blob_connection_string", "") + d.Set("secondary_blob_connection_string", "") + d.Set("primary_access_key", "") + d.Set("secondary_access_key", "") + + keys, err := client.ListKeys(ctx, resGroup, name) + if err != nil { + // the API returns a 200 with an inner error of a 409.. + var hasWriteLock bool + var doesntHavePermissions bool + if e, ok := err.(azautorest.DetailedError); ok { + if status, ok := e.StatusCode.(int); ok { + hasWriteLock = status == http.StatusConflict + doesntHavePermissions = status == http.StatusUnauthorized + } + } + + if !hasWriteLock && !doesntHavePermissions { + return fmt.Errorf("Error listing Keys for Storage Account %q (Resource Group %q): %s", name, resGroup, err) + } + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", resGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + d.Set("account_kind", resp.Kind) + + if sku := resp.Sku; sku != nil { + d.Set("account_type", sku.Name) + d.Set("account_tier", sku.Tier) + d.Set("account_replication_type", strings.Split(fmt.Sprintf("%v", sku.Name), "_")[1]) + } + + if props := resp.AccountProperties; props != nil { + d.Set("access_tier", props.AccessTier) + d.Set("enable_https_traffic_only", props.EnableHTTPSTrafficOnly) + d.Set("is_hns_enabled", props.IsHnsEnabled) + + if customDomain := props.CustomDomain; customDomain != nil { + if err := d.Set("custom_domain", flattenStorageAccountCustomDomain(customDomain)); err != nil { + return fmt.Errorf("Error setting `custom_domain`: %+v", err) + } + } + + if encryption := props.Encryption; encryption != nil { + if services := encryption.Services; services != nil { + if blob := services.Blob; blob != nil { + d.Set("enable_blob_encryption", blob.Enabled) + } + if file := services.File; file != nil { + d.Set("enable_file_encryption", file.Enabled) + } + } + d.Set("account_encryption_source", string(encryption.KeySource)) + } + + // Computed + d.Set("primary_location", props.PrimaryLocation) + d.Set("secondary_location", props.SecondaryLocation) + + if accessKeys := keys.Keys; accessKeys != nil { + storageAccountKeys := *accessKeys + if len(storageAccountKeys) > 0 { + pcs := fmt.Sprintf("DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=%s", *resp.Name, *storageAccountKeys[0].Value, endpointSuffix) + d.Set("primary_connection_string", pcs) + } + + if len(storageAccountKeys) > 1 { + scs := fmt.Sprintf("DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=%s", *resp.Name, *storageAccountKeys[1].Value, endpointSuffix) + d.Set("secondary_connection_string", scs) + } + } + + if err := flattenAndSetAzureRmStorageAccountPrimaryEndpoints(d, props.PrimaryEndpoints); err != nil { + return fmt.Errorf("error setting primary endpoints and hosts for blob, queue, table and file: %+v", err) + } + + if accessKeys := keys.Keys; accessKeys != nil { + storageAccountKeys := *accessKeys + var primaryBlobConnectStr string + if v := props.PrimaryEndpoints; v != nil { + primaryBlobConnectStr = getBlobConnectionString(v.Blob, resp.Name, storageAccountKeys[0].Value) + } + d.Set("primary_blob_connection_string", primaryBlobConnectStr) + } + + if err := flattenAndSetAzureRmStorageAccountSecondaryEndpoints(d, props.SecondaryEndpoints); err != nil { + return fmt.Errorf("error setting secondary endpoints and hosts for blob, queue, table: %+v", err) + } + + if accessKeys := keys.Keys; accessKeys != nil { + storageAccountKeys := *accessKeys + var secondaryBlobConnectStr string + if v := props.SecondaryEndpoints; v != nil { + secondaryBlobConnectStr = getBlobConnectionString(v.Blob, resp.Name, storageAccountKeys[1].Value) + } + d.Set("secondary_blob_connection_string", secondaryBlobConnectStr) + } + + if networkRules := props.NetworkRuleSet; networkRules != nil { + if err := d.Set("network_rules", flattenStorageAccountNetworkRules(networkRules)); err != nil { + return fmt.Errorf("Error setting `network_rules`: %+v", err) + } + } + } + + if accessKeys := keys.Keys; accessKeys != nil { + storageAccountKeys := *accessKeys + d.Set("primary_access_key", storageAccountKeys[0].Value) + d.Set("secondary_access_key", storageAccountKeys[1].Value) + } + + identity := flattenAzureRmStorageAccountIdentity(resp.Identity) + if err := d.Set("identity", identity); err != nil { + return err + } + + // TODO in 2.0 switch to guarding this with d.GetOkExists() + atp, err := advancedThreatProtectionClient.Get(ctx, d.Id()) + if err != nil { + msg := err.Error() + if !strings.Contains(msg, "The resource namespace 'Microsoft.Security' is invalid.") { + if !strings.Contains(msg, "No registered resource provider found for location '") { + if !strings.Contains(msg, "' and API version '2017-08-01-preview' for type ") { + return fmt.Errorf("Error reading the advanced threat protection settings of AzureRM Storage Account %q: %+v", name, err) + } + } + } + } else { + if atpp := atp.AdvancedThreatProtectionProperties; atpp != nil { + d.Set("enable_advanced_threat_protection", atpp.IsEnabled) + } + } + + storageClient := meta.(*ArmClient).Storage + account, err := storageClient.FindAccount(ctx, name) + if err != nil { + return fmt.Errorf("Error retrieving Account %q: %s", name, err) + } + if account == nil { + return fmt.Errorf("Unable to locate Storage Account %q!", name) + } + + queueClient, err := storageClient.QueuesClient(ctx, *account) + if err != nil { + return fmt.Errorf("Error building Queues Client: %s", err) + } + + queueProps, err := queueClient.GetServiceProperties(ctx, name) + if err != nil { + if queueProps.Response.Response != nil && !utils.ResponseWasNotFound(queueProps.Response) { + return fmt.Errorf("Error reading queue properties for AzureRM Storage Account %q: %+v", name, err) + } + } + + if err := d.Set("queue_properties", flattenQueueProperties(queueProps)); err != nil { + return fmt.Errorf("Error setting `queue_properties `for AzureRM Storage Account %q: %+v", name, err) + } + + return tags.FlattenAndSet(d, resp.Tags) +} From 99472becaf776cf5c97f75ef7e778d3df2e35d14 Mon Sep 17 00:00:00 2001 From: Tracy Holmes Date: Tue, 29 Oct 2019 15:15:39 -0500 Subject: [PATCH 02/19] cleanup --- ...resource_arm_advanced_threat_protection.go | 167 ------------------ 1 file changed, 167 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 500bcad7721b..df83749bf46a 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -4,27 +4,19 @@ import ( "fmt" "log" "net/http" - "regexp" "strings" "time" "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/v1.0/security" "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" azautorest "github.com/Azure/go-autorest/autorest" - "github.com/hashicorp/go-getter/helper/url" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/response" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - "github.com/tombuildsstuff/giovanni/storage/2018-11-09/queue/queues" ) const blobStorageAccountDefaultAccessTier = "Hot" @@ -256,138 +248,6 @@ func resourceArmAdvancedThreatProtectionUpdate(d *schema.ResourceData, meta inte d.Partial(true) - if d.HasChange("account_replication_type") { - sku := storage.Sku{ - Name: storage.SkuName(storageType), - } - - opts := storage.AccountUpdateParameters{ - Sku: &sku, - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account type %q: %+v", storageAccountName, err) - } - - d.SetPartial("account_replication_type") - } - - if d.HasChange("access_tier") { - accessTier := d.Get("access_tier").(string) - - opts := storage.AccountUpdateParameters{ - AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ - AccessTier: storage.AccessTier(accessTier), - }, - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account access_tier %q: %+v", storageAccountName, err) - } - - d.SetPartial("access_tier") - } - - if d.HasChange("tags") { - t := d.Get("tags").(map[string]interface{}) - - opts := storage.AccountUpdateParameters{ - Tags: tags.Expand(t), - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account tags %q: %+v", storageAccountName, err) - } - - d.SetPartial("tags") - } - - if d.HasChange("enable_blob_encryption") || d.HasChange("enable_file_encryption") { - encryptionSource := d.Get("account_encryption_source").(string) - - opts := storage.AccountUpdateParameters{ - AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ - Encryption: &storage.Encryption{ - Services: &storage.EncryptionServices{}, - KeySource: storage.KeySource(encryptionSource), - }, - }, - } - - if d.HasChange("enable_blob_encryption") { - enableEncryption := d.Get("enable_blob_encryption").(bool) - opts.Encryption.Services.Blob = &storage.EncryptionService{ - Enabled: utils.Bool(enableEncryption), - } - - d.SetPartial("enable_blob_encryption") - } - - if d.HasChange("enable_file_encryption") { - enableEncryption := d.Get("enable_file_encryption").(bool) - opts.Encryption.Services.File = &storage.EncryptionService{ - Enabled: utils.Bool(enableEncryption), - } - d.SetPartial("enable_file_encryption") - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account Encryption %q: %+v", storageAccountName, err) - } - } - - if d.HasChange("custom_domain") { - opts := storage.AccountUpdateParameters{ - AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ - CustomDomain: expandStorageAccountCustomDomain(d), - }, - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account Custom Domain %q: %+v", storageAccountName, err) - } - } - - if d.HasChange("enable_https_traffic_only") { - enableHTTPSTrafficOnly := d.Get("enable_https_traffic_only").(bool) - - opts := storage.AccountUpdateParameters{ - AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ - EnableHTTPSTrafficOnly: &enableHTTPSTrafficOnly, - }, - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account enable_https_traffic_only %q: %+v", storageAccountName, err) - } - - d.SetPartial("enable_https_traffic_only") - } - - if d.HasChange("identity") { - opts := storage.AccountUpdateParameters{ - Identity: expandAzureRmStorageAccountIdentity(d), - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account identity %q: %+v", storageAccountName, err) - } - } - - if d.HasChange("network_rules") { - opts := storage.AccountUpdateParameters{ - AccountPropertiesUpdateParameters: &storage.AccountPropertiesUpdateParameters{ - NetworkRuleSet: expandStorageAccountNetworkRules(d), - }, - } - - if _, err := client.Update(ctx, resourceGroupName, storageAccountName, opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account network_rules %q: %+v", storageAccountName, err) - } - - d.SetPartial("network_rules") - } - if d.HasChange("enable_advanced_threat_protection") { opts := security.AdvancedThreatProtectionSetting{ AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ @@ -402,33 +262,6 @@ func resourceArmAdvancedThreatProtectionUpdate(d *schema.ResourceData, meta inte d.SetPartial("enable_advanced_threat_protection") } - if d.HasChange("queue_properties") { - storageClient := meta.(*ArmClient).Storage - account, err := storageClient.FindAccount(ctx, storageAccountName) - if err != nil { - return fmt.Errorf("Error retrieving Account %q: %s", storageAccountName, err) - } - if account == nil { - return fmt.Errorf("Unable to locate Storage Account %q!", storageAccountName) - } - - queueClient, err := storageClient.QueuesClient(ctx, *account) - if err != nil { - return fmt.Errorf("Error building Queues Client: %s", err) - } - - queueProperties, err := expandQueueProperties(d.Get("queue_properties").([]interface{})) - if err != nil { - return fmt.Errorf("Error expanding `queue_properties` for Azure Storage Account %q: %+v", storageAccountName, err) - } - - if _, err = queueClient.SetServiceProperties(ctx, storageAccountName, queueProperties); err != nil { - return fmt.Errorf("Error updating Azure Storage Account `queue_properties` %q: %+v", storageAccountName, err) - } - - d.SetPartial("queue_properties") - } - d.Partial(false) return resourceArmAdvancedThreatProtectionRead(d, meta) } From e9dc3e39ea76873610018a56619eb2a368f6c8ba Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 29 Oct 2019 14:10:22 -0700 Subject: [PATCH 03/19] pairing progress --- ...resource_arm_advanced_threat_protection.go | 433 ++---------------- ...rce_arm_advanced_threat_protection_test.go | 184 ++++++++ 2 files changed, 233 insertions(+), 384 deletions(-) create mode 100644 azurerm/resource_arm_advanced_threat_protection_test.go diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index df83749bf46a..7c88c71d67fd 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -2,33 +2,22 @@ package azurerm import ( "fmt" - "log" - "net/http" "strings" "time" "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/v1.0/security" - "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage" - azautorest "github.com/Azure/go-autorest/autorest" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -const blobStorageAccountDefaultAccessTier = "Hot" - func resourceArmAdvancedThreatProtection() *schema.Resource { return &schema.Resource{ - Create: resourceArmAdvancedThreatProtectionCreate, + Create: resourceArmAdvancedThreatProtectionCreateUpdate, Read: resourceArmAdvancedThreatProtectionRead, - Update: resourceArmAdvancedThreatProtectionUpdate, - - MigrateState: resourceStorageAccountMigrateState, - SchemaVersion: 2, + Update: resourceArmAdvancedThreatProtectionCreateUpdate, + Delete: resourceArmAdvancedThreatProtectionDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -42,416 +31,92 @@ func resourceArmAdvancedThreatProtection() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { + "resource_id": { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateArmStorageAccountName, + ValidateFunc: azure.ValidateResourceID, }, - "resource_group_name": azure.SchemaResourceGroupNameDiffSuppress(), - - "location": azure.SchemaLocation(), + "enable": { + Type: schema.TypeBool, + Required: true, + }, }, } } -func resourceArmAdvancedThreatProtectionCreate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient).Storage.AccountsClient - advancedThreatProtectionClient := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient +func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) defer cancel() - storageAccountName := d.Get("name").(string) - resourceGroupName := d.Get("resource_group_name").(string) - - if features.ShouldResourcesBeImported() { - existing, err := client.GetProperties(ctx, resourceGroupName, storageAccountName, "") - if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Error checking for presence of existing Storage Account %q (Resource Group %q): %s", storageAccountName, resourceGroupName, err) - } - } + resourceID := d.Get("resource_id").(string) - if existing.ID != nil && *existing.ID != "" { - return tf.ImportAsExistsError("azurerm_storage_account", *existing.ID) - } - } - - accountKind := d.Get("account_kind").(string) - location := azure.NormalizeLocation(d.Get("location").(string)) - t := d.Get("tags").(map[string]interface{}) - enableBlobEncryption := d.Get("enable_blob_encryption").(bool) - enableFileEncryption := d.Get("enable_file_encryption").(bool) - enableHTTPSTrafficOnly := d.Get("enable_https_traffic_only").(bool) - isHnsEnabled := d.Get("is_hns_enabled").(bool) - - accountTier := d.Get("account_tier").(string) - replicationType := d.Get("account_replication_type").(string) - storageType := fmt.Sprintf("%s_%s", accountTier, replicationType) - storageAccountEncryptionSource := d.Get("account_encryption_source").(string) - - parameters := storage.AccountCreateParameters{ - Location: &location, - Sku: &storage.Sku{ - Name: storage.SkuName(storageType), - }, - Tags: tags.Expand(t), - Kind: storage.Kind(accountKind), - AccountPropertiesCreateParameters: &storage.AccountPropertiesCreateParameters{ - Encryption: &storage.Encryption{ - Services: &storage.EncryptionServices{ - Blob: &storage.EncryptionService{ - Enabled: utils.Bool(enableBlobEncryption), - }, - File: &storage.EncryptionService{ - Enabled: utils.Bool(enableFileEncryption), - }}, - KeySource: storage.KeySource(storageAccountEncryptionSource), - }, - EnableHTTPSTrafficOnly: &enableHTTPSTrafficOnly, - NetworkRuleSet: expandStorageAccountNetworkRules(d), - IsHnsEnabled: &isHnsEnabled, + setting := security.AdvancedThreatProtectionSetting{ + AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ + IsEnabled: utils.Bool(d.Get("enable").(bool)), }, } - if _, ok := d.GetOk("identity"); ok { - storageAccountIdentity := expandAzureRmStorageAccountIdentity(d) - parameters.Identity = storageAccountIdentity - } - - if _, ok := d.GetOk("custom_domain"); ok { - parameters.CustomDomain = expandStorageAccountCustomDomain(d) - } - - // BlobStorage does not support ZRS - if accountKind == string(storage.BlobStorage) { - if string(parameters.Sku.Name) == string(storage.StandardZRS) { - return fmt.Errorf("A `account_replication_type` of `ZRS` isn't supported for Blob Storage accounts.") - } - } - - // AccessTier is only valid for BlobStorage, StorageV2, and FileStorage accounts - if accountKind == string(storage.BlobStorage) || accountKind == string(storage.StorageV2) || accountKind == string(storage.FileStorage) { - accessTier, ok := d.GetOk("access_tier") - if !ok { - // default to "Hot" - accessTier = blobStorageAccountDefaultAccessTier - } - - parameters.AccountPropertiesCreateParameters.AccessTier = storage.AccessTier(accessTier.(string)) - } else { - if isHnsEnabled { - return fmt.Errorf("`is_hns_enabled` can only be used with account kinds `StorageV2` and `BlobStorage`") - } - } - - // AccountTier must be Premium for FileStorage - if accountKind == string(storage.FileStorage) { - if string(parameters.Sku.Tier) == string(storage.StandardLRS) { - return fmt.Errorf("A `account_tier` of `Standard` is not supported for FileStorage accounts.") - } - } - - // Create - future, err := client.Create(ctx, resourceGroupName, storageAccountName, parameters) - if err != nil { - return fmt.Errorf("Error creating Azure Storage Account %q: %+v", storageAccountName, err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("Error waiting for Azure Storage Account %q to be created: %+v", storageAccountName, err) - } - - account, err := client.GetProperties(ctx, resourceGroupName, storageAccountName, "") - if err != nil { - return fmt.Errorf("Error retrieving Azure Storage Account %q: %+v", storageAccountName, err) - } - - if account.ID == nil { - return fmt.Errorf("Cannot read Storage Account %q (resource group %q) ID", - storageAccountName, resourceGroupName) - } - log.Printf("[INFO] storage account %q ID: %q", storageAccountName, *account.ID) - d.SetId(*account.ID) - - // TODO: deprecate & split this out into it's own resource in 2.0 - // as this is not available in all regions, and presumably off by default - // lets only try to set this value when true - // TODO in 2.0 switch to guarding this with d.GetOkExists() ? - if v := d.Get("enable_advanced_threat_protection").(bool); v { - advancedThreatProtectionSetting := security.AdvancedThreatProtectionSetting{ - AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ - IsEnabled: utils.Bool(v), - }, - } - - if _, err = advancedThreatProtectionClient.Create(ctx, d.Id(), advancedThreatProtectionSetting); err != nil { - return fmt.Errorf("Error updating Azure Storage Account enable_advanced_threat_protection %q: %+v", storageAccountName, err) - } - } - - if val, ok := d.GetOk("queue_properties"); ok { - storageClient := meta.(*ArmClient).Storage - account, err := storageClient.FindAccount(ctx, storageAccountName) - if err != nil { - return fmt.Errorf("Error retrieving Account %q: %s", storageAccountName, err) - } - if account == nil { - return fmt.Errorf("Unable to locate Storage Account %q!", storageAccountName) - } - - queueClient, err := storageClient.QueuesClient(ctx, *account) - if err != nil { - return fmt.Errorf("Error building Queues Client: %s", err) - } - - queueProperties, err := expandQueueProperties(val.([]interface{})) - if err != nil { - return fmt.Errorf("Error expanding `queue_properties` for Azure Storage Account %q: %+v", storageAccountName, err) - } - - if _, err = queueClient.SetServiceProperties(ctx, storageAccountName, queueProperties); err != nil { - return fmt.Errorf("Error updating Azure Storage Account `queue_properties` %q: %+v", storageAccountName, err) - } - } - - return resourceArmAdvancedThreatProtectionRead(d, meta) -} - -// resourceArmStorageAccountUpdate is unusual in the ARM API where most resources have a combined -// and idempotent operation for CreateOrUpdate. In particular updating all of the parameters -// available requires a call to Update per parameter... -func resourceArmAdvancedThreatProtectionUpdate(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient).Storage.AccountsClient - advancedThreatProtectionClient := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient - ctx, cancel := timeouts.ForUpdate(meta.(*ArmClient).StopContext, d) - defer cancel() - - id, err := azure.ParseAzureResourceID(d.Id()) + resp, err := client.Create(ctx, resourceID, setting) if err != nil { - return err - } - storageAccountName := id.Path["storageAccounts"] - resourceGroupName := id.ResourceGroup - - accountTier := d.Get("account_tier").(string) - replicationType := d.Get("account_replication_type").(string) - storageType := fmt.Sprintf("%s_%s", accountTier, replicationType) - accountKind := d.Get("account_kind").(string) - - if accountKind == string(storage.BlobStorage) { - if storageType == string(storage.StandardZRS) { - return fmt.Errorf("A `account_replication_type` of `ZRS` isn't supported for Blob Storage accounts.") - } + return fmt.Errorf("Error updating Advanced Threat protection for resource %q: %+v", resourceID, err) } - d.Partial(true) - - if d.HasChange("enable_advanced_threat_protection") { - opts := security.AdvancedThreatProtectionSetting{ - AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ - IsEnabled: utils.Bool(d.Get("enable_advanced_threat_protection").(bool)), - }, - } - - if _, err := advancedThreatProtectionClient.Create(ctx, d.Id(), opts); err != nil { - return fmt.Errorf("Error updating Azure Storage Account enable_advanced_threat_protection %q: %+v", storageAccountName, err) - } - - d.SetPartial("enable_advanced_threat_protection") + if resp.ID == nil { + return fmt.Errorf("Cannot read ID for Advanced Threat Protection for resource %q ", resourceID) } + d.SetId(*resp.ID) - d.Partial(false) return resourceArmAdvancedThreatProtectionRead(d, meta) } func resourceArmAdvancedThreatProtectionRead(d *schema.ResourceData, meta interface{}) error { - client := meta.(*ArmClient).Storage.AccountsClient - advancedThreatProtectionClient := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient - endpointSuffix := meta.(*ArmClient).environment.StorageEndpointSuffix + client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) - if err != nil { - return err + id := d.Id() + parts := strings.Split(strings.Trim(id, "/"), "/providers/Microsoft.Security/advancedThreatProtectionSettings/") + if len(parts) != 2 { + return fmt.Errorf("Error determining target resource ID, resource ID in unexacpted format: %q", id) } - name := id.Path["storageAccounts"] - resGroup := id.ResourceGroup + resourceID := parts[0] - resp, err := client.GetProperties(ctx, resGroup, name, "") + atp, err := client.Get(ctx, resourceID) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - d.SetId("") - return nil - } - return fmt.Errorf("Error reading the state of AzureRM Storage Account %q: %+v", name, err) + return fmt.Errorf("Error reading Advanced Threat protection for resource %q: %+v", resourceID, err) } - // handle the user not having permissions to list the keys - d.Set("primary_connection_string", "") - d.Set("secondary_connection_string", "") - d.Set("primary_blob_connection_string", "") - d.Set("secondary_blob_connection_string", "") - d.Set("primary_access_key", "") - d.Set("secondary_access_key", "") - - keys, err := client.ListKeys(ctx, resGroup, name) - if err != nil { - // the API returns a 200 with an inner error of a 409.. - var hasWriteLock bool - var doesntHavePermissions bool - if e, ok := err.(azautorest.DetailedError); ok { - if status, ok := e.StatusCode.(int); ok { - hasWriteLock = status == http.StatusConflict - doesntHavePermissions = status == http.StatusUnauthorized - } - } - - if !hasWriteLock && !doesntHavePermissions { - return fmt.Errorf("Error listing Keys for Storage Account %q (Resource Group %q): %s", name, resGroup, err) - } - } - - d.Set("name", resp.Name) - d.Set("resource_group_name", resGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) + if atpp := atp.AdvancedThreatProtectionProperties; atpp != nil { + d.Set("enable", atpp.IsEnabled) } - d.Set("account_kind", resp.Kind) - - if sku := resp.Sku; sku != nil { - d.Set("account_type", sku.Name) - d.Set("account_tier", sku.Tier) - d.Set("account_replication_type", strings.Split(fmt.Sprintf("%v", sku.Name), "_")[1]) - } - - if props := resp.AccountProperties; props != nil { - d.Set("access_tier", props.AccessTier) - d.Set("enable_https_traffic_only", props.EnableHTTPSTrafficOnly) - d.Set("is_hns_enabled", props.IsHnsEnabled) - - if customDomain := props.CustomDomain; customDomain != nil { - if err := d.Set("custom_domain", flattenStorageAccountCustomDomain(customDomain)); err != nil { - return fmt.Errorf("Error setting `custom_domain`: %+v", err) - } - } - - if encryption := props.Encryption; encryption != nil { - if services := encryption.Services; services != nil { - if blob := services.Blob; blob != nil { - d.Set("enable_blob_encryption", blob.Enabled) - } - if file := services.File; file != nil { - d.Set("enable_file_encryption", file.Enabled) - } - } - d.Set("account_encryption_source", string(encryption.KeySource)) - } - - // Computed - d.Set("primary_location", props.PrimaryLocation) - d.Set("secondary_location", props.SecondaryLocation) - - if accessKeys := keys.Keys; accessKeys != nil { - storageAccountKeys := *accessKeys - if len(storageAccountKeys) > 0 { - pcs := fmt.Sprintf("DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=%s", *resp.Name, *storageAccountKeys[0].Value, endpointSuffix) - d.Set("primary_connection_string", pcs) - } - - if len(storageAccountKeys) > 1 { - scs := fmt.Sprintf("DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=%s", *resp.Name, *storageAccountKeys[1].Value, endpointSuffix) - d.Set("secondary_connection_string", scs) - } - } - if err := flattenAndSetAzureRmStorageAccountPrimaryEndpoints(d, props.PrimaryEndpoints); err != nil { - return fmt.Errorf("error setting primary endpoints and hosts for blob, queue, table and file: %+v", err) - } - - if accessKeys := keys.Keys; accessKeys != nil { - storageAccountKeys := *accessKeys - var primaryBlobConnectStr string - if v := props.PrimaryEndpoints; v != nil { - primaryBlobConnectStr = getBlobConnectionString(v.Blob, resp.Name, storageAccountKeys[0].Value) - } - d.Set("primary_blob_connection_string", primaryBlobConnectStr) - } - - if err := flattenAndSetAzureRmStorageAccountSecondaryEndpoints(d, props.SecondaryEndpoints); err != nil { - return fmt.Errorf("error setting secondary endpoints and hosts for blob, queue, table: %+v", err) - } - - if accessKeys := keys.Keys; accessKeys != nil { - storageAccountKeys := *accessKeys - var secondaryBlobConnectStr string - if v := props.SecondaryEndpoints; v != nil { - secondaryBlobConnectStr = getBlobConnectionString(v.Blob, resp.Name, storageAccountKeys[1].Value) - } - d.Set("secondary_blob_connection_string", secondaryBlobConnectStr) - } - - if networkRules := props.NetworkRuleSet; networkRules != nil { - if err := d.Set("network_rules", flattenStorageAccountNetworkRules(networkRules)); err != nil { - return fmt.Errorf("Error setting `network_rules`: %+v", err) - } - } - } - - if accessKeys := keys.Keys; accessKeys != nil { - storageAccountKeys := *accessKeys - d.Set("primary_access_key", storageAccountKeys[0].Value) - d.Set("secondary_access_key", storageAccountKeys[1].Value) - } - - identity := flattenAzureRmStorageAccountIdentity(resp.Identity) - if err := d.Set("identity", identity); err != nil { - return err - } - - // TODO in 2.0 switch to guarding this with d.GetOkExists() - atp, err := advancedThreatProtectionClient.Get(ctx, d.Id()) - if err != nil { - msg := err.Error() - if !strings.Contains(msg, "The resource namespace 'Microsoft.Security' is invalid.") { - if !strings.Contains(msg, "No registered resource provider found for location '") { - if !strings.Contains(msg, "' and API version '2017-08-01-preview' for type ") { - return fmt.Errorf("Error reading the advanced threat protection settings of AzureRM Storage Account %q: %+v", name, err) - } - } - } - } else { - if atpp := atp.AdvancedThreatProtectionProperties; atpp != nil { - d.Set("enable_advanced_threat_protection", atpp.IsEnabled) - } - } + return nil +} - storageClient := meta.(*ArmClient).Storage - account, err := storageClient.FindAccount(ctx, name) - if err != nil { - return fmt.Errorf("Error retrieving Account %q: %s", name, err) - } - if account == nil { - return fmt.Errorf("Unable to locate Storage Account %q!", name) - } +func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient + ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) + defer cancel() - queueClient, err := storageClient.QueuesClient(ctx, *account) - if err != nil { - return fmt.Errorf("Error building Queues Client: %s", err) + id := d.Id() + parts := strings.Split(strings.Trim(id, "/"), "/providers/Microsoft.Security/advancedThreatProtectionSettings/") + if len(parts) != 2 { + return fmt.Errorf("Error determining target resource ID, resource ID in unexacpted format: %q", id) } + resourceID := parts[0] - queueProps, err := queueClient.GetServiceProperties(ctx, name) - if err != nil { - if queueProps.Response.Response != nil && !utils.ResponseWasNotFound(queueProps.Response) { - return fmt.Errorf("Error reading queue properties for AzureRM Storage Account %q: %+v", name, err) - } + setting := security.AdvancedThreatProtectionSetting{ + AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ + IsEnabled: utils.Bool(false), + }, } - if err := d.Set("queue_properties", flattenQueueProperties(queueProps)); err != nil { - return fmt.Errorf("Error setting `queue_properties `for AzureRM Storage Account %q: %+v", name, err) + if _, err := client.Create(ctx, resourceID, setting); err != nil { + return fmt.Errorf("Error resetting Advanced Threat protection for resource %q: %+v", resourceID, err) } - return tags.FlattenAndSet(d, resp.Tags) -} + return nil +} \ No newline at end of file diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go new file mode 100644 index 000000000000..b96880a996bb --- /dev/null +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -0,0 +1,184 @@ +package azurerm + +import ( + "fmt" + "net/http" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" +) + +func TestAccAzureRMResourceGroup_basic(t *testing.T) { + resourceName := "azurerm_resource_group.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMResourceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMResourceGroup_basic(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMResourceGroupExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMResourceGroup_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_resource_group.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMResourceGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMResourceGroup_basic(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMResourceGroupExists(resourceName), + ), + }, + { + Config: testAccAzureRMResourceGroup_requiresImport(ri, testLocation()), + ExpectError: testRequiresImportError("azurerm_resource_group"), + }, + }, + }) +} + +func testCheckAzureRMResourceGroupExists(resourceName 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[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + resourceGroup := rs.Primary.Attributes["name"] + + // Ensure resource group exists in API + client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := client.Get(ctx, resourceGroup) + if err != nil { + return fmt.Errorf("Bad: Get on resourceGroupClient: %+v", err) + } + + if resp.StatusCode == http.StatusNotFound { + return fmt.Errorf("Bad: resource group: %q does not exist", resourceGroup) + } + + return nil + } +} + +func testCheckAzureRMResourceGroupDisappears(resourceName 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[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + resourceGroup := rs.Primary.Attributes["name"] + + // Ensure resource group exists in API + client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + deleteFuture, err := client.Delete(ctx, resourceGroup) + if err != nil { + return fmt.Errorf("Failed deleting Resource Group %q: %+v", resourceGroup, err) + } + + err = deleteFuture.WaitForCompletionRef(ctx, client.Client) + if err != nil { + return fmt.Errorf("Failed long polling for the deletion of Resource Group %q: %+v", resourceGroup, err) + } + + return nil + } +} + +func testCheckAzureRMResourceGroupDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_resource_group" { + continue + } + + resourceGroup := rs.Primary.ID + + resp, err := client.Get(ctx, resourceGroup) + if err != nil { + return nil + } + + if resp.StatusCode != http.StatusNotFound { + return fmt.Errorf("Resource Group still exists:\n%#v", resp.Properties) + } + } + + return nil +} + +func testAccAzureRMResourceGroup_basic(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_advanced_threat_protection" "test" { + resource_id = azurerm_resource_group.test.id + enable = true +} +`, rInt, location) +} + +func testAccAzureRMResourceGroup_storageAccount(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-ATP-%d" + location = "%s" +} + +resource "azurerm_storage_account" "testsa" { + name = "acctest%d" + resource_group_name = "${azurerm_resource_group.testrg.name}" + + location = "${azurerm_resource_group.testrg.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags = { + environment = "production" + } +} + +resource "azurerm_advanced_threat_protection" "test" { + resource_id = azurerm_resource_group.azurerm_storage_account.id + enable = true +} +`, rInt, location) +} From 119bcbdc8bc4640a95ea4245ec482f5a561b42e8 Mon Sep 17 00:00:00 2001 From: kt Date: Sat, 2 Nov 2019 08:44:33 -0700 Subject: [PATCH 04/19] advanced threat protection progress --- azurerm/resource_arm_advanced_threat_protection.go | 8 ++++---- azurerm/resource_arm_advanced_threat_protection_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 7c88c71d67fd..09b3828f548b 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -17,7 +17,7 @@ func resourceArmAdvancedThreatProtection() *schema.Resource { Create: resourceArmAdvancedThreatProtectionCreateUpdate, Read: resourceArmAdvancedThreatProtectionRead, Update: resourceArmAdvancedThreatProtectionCreateUpdate, - Delete: resourceArmAdvancedThreatProtectionDelete, + Delete: resourceArmAdvancedThreatProtectionDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, @@ -39,8 +39,8 @@ func resourceArmAdvancedThreatProtection() *schema.Resource { }, "enable": { - Type: schema.TypeBool, - Required: true, + Type: schema.TypeBool, + Required: true, }, }, } @@ -119,4 +119,4 @@ func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta inte } return nil -} \ No newline at end of file +} diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index b96880a996bb..150a5484fc7c 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -101,7 +101,7 @@ func testCheckAzureRMResourceGroupDisappears(resourceName string) resource.TestC resourceGroup := rs.Primary.Attributes["name"] // Ensure resource group exists in API - client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient + client := testAccProvider.Meta().(*ArmClient).Sto.GroupsClient ctx := testAccProvider.Meta().(*ArmClient).StopContext deleteFuture, err := client.Delete(ctx, resourceGroup) From f355d84087242a3d8f4ff8bc3a5bc9f46270277f Mon Sep 17 00:00:00 2001 From: kt Date: Sun, 3 Nov 2019 09:28:13 -0800 Subject: [PATCH 05/19] add cosmos test --- azurerm/helpers/azure/resourceid.go | 6 +- azurerm/provider.go | 1 + ...resource_arm_advanced_threat_protection.go | 75 +++++-- ...rce_arm_advanced_threat_protection_test.go | 196 ++++++++++++------ ...m_automation_dsc_nodeconfiguration_test.go | 2 +- azurerm/resource_arm_storage_account.go | 2 +- .../advanced_threat_protection.html.markdown | 88 ++++++++ 7 files changed, 279 insertions(+), 91 deletions(-) create mode 100644 website/docs/r/advanced_threat_protection.html.markdown diff --git a/azurerm/helpers/azure/resourceid.go b/azurerm/helpers/azure/resourceid.go index d426ceeda4c5..6336a261e7ba 100644 --- a/azurerm/helpers/azure/resourceid.go +++ b/azurerm/helpers/azure/resourceid.go @@ -6,7 +6,7 @@ import ( "strings" ) -// ResourceID represents a parsed long-form Azure Resource Manager ID +// TargetResourceID represents a parsed long-form Azure Resource Manager ID // with the Subscription ID, Resource Group and the Provider as top- // level fields, and other key-value pairs available via a map in the // Path field. @@ -18,7 +18,7 @@ type ResourceID struct { } // parseAzureResourceID converts a long-form Azure Resource Manager ID -// into a ResourceID. We make assumptions about the structure of URLs, +// into a TargetResourceID. We make assumptions about the structure of URLs, // which is obviously not good, but the best thing available given the // SDK. func ParseAzureResourceID(id string) (*ResourceID, error) { @@ -61,7 +61,7 @@ func ParseAzureResourceID(id string) (*ResourceID, error) { } } - // Build up a ResourceID from the map + // Build up a TargetResourceID from the map idObj := &ResourceID{} idObj.Path = componentMap diff --git a/azurerm/provider.go b/azurerm/provider.go index 4c401680c0fa..40f27e7b0ce9 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -153,6 +153,7 @@ func Provider() terraform.ResourceProvider { } resources := map[string]*schema.Resource{ + "azurerm_advanced_threat_protection": resourceArmAdvancedThreatProtection(), "azurerm_analysis_services_server": resourceArmAnalysisServicesServer(), "azurerm_api_management": resourceArmApiManagementService(), "azurerm_api_management_api": resourceArmApiManagementApi(), diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 09b3828f548b..3dcb61544f4a 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -2,6 +2,7 @@ package azurerm import ( "fmt" + "log" "strings" "time" @@ -24,21 +25,21 @@ func resourceArmAdvancedThreatProtection() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), + Create: schema.DefaultTimeout(30 * time.Minute), Read: schema.DefaultTimeout(5 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), }, Schema: map[string]*schema.Schema{ - "resource_id": { + "target_resource_id": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: azure.ValidateResourceID, }, - "enable": { + "enabled": { Type: schema.TypeBool, Required: true, }, @@ -46,16 +47,40 @@ func resourceArmAdvancedThreatProtection() *schema.Resource { } } +type AdvancedThreatProtectionResourceID struct { + Base azure.ResourceID + + TargetResourceID string +} + +func parseVirtualMachineScaleSetResourceID(input string) (*AdvancedThreatProtectionResourceID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Virtual Machine Scale Set ID %q: %+v", input, err) + } + + parts := strings.Split(input, "/providers/Microsoft.Security/advancedThreatProtectionSettings/") + if len(parts) != 2 { + return nil, fmt.Errorf("Error determining target resource ID, resource ID in unexacpted format: %q", id) + } + + return &AdvancedThreatProtectionResourceID{ + Base: *id, + TargetResourceID: parts[0], + }, nil + +} + func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) defer cancel() - resourceID := d.Get("resource_id").(string) + resourceID := d.Get("target_resource_id").(string) setting := security.AdvancedThreatProtectionSetting{ AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ - IsEnabled: utils.Bool(d.Get("enable").(bool)), + IsEnabled: utils.Bool(d.Get("enabled").(bool)), }, } @@ -77,20 +102,25 @@ func resourceArmAdvancedThreatProtectionRead(d *schema.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) defer cancel() - id := d.Id() - parts := strings.Split(strings.Trim(id, "/"), "/providers/Microsoft.Security/advancedThreatProtectionSettings/") - if len(parts) != 2 { - return fmt.Errorf("Error determining target resource ID, resource ID in unexacpted format: %q", id) + id, err := parseVirtualMachineScaleSetResourceID(d.Id()) + if err != nil { + return err } - resourceID := parts[0] - atp, err := client.Get(ctx, resourceID) + resp, err := client.Get(ctx, id.TargetResourceID) if err != nil { - return fmt.Errorf("Error reading Advanced Threat protection for resource %q: %+v", resourceID, err) + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("Advanced Threat Protection was not found for resource %q: %+v", id.TargetResourceID, err) + d.SetId("") + return nil + } + + return fmt.Errorf("Error reading Advanced Threat protection for resource %q: %+v", id.TargetResourceID, err) } - if atpp := atp.AdvancedThreatProtectionProperties; atpp != nil { - d.Set("enable", atpp.IsEnabled) + d.Set("target_resource_id", id.TargetResourceID) + if atpp := resp.AdvancedThreatProtectionProperties; atpp != nil { + d.Set("enabled", resp.IsEnabled) } return nil @@ -101,21 +131,20 @@ func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta inte ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) defer cancel() - id := d.Id() - parts := strings.Split(strings.Trim(id, "/"), "/providers/Microsoft.Security/advancedThreatProtectionSettings/") - if len(parts) != 2 { - return fmt.Errorf("Error determining target resource ID, resource ID in unexacpted format: %q", id) + id, err := parseVirtualMachineScaleSetResourceID(d.Id()) + if err != nil { + return err } - resourceID := parts[0] + // there is no delete.. so lets just do best effort and set it to false? setting := security.AdvancedThreatProtectionSetting{ AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ IsEnabled: utils.Bool(false), }, } - if _, err := client.Create(ctx, resourceID, setting); err != nil { - return fmt.Errorf("Error resetting Advanced Threat protection for resource %q: %+v", resourceID, err) + if _, err := client.Create(ctx, id.TargetResourceID, setting); err != nil { + return fmt.Errorf("Error resetting Advanced Threat protection for resource %q: %+v", id.TargetResourceID, err) } return nil diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index 150a5484fc7c..d29b6f0bb3f3 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -5,65 +5,96 @@ import ( "net/http" "testing" + "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2015-04-08/documentdb" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" ) -func TestAccAzureRMResourceGroup_basic(t *testing.T) { - resourceName := "azurerm_resource_group.test" +func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { + rn := "azurerm_advanced_threat_protection.test" ri := tf.AccRandTimeInt() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testCheckAzureRMResourceGroupDestroy, + CheckDestroy: testCheckAzureRMAdvancedThreatProtectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMResourceGroup_basic(ri, testLocation()), + Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), true, true), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMResourceGroupExists(resourceName), + resource.TestCheckResourceAttr(rn, "enabled", "true"), ), }, { - ResourceName: resourceName, + ResourceName: rn, ImportState: true, ImportStateVerify: true, }, + { + Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), true, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(rn, "enabled", "false"), + ), + }, + { + ResourceName: rn, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), false, false), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionIsFalse(rn), + ), + }, }, }) } -func TestAccAzureRMResourceGroup_requiresImport(t *testing.T) { - if !features.ShouldResourcesBeImported() { - t.Skip("Skipping since resources aren't required to be imported") - return - } - - resourceName := "azurerm_resource_group.test" +func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { + rn := "azurerm_advanced_threat_protection.test" ri := tf.AccRandTimeInt() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testCheckAzureRMResourceGroupDestroy, + CheckDestroy: testCheckAzureRMAdvancedThreatProtectionDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMResourceGroup_basic(ri, testLocation()), + Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), true, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(rn, "enabled", "true"), + ), + }, + { + ResourceName: rn, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), true, false), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMResourceGroupExists(resourceName), + resource.TestCheckResourceAttr(rn, "enabled", "false"), ), }, { - Config: testAccAzureRMResourceGroup_requiresImport(ri, testLocation()), - ExpectError: testRequiresImportError("azurerm_resource_group"), + ResourceName: rn, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), false, false), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionIsFalse(rn), + ), }, }, }) } -func testCheckAzureRMResourceGroupExists(resourceName string) resource.TestCheckFunc { +/* +func testCheckAzureRMAdvancedThreatProtectionExists(resourceName 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[resourceName] @@ -71,103 +102,108 @@ func testCheckAzureRMResourceGroupExists(resourceName string) resource.TestCheck return fmt.Errorf("Not found: %s", resourceName) } - resourceGroup := rs.Primary.Attributes["name"] + AdvancedThreatProtection := rs.Primary.Attributes["name"] // Ensure resource group exists in API client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient ctx := testAccProvider.Meta().(*ArmClient).StopContext - resp, err := client.Get(ctx, resourceGroup) + resp, err := client.Get(ctx, AdvancedThreatProtection) if err != nil { - return fmt.Errorf("Bad: Get on resourceGroupClient: %+v", err) + return fmt.Errorf("Bad: Get on AdvancedThreatProtectionClient: %+v", err) } if resp.StatusCode == http.StatusNotFound { - return fmt.Errorf("Bad: resource group: %q does not exist", resourceGroup) + return fmt.Errorf("Bad: resource group: %q does not exist", AdvancedThreatProtection) } return nil } } - -func testCheckAzureRMResourceGroupDisappears(resourceName string) resource.TestCheckFunc { +*/ +func testCheckAzureRMAdvancedThreatProtectionIsFalse(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { + // Ensure resource group exists in API + client := testAccProvider.Meta().(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[resourceName] if !ok { return fmt.Errorf("Not found: %s", resourceName) } - resourceGroup := rs.Primary.Attributes["name"] - - // Ensure resource group exists in API - client := testAccProvider.Meta().(*ArmClient).Sto.GroupsClient - ctx := testAccProvider.Meta().(*ArmClient).StopContext - - deleteFuture, err := client.Delete(ctx, resourceGroup) + id, err := parseVirtualMachineScaleSetResourceID(rs.Primary.ID) if err != nil { - return fmt.Errorf("Failed deleting Resource Group %q: %+v", resourceGroup, err) + return err } - err = deleteFuture.WaitForCompletionRef(ctx, client.Client) + resp, err := client.Get(ctx, id.TargetResourceID) if err != nil { - return fmt.Errorf("Failed long polling for the deletion of Resource Group %q: %+v", resourceGroup, err) + return fmt.Errorf("Failed reading Advanced Threat Protection for resource %q: %+v", id.TargetResourceID, err) + } + + if props := resp.AdvancedThreatProtectionProperties; props != nil { + if props.IsEnabled != nil { + if *props.IsEnabled { + return fmt.Errorf("Advanced Threat Protection is still true for resource %q: %+v", id.TargetResourceID, err) + } + } } return nil } } -func testCheckAzureRMResourceGroupDestroy(s *terraform.State) error { - client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient +func testCheckAzureRMAdvancedThreatProtectionDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx := testAccProvider.Meta().(*ArmClient).StopContext for _, rs := range s.RootModule().Resources { - if rs.Type != "azurerm_resource_group" { + if rs.Type != "azurerm_advanced_threat_protection" { continue } - resourceGroup := rs.Primary.ID + id, err := parseVirtualMachineScaleSetResourceID(rs.Primary.ID) + if err != nil { + return err + } - resp, err := client.Get(ctx, resourceGroup) + resp, err := client.Get(ctx, id.TargetResourceID) if err != nil { return nil } if resp.StatusCode != http.StatusNotFound { - return fmt.Errorf("Resource Group still exists:\n%#v", resp.Properties) + return fmt.Errorf("Advanced Threat Protection still exists:\n%#v", resp.ID) } } return nil } -func testAccAzureRMResourceGroup_basic(rInt int, location string) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - +func testAccAzureRMAdvancedThreatProtection_storageAccount(rInt int, location string, hasResource, enabled bool) string { + atp := "" + if hasResource { + atp = fmt.Sprintf(` resource "azurerm_advanced_threat_protection" "test" { - resource_id = azurerm_resource_group.test.id - enable = true -} -`, rInt, location) + target_resource_id = "${azurerm_storage_account.test.id}" + enabled = %t } +`, enabled) + } -func testAccAzureRMResourceGroup_storageAccount(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { - name = "acctestRG-ATP-%d" - location = "%s" + name = "acctestRG-ATP-%[1]d" + location = "%[2]s" } -resource "azurerm_storage_account" "testsa" { - name = "acctest%d" - resource_group_name = "${azurerm_resource_group.testrg.name}" +resource "azurerm_storage_account" "test" { + name = "acctest%[3]d" + resource_group_name = "${azurerm_resource_group.test.name}" - location = "${azurerm_resource_group.testrg.location}" + location = "${azurerm_resource_group.test.location}" account_tier = "Standard" account_replication_type = "LRS" @@ -176,9 +212,43 @@ resource "azurerm_storage_account" "testsa" { } } +%[4]s +`, rInt, location, rInt/10, atp) +} + +func testAccAzureRMAdvancedThreatProtection_cosmosAccount(rInt int, location string, hasResource, enabled bool) string { + atp := "" + if hasResource { + atp = fmt.Sprintf(` resource "azurerm_advanced_threat_protection" "test" { - resource_id = azurerm_resource_group.azurerm_storage_account.id - enable = true + target_resource_id = "${azurerm_cosmosdb_account.test.id}" + enabled = %t +} +`, enabled) + } + + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-ATP-%[1]d" + location = "%[2]s" } -`, rInt, location) + +resource "azurerm_cosmosdb_account" "test" { + name = "acctest-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + offer_type = "Standard" + + consistency_policy { + consistency_level = "%[3]s" + } + + geo_location { + location = "${azurerm_resource_group.test.location}" + failover_priority = 0 + } +} + +%[4]s +`, rInt, location, string(documentdb.Eventual), atp) } diff --git a/azurerm/resource_arm_automation_dsc_nodeconfiguration_test.go b/azurerm/resource_arm_automation_dsc_nodeconfiguration_test.go index 9546b9145fdb..d2d45129958c 100644 --- a/azurerm/resource_arm_automation_dsc_nodeconfiguration_test.go +++ b/azurerm/resource_arm_automation_dsc_nodeconfiguration_test.go @@ -167,7 +167,7 @@ resource "azurerm_automation_dsc_nodeconfiguration" "test" { content_embedded = < Date: Sun, 3 Nov 2019 13:12:30 -0800 Subject: [PATCH 06/19] commit --- azurerm/resource_arm_advanced_threat_protection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index d29b6f0bb3f3..b8525198d0e5 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -83,12 +83,12 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - { + /*{ Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), false, false), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAdvancedThreatProtectionIsFalse(rn), ), - }, + },*/ }, }) } From 4e8b3baa2ecec2d8f921ffaba045479d69afb450 Mon Sep 17 00:00:00 2001 From: kt Date: Sat, 9 Nov 2019 18:41:43 -0800 Subject: [PATCH 07/19] update docs & tests --- ...resource_arm_advanced_threat_protection.go | 10 +-- ...rce_arm_advanced_threat_protection_test.go | 59 ++++++++------- azurerm/resource_arm_storage_account.go | 3 +- .../advanced_threat_protection.html.markdown | 73 ++++++------------- 4 files changed, 62 insertions(+), 83 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 3dcb61544f4a..589fa0f29520 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -53,10 +53,10 @@ type AdvancedThreatProtectionResourceID struct { TargetResourceID string } -func parseVirtualMachineScaleSetResourceID(input string) (*AdvancedThreatProtectionResourceID, error) { +func parseAdvancedThreatProtectionID(input string) (*AdvancedThreatProtectionResourceID, error) { id, err := azure.ParseAzureResourceID(input) if err != nil { - return nil, fmt.Errorf("[ERROR] Unable to parse Virtual Machine Scale Set ID %q: %+v", input, err) + return nil, fmt.Errorf("[ERROR] Unable to parse Advanced Threat Protection Set ID %q: %+v", input, err) } parts := strings.Split(input, "/providers/Microsoft.Security/advancedThreatProtectionSettings/") @@ -102,7 +102,7 @@ func resourceArmAdvancedThreatProtectionRead(d *schema.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) defer cancel() - id, err := parseVirtualMachineScaleSetResourceID(d.Id()) + id, err := parseAdvancedThreatProtectionID(d.Id()) if err != nil { return err } @@ -131,7 +131,7 @@ func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta inte ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) defer cancel() - id, err := parseVirtualMachineScaleSetResourceID(d.Id()) + id, err := parseAdvancedThreatProtectionID(d.Id()) if err != nil { return err } @@ -144,7 +144,7 @@ func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta inte } if _, err := client.Create(ctx, id.TargetResourceID, setting); err != nil { - return fmt.Errorf("Error resetting Advanced Threat protection for resource %q: %+v", id.TargetResourceID, err) + return fmt.Errorf("Error resetting Advanced Threat protection to false for resource %q: %+v", id.TargetResourceID, err) } return nil diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index b8525198d0e5..1c4463258da5 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -14,6 +14,7 @@ import ( func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { rn := "azurerm_advanced_threat_protection.test" ri := tf.AccRandTimeInt() + var id AdvancedThreatProtectionResourceID resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -23,6 +24,7 @@ func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { { Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), true, true), Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), resource.TestCheckResourceAttr(rn, "enabled", "true"), ), }, @@ -34,6 +36,7 @@ func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { { Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), true, false), Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), resource.TestCheckResourceAttr(rn, "enabled", "false"), ), }, @@ -45,7 +48,7 @@ func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { { Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), false, false), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMAdvancedThreatProtectionIsFalse(rn), + testCheckAzureRMAdvancedThreatProtectionIsFalse(&id), ), }, }, @@ -55,6 +58,12 @@ func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { rn := "azurerm_advanced_threat_protection.test" ri := tf.AccRandTimeInt() + var id AdvancedThreatProtectionResourceID + + // the API errors on deleting the cosmos DB account some of the time so lets skip this test for now + // remove once this is fixed: https://github.com/Azure/azure-sdk-for-go/issues/6310 + // run it multiple times in a row as it only fails 50% of the time + t.Skip() resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -64,6 +73,7 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { { Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), true, true), Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), resource.TestCheckResourceAttr(rn, "enabled", "true"), ), }, @@ -75,6 +85,7 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { { Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), true, false), Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), resource.TestCheckResourceAttr(rn, "enabled", "false"), ), }, @@ -83,61 +94,53 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - /*{ + { Config: testAccAzureRMAdvancedThreatProtection_cosmosAccount(ri, testLocation(), false, false), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMAdvancedThreatProtectionIsFalse(rn), + testCheckAzureRMAdvancedThreatProtectionIsFalse(&id), ), - },*/ + }, }, }) } -/* -func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string) resource.TestCheckFunc { +func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string, idToReturn *AdvancedThreatProtectionResourceID) resource.TestCheckFunc { return func(s *terraform.State) error { + // Ensure resource group exists in API + client := testAccProvider.Meta().(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + // Ensure we have enough information in state to look up in API rs, ok := s.RootModule().Resources[resourceName] if !ok { return fmt.Errorf("Not found: %s", resourceName) } - AdvancedThreatProtection := rs.Primary.Attributes["name"] - - // Ensure resource group exists in API - client := testAccProvider.Meta().(*ArmClient).Resource.GroupsClient - ctx := testAccProvider.Meta().(*ArmClient).StopContext + id, err := parseAdvancedThreatProtectionID(rs.Primary.ID) + if err != nil { + return err + } - resp, err := client.Get(ctx, AdvancedThreatProtection) + resp, err := client.Get(ctx, id.TargetResourceID) if err != nil { return fmt.Errorf("Bad: Get on AdvancedThreatProtectionClient: %+v", err) } if resp.StatusCode == http.StatusNotFound { - return fmt.Errorf("Bad: resource group: %q does not exist", AdvancedThreatProtection) + return fmt.Errorf("Advanced Threat Protection for resource %q not found", id.TargetResourceID) } + *idToReturn = *id + return nil } } -*/ -func testCheckAzureRMAdvancedThreatProtectionIsFalse(resourceName string) resource.TestCheckFunc { + +func testCheckAzureRMAdvancedThreatProtectionIsFalse(id *AdvancedThreatProtectionResourceID) resource.TestCheckFunc { return func(s *terraform.State) error { - // Ensure resource group exists in API client := testAccProvider.Meta().(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx := testAccProvider.Meta().(*ArmClient).StopContext - // Ensure we have enough information in state to look up in API - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return fmt.Errorf("Not found: %s", resourceName) - } - - id, err := parseVirtualMachineScaleSetResourceID(rs.Primary.ID) - if err != nil { - return err - } - resp, err := client.Get(ctx, id.TargetResourceID) if err != nil { return fmt.Errorf("Failed reading Advanced Threat Protection for resource %q: %+v", id.TargetResourceID, err) @@ -164,7 +167,7 @@ func testCheckAzureRMAdvancedThreatProtectionDestroy(s *terraform.State) error { continue } - id, err := parseVirtualMachineScaleSetResourceID(rs.Primary.ID) + id, err := parseAdvancedThreatProtectionID(rs.Primary.ID) if err != nil { return err } diff --git a/azurerm/resource_arm_storage_account.go b/azurerm/resource_arm_storage_account.go index 3887ce0e2176..bba4c3b8cc0a 100644 --- a/azurerm/resource_arm_storage_account.go +++ b/azurerm/resource_arm_storage_account.go @@ -174,10 +174,11 @@ func resourceArmStorageAccount() *schema.Resource { ForceNew: true, }, + // TODO remove this in 2.0 for the dedicated resource "enable_advanced_threat_protection": { Type: schema.TypeBool, Optional: true, - Default: false, // TODO remove this in 2.0 so we can use GetOkExists to guard the ATP client use + Computed: true, }, "network_rules": { diff --git a/website/docs/r/advanced_threat_protection.html.markdown b/website/docs/r/advanced_threat_protection.html.markdown index a7802eb74479..2448eaa15d0f 100644 --- a/website/docs/r/advanced_threat_protection.html.markdown +++ b/website/docs/r/advanced_threat_protection.html.markdown @@ -1,88 +1,63 @@ --- layout: "azurerm" -page_title: "Azure Resource Manager: azurerm_analysis_services_server" -sidebar_current: "docs-azurerm-resource-analysis_services_server-x" +page_title: "Azure Resource Manager: azurerm_advanced_threat_protection" +sidebar_current: "docs-azurerm-resource-azurerm-advanced-threat-protection-x" description: |- - Manages an Analysis Services Server. + Manages a resources Advanced Threat Protection setting. --- -# azurerm_analysis_services_server +# azurerm_advanced_threat_protection -Manages an Analysis Services Server. +Manages a resources Advanced Threat Protection setting.. ## Example Usage ```hcl resource "azurerm_resource_group" "rg" { - name = "analysis-services-server-test" + name = "atp-example" location = "northeurope" } -resource "azurerm_analysis_services_server" "server" { - name = "analysisservicesserver" - location = "northeurope" - resource_group_name = "${azurerm_resource_group.rg.name}" - sku = "S0" - admin_users = ["myuser@domain.tld"] - enable_power_bi_service = true - - ipv4_firewall_rule { - name = "myRule1" - range_start = "210.117.252.0" - range_end = "210.117.252.255" - } +resource "azurerm_storage_account" "example" { + name = "examplestorage" + resource_group_name = "${azurerm_resource_group.example.name}" + + location = "${azurerm_resource_group.example.location}" + account_tier = "Standard" + account_replication_type = "LRS" tags = { - abc = 123 + environment = "example" } } + +resource "azurerm_advanced_threat_protection" "example" { + target_resource_id = "${azurerm_storage_account.example.id}" + enabled = true +} + ``` ## Argument Reference The following arguments are supported: -* `name` - (Required) The name of the Analysis Services Server. Changing this forces a new resource to be created. - -* `location` - (Required) The Azure location where the Analysis Services Server exists. Changing this forces a new resource to be created. - -* `resource_group_name` - (Required) The name of the Resource Group in which the Analysis Services Server should be exist. Changing this forces a new resource to be created. - -* `sku` - (Required) SKU for the Analysis Services Server. Possible values are: `D1`, `B1`, `B2`, `S0`, `S1`, `S2`, `S4`, `S8` and `S9` - -* `admin_users` - (Optional) List of email addresses of admin users. - -* `querypool_connection_mode` - (Optional) Controls how the read-write server is used in the query pool. If this values is set to `All` then read-write servers are also used for queries. Otherwise with `ReadOnly` these servers do not participate in query operations. - -* `backup_blob_container_uri` - (Optional) URI and SAS token for a blob container to store backups. - -* `enable_power_bi_service` - (Optional) Indicates if the Power BI service is allowed to access or not. - -* `ipv4_firewall_rule` - (Optional) One or more `ipv4_firewall_rule` block(s) as defined below. - ---- - -A `ipv4_firewall_rule` block supports the following: - -* `name` - (Required) Specifies the name of the firewall rule. - -* `range_start` - (Required) Start of the firewall rule range as IPv4 address. +* `target_resource_id` - (Required) The azure resource ID of the resource to enable the setting on. Changing this forces a new resource to be created. -* `range_end` - (Required) End of the firewall rule range as IPv4 address. +* `enabled` - (Required) Whether to enable or disable Advanced Threat Protection on this resource. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `id` - The ID of the Analysis Services Server. +* `id` - The ID of the Advanced Threat Protection resource. -* `server_full_name` - The full name of the Analysis Services Server. ## Import Analysis Services Server can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_analysis_services_server.server /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resourcegroup1/providers/Microsoft.AnalysisServices/servers/server1 +terraform import azurerm_advanced_threat_protection.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/exampleResourceGroup/providers/Microsoft.Storage/storageAccounts/exampleaccount/providers/Microsoft.Security/advancedThreatProtectionSettings/default ``` From cc380f52ed4b49dbd52b416ff8ceedbda74516ec Mon Sep 17 00:00:00 2001 From: kt Date: Sat, 9 Nov 2019 21:03:38 -0800 Subject: [PATCH 08/19] fix linting errors --- azurerm/resource_arm_advanced_threat_protection.go | 1 - website/docs/r/advanced_threat_protection.html.markdown | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 589fa0f29520..d7d49437d6e1 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -68,7 +68,6 @@ func parseAdvancedThreatProtectionID(input string) (*AdvancedThreatProtectionRes Base: *id, TargetResourceID: parts[0], }, nil - } func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { diff --git a/website/docs/r/advanced_threat_protection.html.markdown b/website/docs/r/advanced_threat_protection.html.markdown index 2448eaa15d0f..efc746b15015 100644 --- a/website/docs/r/advanced_threat_protection.html.markdown +++ b/website/docs/r/advanced_threat_protection.html.markdown @@ -1,4 +1,5 @@ --- +subcategory: "Security Center" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_advanced_threat_protection" sidebar_current: "docs-azurerm-resource-azurerm-advanced-threat-protection-x" From de2a5dd43a217ecefc90a70942ebf22a2e042e71 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 21:53:13 -0800 Subject: [PATCH 09/19] Apply suggestions from code review Co-Authored-By: Tom Harvey --- azurerm/resource_arm_advanced_threat_protection.go | 6 +++--- azurerm/resource_arm_advanced_threat_protection_test.go | 2 +- website/docs/r/advanced_threat_protection.html.markdown | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index d7d49437d6e1..8d6cbe0c6f47 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -61,7 +61,7 @@ func parseAdvancedThreatProtectionID(input string) (*AdvancedThreatProtectionRes parts := strings.Split(input, "/providers/Microsoft.Security/advancedThreatProtectionSettings/") if len(parts) != 2 { - return nil, fmt.Errorf("Error determining target resource ID, resource ID in unexacpted format: %q", id) + return nil, fmt.Errorf("Error determining target resource ID, resource ID in unexpected format: %q", id) } return &AdvancedThreatProtectionResourceID{ @@ -72,7 +72,7 @@ func parseAdvancedThreatProtectionID(input string) (*AdvancedThreatProtectionRes func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient - ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) + ctx, cancel := timeouts.ForCreateUpdate(meta.(*ArmClient).StopContext, d) defer cancel() resourceID := d.Get("target_resource_id").(string) @@ -127,7 +127,7 @@ func resourceArmAdvancedThreatProtectionRead(d *schema.ResourceData, meta interf func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient - ctx, cancel := timeouts.ForCreate(meta.(*ArmClient).StopContext, d) + ctx, cancel := timeouts.ForDelete(meta.(*ArmClient).StopContext, d) defer cancel() id, err := parseAdvancedThreatProtectionID(d.Id()) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index 1c4463258da5..3d4be11308b8 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -61,7 +61,7 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { var id AdvancedThreatProtectionResourceID // the API errors on deleting the cosmos DB account some of the time so lets skip this test for now - // remove once this is fixed: https://github.com/Azure/azure-sdk-for-go/issues/6310 + // TODO: remove once this is fixed: https://github.com/Azure/azure-sdk-for-go/issues/6310 // run it multiple times in a row as it only fails 50% of the time t.Skip() diff --git a/website/docs/r/advanced_threat_protection.html.markdown b/website/docs/r/advanced_threat_protection.html.markdown index efc746b15015..bffe200f2565 100644 --- a/website/docs/r/advanced_threat_protection.html.markdown +++ b/website/docs/r/advanced_threat_protection.html.markdown @@ -9,7 +9,7 @@ description: |- # azurerm_advanced_threat_protection -Manages a resources Advanced Threat Protection setting.. +Manages a resources Advanced Threat Protection setting. ## Example Usage @@ -43,9 +43,9 @@ resource "azurerm_advanced_threat_protection" "example" { The following arguments are supported: -* `target_resource_id` - (Required) The azure resource ID of the resource to enable the setting on. Changing this forces a new resource to be created. +* `target_resource_id` - (Required) The ID of the Azure Resource which to enable Advanced Threat Protection on. Changing this forces a new resource to be created. -* `enabled` - (Required) Whether to enable or disable Advanced Threat Protection on this resource. +* `enabled` - (Required) Should Advanced Threat Protection be enabled on this resource? ## Attributes Reference @@ -57,7 +57,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -Analysis Services Server can be imported using the `resource id`, e.g. +Advanced Threat Protection can be imported using the `resource id`, e.g. ```shell terraform import azurerm_advanced_threat_protection.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/exampleResourceGroup/providers/Microsoft.Storage/storageAccounts/exampleaccount/providers/Microsoft.Security/advancedThreatProtectionSettings/default From c570b2b47f14c4deeac171dbc94ad3345da96314 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 22:44:41 -0800 Subject: [PATCH 10/19] Apply suggestions from code review Co-Authored-By: Tom Harvey --- azurerm/helpers/azure/resourceid.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/helpers/azure/resourceid.go b/azurerm/helpers/azure/resourceid.go index 6336a261e7ba..7744ce163d5b 100644 --- a/azurerm/helpers/azure/resourceid.go +++ b/azurerm/helpers/azure/resourceid.go @@ -18,7 +18,7 @@ type ResourceID struct { } // parseAzureResourceID converts a long-form Azure Resource Manager ID -// into a TargetResourceID. We make assumptions about the structure of URLs, +// into a ResourceID. We make assumptions about the structure of URLs, // which is obviously not good, but the best thing available given the // SDK. func ParseAzureResourceID(id string) (*ResourceID, error) { From ece0f4f37cf954f042970eb353d20b31e2494b6d Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 22:47:08 -0800 Subject: [PATCH 11/19] Update azurerm/helpers/azure/resourceid.go Co-Authored-By: Tom Harvey --- azurerm/helpers/azure/resourceid.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/helpers/azure/resourceid.go b/azurerm/helpers/azure/resourceid.go index 7744ce163d5b..2ea9dbb490ce 100644 --- a/azurerm/helpers/azure/resourceid.go +++ b/azurerm/helpers/azure/resourceid.go @@ -6,7 +6,7 @@ import ( "strings" ) -// TargetResourceID represents a parsed long-form Azure Resource Manager ID +// ResourceID represents a parsed long-form Azure Resource Manager ID // with the Subscription ID, Resource Group and the Provider as top- // level fields, and other key-value pairs available via a map in the // Path field. From c37cb9f942c43e9b36f05af91d1ddac2c01d662e Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:06:04 -0800 Subject: [PATCH 12/19] address PR comments --- .../advanced_threat_protection.go | 31 +++++++++++++ ...resource_arm_advanced_threat_protection.go | 44 ++++++++----------- ...rce_arm_advanced_threat_protection_test.go | 13 +++--- azurerm/resource_arm_storage_account.go | 7 +-- .../guides/2.0-upgrade-guide.html.markdown | 2 + 5 files changed, 62 insertions(+), 35 deletions(-) create mode 100644 azurerm/internal/services/securitycenter/advanced_threat_protection.go diff --git a/azurerm/internal/services/securitycenter/advanced_threat_protection.go b/azurerm/internal/services/securitycenter/advanced_threat_protection.go new file mode 100644 index 000000000000..db74276b2c46 --- /dev/null +++ b/azurerm/internal/services/securitycenter/advanced_threat_protection.go @@ -0,0 +1,31 @@ +package securitycenter + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type AdvancedThreatProtectionResourceID struct { + Base azure.ResourceID + + TargetResourceID string +} + +func ParseAdvancedThreatProtectionID(input string) (*AdvancedThreatProtectionResourceID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Advanced Threat Protection Set ID %q: %+v", input, err) + } + + parts := strings.Split(input, "/providers/Microsoft.Security/advancedThreatProtectionSettings/") + if len(parts) != 2 { + return nil, fmt.Errorf("Error determining target resource ID, resource ID in unexpected format: %q", id) + } + + return &AdvancedThreatProtectionResourceID{ + Base: *id, + TargetResourceID: parts[0], + }, nil +} diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 8d6cbe0c6f47..6fcef3861fb6 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -3,12 +3,14 @@ package azurerm import ( "fmt" "log" - "strings" "time" "github.com/Azure/azure-sdk-for-go/services/preview/security/mgmt/v1.0/security" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/securitycenter" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -47,29 +49,6 @@ func resourceArmAdvancedThreatProtection() *schema.Resource { } } -type AdvancedThreatProtectionResourceID struct { - Base azure.ResourceID - - TargetResourceID string -} - -func parseAdvancedThreatProtectionID(input string) (*AdvancedThreatProtectionResourceID, error) { - id, err := azure.ParseAzureResourceID(input) - if err != nil { - return nil, fmt.Errorf("[ERROR] Unable to parse Advanced Threat Protection Set ID %q: %+v", input, err) - } - - parts := strings.Split(input, "/providers/Microsoft.Security/advancedThreatProtectionSettings/") - if len(parts) != 2 { - return nil, fmt.Errorf("Error determining target resource ID, resource ID in unexpected format: %q", id) - } - - return &AdvancedThreatProtectionResourceID{ - Base: *id, - TargetResourceID: parts[0], - }, nil -} - func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*ArmClient).StopContext, d) @@ -77,6 +56,19 @@ func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, met resourceID := d.Get("target_resource_id").(string) + if features.ShouldResourcesBeImported() && d.IsNewResource() { + server, err := client.Get(ctx, "target_resource_id") + if err != nil { + if !utils.ResponseWasNotFound(server.Response) { + return fmt.Errorf("Error checking for presence of existing Advanced Threat Protection for resource %q: %+v", resourceID, err) + } + } + + if server.ID != nil && *server.ID != "" { + return tf.ImportAsExistsError("azurerm_advanced_threat_protection", *server.ID) + } + } + setting := security.AdvancedThreatProtectionSetting{ AdvancedThreatProtectionProperties: &security.AdvancedThreatProtectionProperties{ IsEnabled: utils.Bool(d.Get("enabled").(bool)), @@ -101,7 +93,7 @@ func resourceArmAdvancedThreatProtectionRead(d *schema.ResourceData, meta interf ctx, cancel := timeouts.ForRead(meta.(*ArmClient).StopContext, d) defer cancel() - id, err := parseAdvancedThreatProtectionID(d.Id()) + id, err := securitycenter.ParseAdvancedThreatProtectionID(d.Id()) if err != nil { return err } @@ -130,7 +122,7 @@ func resourceArmAdvancedThreatProtectionDelete(d *schema.ResourceData, meta inte ctx, cancel := timeouts.ForDelete(meta.(*ArmClient).StopContext, d) defer cancel() - id, err := parseAdvancedThreatProtectionID(d.Id()) + id, err := securitycenter.ParseAdvancedThreatProtectionID(d.Id()) if err != nil { return err } diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index 3d4be11308b8..ddbffffe7ae8 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -9,12 +9,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/securitycenter" ) func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { rn := "azurerm_advanced_threat_protection.test" ri := tf.AccRandTimeInt() - var id AdvancedThreatProtectionResourceID + var id securitycenter.AdvancedThreatProtectionResourceID resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -58,7 +59,7 @@ func TestAccAzureRMAdvancedThreatProtection_storageAccount(t *testing.T) { func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { rn := "azurerm_advanced_threat_protection.test" ri := tf.AccRandTimeInt() - var id AdvancedThreatProtectionResourceID + var id securitycenter.AdvancedThreatProtectionResourceID // the API errors on deleting the cosmos DB account some of the time so lets skip this test for now // TODO: remove once this is fixed: https://github.com/Azure/azure-sdk-for-go/issues/6310 @@ -104,7 +105,7 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { }) } -func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string, idToReturn *AdvancedThreatProtectionResourceID) resource.TestCheckFunc { +func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string, idToReturn *securitycenter.AdvancedThreatProtectionResourceID) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure resource group exists in API client := testAccProvider.Meta().(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient @@ -116,7 +117,7 @@ func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string, idToRet return fmt.Errorf("Not found: %s", resourceName) } - id, err := parseAdvancedThreatProtectionID(rs.Primary.ID) + id, err := securitycenter.ParseAdvancedThreatProtectionID(rs.Primary.ID) if err != nil { return err } @@ -136,7 +137,7 @@ func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string, idToRet } } -func testCheckAzureRMAdvancedThreatProtectionIsFalse(id *AdvancedThreatProtectionResourceID) resource.TestCheckFunc { +func testCheckAzureRMAdvancedThreatProtectionIsFalse(id *securitycenter.AdvancedThreatProtectionResourceID) resource.TestCheckFunc { return func(s *terraform.State) error { client := testAccProvider.Meta().(*ArmClient).SecurityCenter.AdvancedThreatProtectionClient ctx := testAccProvider.Meta().(*ArmClient).StopContext @@ -167,7 +168,7 @@ func testCheckAzureRMAdvancedThreatProtectionDestroy(s *terraform.State) error { continue } - id, err := parseAdvancedThreatProtectionID(rs.Primary.ID) + id, err := securitycenter.ParseAdvancedThreatProtectionID(rs.Primary.ID) if err != nil { return err } diff --git a/azurerm/resource_arm_storage_account.go b/azurerm/resource_arm_storage_account.go index bba4c3b8cc0a..b808b64feac1 100644 --- a/azurerm/resource_arm_storage_account.go +++ b/azurerm/resource_arm_storage_account.go @@ -176,9 +176,10 @@ func resourceArmStorageAccount() *schema.Resource { // TODO remove this in 2.0 for the dedicated resource "enable_advanced_threat_protection": { - Type: schema.TypeBool, - Optional: true, - Computed: true, + Type: schema.TypeBool, + Optional: true, + Computed: true, + Deprecated: "This property has been deprecated in favour of the new 'azurerm_advanced_threat_protection' resource and will be removed in version 2.0 of the provider", }, "network_rules": { diff --git a/website/docs/guides/2.0-upgrade-guide.html.markdown b/website/docs/guides/2.0-upgrade-guide.html.markdown index 82355d01cc9c..50af6f744f8f 100644 --- a/website/docs/guides/2.0-upgrade-guide.html.markdown +++ b/website/docs/guides/2.0-upgrade-guide.html.markdown @@ -380,6 +380,8 @@ The deprecated `enable_filtering_messages_before_publishing` field will be remov The deprecated `account_type` field will be removed. This has been split into the fields `account_tier` and `account_replication_type`. +The deprecated `enable_advanced_threat_protection` field will be removed. This functionality has been move in the more general `azurerm_advanced_threat_protection` resource. + ### Resource: `azurerm_storage_blob` The deprecated `attempts` field will be removed, since Terraform now handles retries automatically. From 76ec3f2702d606c6c861e5c8706ba60e5e9dfa5d Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:13:56 -0800 Subject: [PATCH 13/19] add requires import test --- ...rce_arm_advanced_threat_protection_test.go | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index ddbffffe7ae8..1f02fe0186c1 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/securitycenter" ) @@ -105,6 +106,44 @@ func TestAccAzureRMAdvancedThreatProtection_cosmosAccount(t *testing.T) { }) } +func TestAccAzureRMAdvancedThreatProtection_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + rn := "azurerm_advanced_threat_protection.test" + ri := tf.AccRandTimeInt() + var id securitycenter.AdvancedThreatProtectionResourceID + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAdvancedThreatProtectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAdvancedThreatProtection_storageAccount(ri, testLocation(), true, true), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), + resource.TestCheckResourceAttr(rn, "enabled", "true"), + ), + }, + { + ResourceName: rn, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAzureRMAdvancedThreatProtection_requiresImport(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), + resource.TestCheckResourceAttr(rn, "enabled", "false"), + ), + }, + }, + }) +} + func testCheckAzureRMAdvancedThreatProtectionExists(resourceName string, idToReturn *securitycenter.AdvancedThreatProtectionResourceID) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure resource group exists in API @@ -186,6 +225,31 @@ func testCheckAzureRMAdvancedThreatProtectionDestroy(s *terraform.State) error { return nil } +func testAccAzureRMAdvancedThreatProtection_requiresImport(rInt int, location string) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_resource_group" "test" { + name = "acctestRG-ATP-%[2]d" + location = "%[3]s" +} + +resource "azurerm_storage_account" "test" { + name = "acctest%[4]d" + resource_group_name = "${azurerm_resource_group.test.name}" + + location = "${azurerm_resource_group.test.location}" + account_tier = "Standard" + account_replication_type = "LRS" + + tags = { + environment = "production" + } +} + +`, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, testLocation(), true, true), rInt, location, rInt/10) +} + func testAccAzureRMAdvancedThreatProtection_storageAccount(rInt int, location string, hasResource, enabled bool) string { atp := "" if hasResource { From 692f4596f0c0e1e8ebd342886760e6ecf7f82a8d Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:17:30 -0800 Subject: [PATCH 14/19] fix test --- ...rce_arm_advanced_threat_protection_test.go | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index 1f02fe0186c1..ddfbdd9326bb 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -134,11 +134,8 @@ func TestAccAzureRMAdvancedThreatProtection_requiresImport(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccAzureRMAdvancedThreatProtection_requiresImport(ri, testLocation()), - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMAdvancedThreatProtectionExists(rn, &id), - resource.TestCheckResourceAttr(rn, "enabled", "false"), - ), + Config: testAccAzureRMAdvancedThreatProtection_requiresImport(ri, testLocation()), + ExpectError: testRequiresImportError("azurerm_api_management_api_policy"), }, }, }) @@ -229,25 +226,11 @@ func testAccAzureRMAdvancedThreatProtection_requiresImport(rInt int, location st return fmt.Sprintf(` %[1]s -resource "azurerm_resource_group" "test" { - name = "acctestRG-ATP-%[2]d" - location = "%[3]s" -} - -resource "azurerm_storage_account" "test" { - name = "acctest%[4]d" - resource_group_name = "${azurerm_resource_group.test.name}" - - location = "${azurerm_resource_group.test.location}" - account_tier = "Standard" - account_replication_type = "LRS" - - tags = { - environment = "production" - } +resource "azurerm_advanced_threat_protection" "requireimport" { + target_resource_id = "${azurerm_advanced_threat_protection.requireimport.id}" + enabled = "${azurerm_advanced_threat_protection.requireimport.enabled}" } - -`, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, testLocation(), true, true), rInt, location, rInt/10) +`, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, testLocation(), true, true)) } func testAccAzureRMAdvancedThreatProtection_storageAccount(rInt int, location string, hasResource, enabled bool) string { From 92aa7f05e6cbbaa9e3e5dfa4ba6352d6374aa9de Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:20:33 -0800 Subject: [PATCH 15/19] fix test --- azurerm/resource_arm_advanced_threat_protection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index ddfbdd9326bb..b5ae62cf7f43 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -227,8 +227,8 @@ func testAccAzureRMAdvancedThreatProtection_requiresImport(rInt int, location st %[1]s resource "azurerm_advanced_threat_protection" "requireimport" { - target_resource_id = "${azurerm_advanced_threat_protection.requireimport.id}" - enabled = "${azurerm_advanced_threat_protection.requireimport.enabled}" + target_resource_id = "${azurerm_advanced_threat_protection.test.id}" + enabled = "${azurerm_advanced_threat_protection.test.enabled}" } `, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, testLocation(), true, true)) } From a172a320346e5db17c46883c254c68fdb47c8ba5 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:22:37 -0800 Subject: [PATCH 16/19] fix small typo --- azurerm/resource_arm_advanced_threat_protection_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index b5ae62cf7f43..dfd1cdcc53ab 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -230,7 +230,7 @@ resource "azurerm_advanced_threat_protection" "requireimport" { target_resource_id = "${azurerm_advanced_threat_protection.test.id}" enabled = "${azurerm_advanced_threat_protection.test.enabled}" } -`, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, testLocation(), true, true)) +`, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, location, true, true)) } func testAccAzureRMAdvancedThreatProtection_storageAccount(rInt int, location string, hasResource, enabled bool) string { From 0a9c3b86439edc64e89ccbcfef92d261189d76c9 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:33:40 -0800 Subject: [PATCH 17/19] another typo --- azurerm/resource_arm_advanced_threat_protection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection_test.go b/azurerm/resource_arm_advanced_threat_protection_test.go index dfd1cdcc53ab..f71a02ebb004 100644 --- a/azurerm/resource_arm_advanced_threat_protection_test.go +++ b/azurerm/resource_arm_advanced_threat_protection_test.go @@ -135,7 +135,7 @@ func TestAccAzureRMAdvancedThreatProtection_requiresImport(t *testing.T) { }, { Config: testAccAzureRMAdvancedThreatProtection_requiresImport(ri, testLocation()), - ExpectError: testRequiresImportError("azurerm_api_management_api_policy"), + ExpectError: testRequiresImportError("azurerm_advanced_threat_protection"), }, }, }) @@ -227,7 +227,7 @@ func testAccAzureRMAdvancedThreatProtection_requiresImport(rInt int, location st %[1]s resource "azurerm_advanced_threat_protection" "requireimport" { - target_resource_id = "${azurerm_advanced_threat_protection.test.id}" + target_resource_id = "${azurerm_advanced_threat_protection.test.target_resource_id}" enabled = "${azurerm_advanced_threat_protection.test.enabled}" } `, testAccAzureRMAdvancedThreatProtection_storageAccount(rInt, location, true, true)) From 97992cfec3d7cf217cec3c5b71c94cc3d40dd6b7 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 17 Dec 2019 23:44:21 -0800 Subject: [PATCH 18/19] fix test --- azurerm/resource_arm_advanced_threat_protection.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/resource_arm_advanced_threat_protection.go b/azurerm/resource_arm_advanced_threat_protection.go index 6fcef3861fb6..e9dd3f4b354f 100644 --- a/azurerm/resource_arm_advanced_threat_protection.go +++ b/azurerm/resource_arm_advanced_threat_protection.go @@ -57,14 +57,14 @@ func resourceArmAdvancedThreatProtectionCreateUpdate(d *schema.ResourceData, met resourceID := d.Get("target_resource_id").(string) if features.ShouldResourcesBeImported() && d.IsNewResource() { - server, err := client.Get(ctx, "target_resource_id") + server, err := client.Get(ctx, resourceID) if err != nil { if !utils.ResponseWasNotFound(server.Response) { return fmt.Errorf("Error checking for presence of existing Advanced Threat Protection for resource %q: %+v", resourceID, err) } } - if server.ID != nil && *server.ID != "" { + if server.ID != nil && *server.ID != "" && server.IsEnabled != nil && *server.IsEnabled { return tf.ImportAsExistsError("azurerm_advanced_threat_protection", *server.ID) } } From bb696904ac1fcf883d33c3a53c235726f781d5fe Mon Sep 17 00:00:00 2001 From: kt Date: Wed, 18 Dec 2019 00:16:13 -0800 Subject: [PATCH 19/19] make fmt --- azurerm/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/provider.go b/azurerm/provider.go index f8e5d69f020e..3ac63fe1b07e 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -157,7 +157,7 @@ func Provider() terraform.ResourceProvider { } resources := map[string]*schema.Resource{ - "azurerm_advanced_threat_protection": resourceArmAdvancedThreatProtection(), + "azurerm_advanced_threat_protection": resourceArmAdvancedThreatProtection(), "azurerm_analysis_services_server": resourceArmAnalysisServicesServer(), "azurerm_api_management": resourceArmApiManagementService(), "azurerm_api_management_api": resourceArmApiManagementApi(),