From 100fa1fc6412ab6efec0ea4c5a9d72c520d9da82 Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Sun, 13 Oct 2019 11:54:26 +0300 Subject: [PATCH 01/38] add ca_cert_identifier to rds instance --- aws/resource_aws_db_instance.go | 25 ++++++++++++---- aws/resource_aws_db_instance_test.go | 45 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 921f2a48374..19186e25475 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -81,6 +81,12 @@ func resourceAwsDbInstance() *schema.Resource { DiffSuppressFunc: suppressAwsDbEngineVersionDiffs, }, + "ca_cert_identifier": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "character_set_name": { Type: schema.TypeString, Optional: true, @@ -422,11 +428,6 @@ func resourceAwsDbInstance() *schema.Resource { Computed: true, }, - "ca_cert_identifier": { - Type: schema.TypeString, - Computed: true, - }, - "enabled_cloudwatch_logs_exports": { Type: schema.TypeList, Optional: true, @@ -1043,6 +1044,7 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error if _, ok := d.GetOk("username"); !ok { return fmt.Errorf(`provider.aws: aws_db_instance: %s: "username": required field is not set`, d.Get("name").(string)) } + opts := rds.CreateDBInstanceInput{ AllocatedStorage: aws.Int64(int64(d.Get("allocated_storage").(int))), DBName: aws.String(d.Get("name").(string)), @@ -1176,8 +1178,9 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) var err error + var createdDBInstanceOutput *rds.CreateDBInstanceOutput err = resource.Retry(5*time.Minute, func() *resource.RetryError { - _, err = conn.CreateDBInstance(&opts) + createdDBInstanceOutput, err = conn.CreateDBInstance(&opts) if err != nil { if isAWSErr(err, "InvalidParameterValue", "ENHANCED_MONITORING") { return resource.RetryableError(err) @@ -1196,6 +1199,11 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error } return fmt.Errorf("Error creating DB Instance: %s", err) } + // This is added here to avoid unnecessary modification when ca_cert_identifier is the default one + if attr, ok := d.GetOk("ca_cert_identifier"); ok && attr.(string) != aws.StringValue(createdDBInstanceOutput.DBInstance.CACertificateIdentifier) { + modifyDbInstanceInput.CACertificateIdentifier = aws.String(attr.(string)) + requiresModifyDbInstance = true + } } d.SetId(d.Get("identifier").(string)) @@ -1484,6 +1492,11 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error req.CopyTagsToSnapshot = aws.Bool(d.Get("copy_tags_to_snapshot").(bool)) requestUpdate = true } + if d.HasChange("ca_cert_identifier") { + d.SetPartial("ca_cert_identifier") + req.CACertificateIdentifier = aws.String(d.Get("ca_cert_identifier").(string)) + requestUpdate = true + } if d.HasChange("deletion_protection") { d.SetPartial("deletion_protection") req.DeletionProtection = aws.Bool(d.Get("deletion_protection").(bool)) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 0a1a6153c51..fe8374052fd 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -2583,6 +2583,35 @@ func TestAccAWSDBInstance_SnapshotIdentifier_PerformanceInsightsEnabled(t *testi }) } +func TestAccAWSDBInstance_CACertificateIdentifier(t *testing.T) { + var dbInstance rds.DBInstance + + resourceName := "aws_db_instance.bar" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(testAccAWSDBInstanceConfigWithCACertificateIdentifier, "rds-ca-2015"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + resource.TestCheckResourceAttr(resourceName, "ca_cert_identifier", "rds-ca-2015"), + ), + }, + // Ensure we are able to modify the CACertIdentifier + { + Config: fmt.Sprintf(testAccAWSDBInstanceConfigWithCACertificateIdentifier, "rds-ca-2019"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists(resourceName, &dbInstance), + resource.TestCheckResourceAttr(resourceName, "ca_cert_identifier", "rds-ca-2019"), + ), + }, + }, + }) +} + // Database names cannot collide, and deletion takes so long, that making the // name a bit random helps so able we can kill a test that's just waiting for a // delete and not be blocked on kicking off another one. @@ -2690,6 +2719,22 @@ resource "aws_db_instance" "bar" { } ` +const testAccAWSDBInstanceConfigWithCACertificateIdentifier = ` +resource "aws_db_instance" "bar" { + allocated_storage = 10 + engine = "MySQL" + instance_class = "db.t2.micro" + name = "baz" + password = "barbarbarbar" + username = "foo" + ca_cert_identifier = "%s" + apply_immediately = true + skip_final_snapshot = true + timeouts { + create = "30m" + } +}` + func testAccAWSDBInstanceConfigWithOptionGroup(rName string) string { return fmt.Sprintf(` resource "aws_db_option_group" "bar" { From 201a0b211657d64aca96e49e21e41bfad2c1212c Mon Sep 17 00:00:00 2001 From: Sunil Kumar Mohanty Date: Sun, 13 Oct 2019 12:08:23 +0300 Subject: [PATCH 02/38] update documentation --- website/docs/r/db_instance.html.markdown | 340 +++++++++++------------ 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/website/docs/r/db_instance.html.markdown b/website/docs/r/db_instance.html.markdown index e61e8f4bbff..a47cad6a71d 100644 --- a/website/docs/r/db_instance.html.markdown +++ b/website/docs/r/db_instance.html.markdown @@ -1,14 +1,14 @@ --- -layout: "aws" -page_title: "AWS: aws_db_instance" +layout: 'aws' +page_title: 'AWS: aws_db_instance' description: |- Provides an RDS instance resource. --- # Resource: aws_db_instance -Provides an RDS instance resource. A DB instance is an isolated database -environment in the cloud. A DB instance can contain multiple user-created +Provides an RDS instance resource. A DB instance is an isolated database +environment in the cloud. A DB instance can contain multiple user-created databases. Changes to a DB instance can occur when you manually change a parameter, such as @@ -29,6 +29,7 @@ the raw state as plain-text. [Read more about sensitive data in state](/docs/state/sensitive-data.html). ## RDS Instance Class Types + Amazon RDS supports three types of instance classes: Standard, Memory Optimized, and Burstable Performance. For more information please read the AWS RDS documentation about [DB Instance Class Types](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html) @@ -71,133 +72,134 @@ documentation](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_Crea The following arguments are supported: -* `allocated_storage` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The allocated storage in gibibytes. If `max_allocated_storage` is configured, this argument represents the initial storage allocation and differences from the configuration will be ignored automatically when Storage Autoscaling occurs. -* `allow_major_version_upgrade` - (Optional) Indicates that major version -upgrades are allowed. Changing this parameter does not result in an outage and -the change is asynchronously applied as soon as possible. -* `apply_immediately` - (Optional) Specifies whether any database modifications -are applied immediately, or during the next maintenance window. Default is -`false`. See [Amazon RDS Documentation for more -information.](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html) -* `auto_minor_version_upgrade` - (Optional) Indicates that minor engine upgrades -will be applied automatically to the DB instance during the maintenance window. -Defaults to true. -* `availability_zone` - (Optional) The AZ for the RDS instance. -* `backup_retention_period` - (Optional) The days to retain backups for. Must be -between `0` and `35`. Must be greater than `0` if the database is used as a source for a Read Replica. [See Read Replica][1]. -* `backup_window` - (Optional) The daily time range (in UTC) during which -automated backups are created if they are enabled. Example: "09:46-10:16". Must -not overlap with `maintenance_window`. -* `character_set_name` - (Optional) The character set name to use for DB -encoding in Oracle instances. This can't be changed. See [Oracle Character Sets -Supported in Amazon -RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.OracleCharacterSets.html) -for more information. -* `copy_tags_to_snapshot` – (Optional, boolean) Copy all Instance `tags` to snapshots. Default is `false`. -* `db_subnet_group_name` - (Optional) Name of [DB subnet group](/docs/providers/aws/r/db_subnet_group.html). DB instance will -be created in the VPC associated with the DB subnet group. If unspecified, will -be created in the `default` VPC, or in EC2 Classic, if available. When working -with read replicas, it should be specified only if the source database -specifies an instance in another AWS Region. See [DBSubnetGroupName in API -action CreateDBInstanceReadReplica](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstanceReadReplica.html) -for additional read replica contraints. -* `deletion_protection` - (Optional) If the DB instance should have deletion protection enabled. The database can't be deleted when this value is set to `true`. The default is `false`. -* `domain` - (Optional) The ID of the Directory Service Active Directory domain to create the instance in. -* `domain_iam_role_name` - (Optional, but required if domain is provided) The name of the IAM role to be used when making API calls to the Directory Service. -* `enabled_cloudwatch_logs_exports` - (Optional) List of log types to enable for exporting to CloudWatch logs. If omitted, no logs will be exported. Valid values (depending on `engine`): `alert`, `audit`, `error`, `general`, `listener`, `slowquery`, `trace`, `postgresql` (PostgreSQL), `upgrade` (PostgreSQL). -* `engine` - (Required unless a `snapshot_identifier` or `replicate_source_db` -is provided) The database engine to use. For supported values, see the Engine parameter in [API action CreateDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html). -Note that for Amazon Aurora instances the engine must match the [DB cluster](/docs/providers/aws/r/rds_cluster.html)'s engine'. -For information on the difference between the available Aurora MySQL engines -see [Comparison between Aurora MySQL 1 and Aurora MySQL 2](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/AuroraMySQL.Updates.20180206.html) -in the Amazon RDS User Guide. -* `engine_version` - (Optional) The engine version to use. If `auto_minor_version_upgrade` -is enabled, you can provide a prefix of the version such as `5.7` (for `5.7.10`) and -this attribute will ignore differences in the patch version automatically (e.g. `5.7.17`). -For supported values, see the EngineVersion parameter in [API action CreateDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html). -Note that for Amazon Aurora instances the engine version must match the [DB cluster](/docs/providers/aws/r/rds_cluster.html)'s engine version'. -* `final_snapshot_identifier` - (Optional) The name of your final DB snapshot -when this DB instance is deleted. Must be provided if `skip_final_snapshot` is -set to `false`. -* `iam_database_authentication_enabled` - (Optional) Specifies whether or -mappings of AWS Identity and Access Management (IAM) accounts to database -accounts is enabled. -* `identifier` - (Optional, Forces new resource) The name of the RDS instance, -if omitted, Terraform will assign a random, unique identifier. -* `identifier_prefix` - (Optional, Forces new resource) Creates a unique -identifier beginning with the specified prefix. Conflicts with `identifier`. -* `instance_class` - (Required) The instance type of the RDS instance. -* `iops` - (Optional) The amount of provisioned IOPS. Setting this implies a -storage_type of "io1". -* `kms_key_id` - (Optional) The ARN for the KMS encryption key. If creating an -encrypted replica, set this to the destination KMS ARN. -* `license_model` - (Optional, but required for some DB engines, i.e. Oracle -SE1) License model information for this DB instance. -* `maintenance_window` - (Optional) The window to perform maintenance in. -Syntax: "ddd:hh24:mi-ddd:hh24:mi". Eg: "Mon:00:00-Mon:03:00". See [RDS -Maintenance Window -docs](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html#AdjustingTheMaintenanceWindow) -for more information. -* `max_allocated_storage` - (Optional) When configured, the upper limit to which Amazon RDS can automatically scale the storage of the DB instance. Configuring this will automatically ignore differences to `allocated_storage`. Must be greater than or equal to `allocated_storage` or `0` to disable Storage Autoscaling. -* `monitoring_interval` - (Optional) The interval, in seconds, between points -when Enhanced Monitoring metrics are collected for the DB instance. To disable -collecting Enhanced Monitoring metrics, specify 0. The default is 0. Valid -Values: 0, 1, 5, 10, 15, 30, 60. -* `monitoring_role_arn` - (Optional) The ARN for the IAM role that permits RDS -to send enhanced monitoring metrics to CloudWatch Logs. You can find more -information on the [AWS -Documentation](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.html) -what IAM permissions are needed to allow Enhanced Monitoring for RDS Instances. -* `multi_az` - (Optional) Specifies if the RDS instance is multi-AZ -* `name` - (Optional) The name of the database to create when the DB instance is created. If this parameter is not specified, no database is created in the DB instance. Note that this does not apply for Oracle or SQL Server engines. See the [AWS documentation](http://docs.aws.amazon.com/cli/latest/reference/rds/create-db-instance.html) for more details on what applies for those engines. -* `option_group_name` - (Optional) Name of the DB option group to associate. -* `parameter_group_name` - (Optional) Name of the DB parameter group to -associate. -* `password` - (Required unless a `snapshot_identifier` or `replicate_source_db` -is provided) Password for the master DB user. Note that this may show up in -logs, and it will be stored in the state file. -* `port` - (Optional) The port on which the DB accepts connections. -* `publicly_accessible` - (Optional) Bool to control if instance is publicly -accessible. Default is `false`. -* `replicate_source_db` - (Optional) Specifies that this resource is a Replicate -database, and to use this value as the source database. This correlates to the -`identifier` of another Amazon RDS Database to replicate. Note that if you are -creating a cross-region replica of an encrypted database you will also need to -specify a `kms_key_id`. See [DB Instance Replication][1] and [Working with -PostgreSQL and MySQL Read Replicas](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html) -for more information on using Replication. -* `security_group_names` - (Optional/Deprecated) List of DB Security Groups to -associate. Only used for [DB Instances on the _EC2-Classic_ -Platform](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.html#USER_VPC.FindDefaultVPC). -* `skip_final_snapshot` - (Optional) Determines whether a final DB snapshot is -created before the DB instance is deleted. If true is specified, no DBSnapshot -is created. If false is specified, a DB snapshot is created before the DB -instance is deleted, using the value from `final_snapshot_identifier`. Default -is `false`. -* `snapshot_identifier` - (Optional) Specifies whether or not to create this -database from a snapshot. This correlates to the snapshot ID you'd find in the -RDS console, e.g: rds:production-2015-06-26-06-05. -* `storage_encrypted` - (Optional) Specifies whether the DB instance is -encrypted. Note that if you are creating a cross-region read replica this field -is ignored and you should instead declare `kms_key_id` with a valid ARN. The -default is `false` if not specified. -* `storage_type` - (Optional) One of "standard" (magnetic), "gp2" (general -purpose SSD), or "io1" (provisioned IOPS SSD). The default is "io1" if `iops` is -specified, "gp2" if not. -* `tags` - (Optional) A mapping of tags to assign to the resource. -* `timezone` - (Optional) Time zone of the DB instance. `timezone` is currently -only supported by Microsoft SQL Server. The `timezone` can only be set on -creation. See [MSSQL User -Guide](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_SQLServer.html#SQLServer.Concepts.General.TimeZone) -for more information. -* `username` - (Required unless a `snapshot_identifier` or `replicate_source_db` -is provided) Username for the master DB user. -* `vpc_security_group_ids` - (Optional) List of VPC security groups to -associate. -* `s3_import` - (Optional) Restore from a Percona Xtrabackup in S3. See [Importing Data into an Amazon RDS MySQL DB Instance](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.html) -* `performance_insights_enabled` - (Optional) Specifies whether Performance Insights are enabled. Defaults to false. -* `performance_insights_kms_key_id` - (Optional) The ARN for the KMS key to encrypt Performance Insights data. When specifying `performance_insights_kms_key_id`, `performance_insights_enabled` needs to be set to true. Once KMS key is set, it can never be changed. -* `performance_insights_retention_period` - (Optional) The amount of time in days to retain Performance Insights data. Either 7 (7 days) or 731 (2 years). When specifying `performance_insights_retention_period`, `performance_insights_enabled` needs to be set to true. Defaults to '7'. +- `allocated_storage` - (Required unless a `snapshot_identifier` or `replicate_source_db` is provided) The allocated storage in gibibytes. If `max_allocated_storage` is configured, this argument represents the initial storage allocation and differences from the configuration will be ignored automatically when Storage Autoscaling occurs. +- `allow_major_version_upgrade` - (Optional) Indicates that major version + upgrades are allowed. Changing this parameter does not result in an outage and + the change is asynchronously applied as soon as possible. +- `apply_immediately` - (Optional) Specifies whether any database modifications + are applied immediately, or during the next maintenance window. Default is + `false`. See [Amazon RDS Documentation for more + information.](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html) +- `auto_minor_version_upgrade` - (Optional) Indicates that minor engine upgrades + will be applied automatically to the DB instance during the maintenance window. + Defaults to true. +- `availability_zone` - (Optional) The AZ for the RDS instance. +- `backup_retention_period` - (Optional) The days to retain backups for. Must be + between `0` and `35`. Must be greater than `0` if the database is used as a source for a Read Replica. [See Read Replica][1]. +- `backup_window` - (Optional) The daily time range (in UTC) during which + automated backups are created if they are enabled. Example: "09:46-10:16". Must + not overlap with `maintenance_window`. +- `ca_cert_identifier` - (Optional) The identifier of the CA certificate for the DB instance. +- `character_set_name` - (Optional) The character set name to use for DB + encoding in Oracle instances. This can't be changed. See [Oracle Character Sets + Supported in Amazon + RDS](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.OracleCharacterSets.html) + for more information. +- `copy_tags_to_snapshot` – (Optional, boolean) Copy all Instance `tags` to snapshots. Default is `false`. +- `db_subnet_group_name` - (Optional) Name of [DB subnet group](/docs/providers/aws/r/db_subnet_group.html). DB instance will + be created in the VPC associated with the DB subnet group. If unspecified, will + be created in the `default` VPC, or in EC2 Classic, if available. When working + with read replicas, it should be specified only if the source database + specifies an instance in another AWS Region. See [DBSubnetGroupName in API + action CreateDBInstanceReadReplica](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstanceReadReplica.html) + for additional read replica contraints. +- `deletion_protection` - (Optional) If the DB instance should have deletion protection enabled. The database can't be deleted when this value is set to `true`. The default is `false`. +- `domain` - (Optional) The ID of the Directory Service Active Directory domain to create the instance in. +- `domain_iam_role_name` - (Optional, but required if domain is provided) The name of the IAM role to be used when making API calls to the Directory Service. +- `enabled_cloudwatch_logs_exports` - (Optional) List of log types to enable for exporting to CloudWatch logs. If omitted, no logs will be exported. Valid values (depending on `engine`): `alert`, `audit`, `error`, `general`, `listener`, `slowquery`, `trace`, `postgresql` (PostgreSQL), `upgrade` (PostgreSQL). +- `engine` - (Required unless a `snapshot_identifier` or `replicate_source_db` + is provided) The database engine to use. For supported values, see the Engine parameter in [API action CreateDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html). + Note that for Amazon Aurora instances the engine must match the [DB cluster](/docs/providers/aws/r/rds_cluster.html)'s engine'. + For information on the difference between the available Aurora MySQL engines + see [Comparison between Aurora MySQL 1 and Aurora MySQL 2](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/AuroraMySQL.Updates.20180206.html) + in the Amazon RDS User Guide. +- `engine_version` - (Optional) The engine version to use. If `auto_minor_version_upgrade` + is enabled, you can provide a prefix of the version such as `5.7` (for `5.7.10`) and + this attribute will ignore differences in the patch version automatically (e.g. `5.7.17`). + For supported values, see the EngineVersion parameter in [API action CreateDBInstance](https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html). + Note that for Amazon Aurora instances the engine version must match the [DB cluster](/docs/providers/aws/r/rds_cluster.html)'s engine version'. +- `final_snapshot_identifier` - (Optional) The name of your final DB snapshot + when this DB instance is deleted. Must be provided if `skip_final_snapshot` is + set to `false`. +- `iam_database_authentication_enabled` - (Optional) Specifies whether or + mappings of AWS Identity and Access Management (IAM) accounts to database + accounts is enabled. +- `identifier` - (Optional, Forces new resource) The name of the RDS instance, + if omitted, Terraform will assign a random, unique identifier. +- `identifier_prefix` - (Optional, Forces new resource) Creates a unique + identifier beginning with the specified prefix. Conflicts with `identifier`. +- `instance_class` - (Required) The instance type of the RDS instance. +- `iops` - (Optional) The amount of provisioned IOPS. Setting this implies a + storage_type of "io1". +- `kms_key_id` - (Optional) The ARN for the KMS encryption key. If creating an + encrypted replica, set this to the destination KMS ARN. +- `license_model` - (Optional, but required for some DB engines, i.e. Oracle + SE1) License model information for this DB instance. +- `maintenance_window` - (Optional) The window to perform maintenance in. + Syntax: "ddd:hh24:mi-ddd:hh24:mi". Eg: "Mon:00:00-Mon:03:00". See [RDS + Maintenance Window + docs](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html#AdjustingTheMaintenanceWindow) + for more information. +- `max_allocated_storage` - (Optional) When configured, the upper limit to which Amazon RDS can automatically scale the storage of the DB instance. Configuring this will automatically ignore differences to `allocated_storage`. Must be greater than or equal to `allocated_storage` or `0` to disable Storage Autoscaling. +- `monitoring_interval` - (Optional) The interval, in seconds, between points + when Enhanced Monitoring metrics are collected for the DB instance. To disable + collecting Enhanced Monitoring metrics, specify 0. The default is 0. Valid + Values: 0, 1, 5, 10, 15, 30, 60. +- `monitoring_role_arn` - (Optional) The ARN for the IAM role that permits RDS + to send enhanced monitoring metrics to CloudWatch Logs. You can find more + information on the [AWS + Documentation](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.html) + what IAM permissions are needed to allow Enhanced Monitoring for RDS Instances. +- `multi_az` - (Optional) Specifies if the RDS instance is multi-AZ +- `name` - (Optional) The name of the database to create when the DB instance is created. If this parameter is not specified, no database is created in the DB instance. Note that this does not apply for Oracle or SQL Server engines. See the [AWS documentation](http://docs.aws.amazon.com/cli/latest/reference/rds/create-db-instance.html) for more details on what applies for those engines. +- `option_group_name` - (Optional) Name of the DB option group to associate. +- `parameter_group_name` - (Optional) Name of the DB parameter group to + associate. +- `password` - (Required unless a `snapshot_identifier` or `replicate_source_db` + is provided) Password for the master DB user. Note that this may show up in + logs, and it will be stored in the state file. +- `port` - (Optional) The port on which the DB accepts connections. +- `publicly_accessible` - (Optional) Bool to control if instance is publicly + accessible. Default is `false`. +- `replicate_source_db` - (Optional) Specifies that this resource is a Replicate + database, and to use this value as the source database. This correlates to the + `identifier` of another Amazon RDS Database to replicate. Note that if you are + creating a cross-region replica of an encrypted database you will also need to + specify a `kms_key_id`. See [DB Instance Replication][1] and [Working with + PostgreSQL and MySQL Read Replicas](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html) + for more information on using Replication. +- `security_group_names` - (Optional/Deprecated) List of DB Security Groups to + associate. Only used for [DB Instances on the _EC2-Classic_ + Platform](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.html#USER_VPC.FindDefaultVPC). +- `skip_final_snapshot` - (Optional) Determines whether a final DB snapshot is + created before the DB instance is deleted. If true is specified, no DBSnapshot + is created. If false is specified, a DB snapshot is created before the DB + instance is deleted, using the value from `final_snapshot_identifier`. Default + is `false`. +- `snapshot_identifier` - (Optional) Specifies whether or not to create this + database from a snapshot. This correlates to the snapshot ID you'd find in the + RDS console, e.g: rds:production-2015-06-26-06-05. +- `storage_encrypted` - (Optional) Specifies whether the DB instance is + encrypted. Note that if you are creating a cross-region read replica this field + is ignored and you should instead declare `kms_key_id` with a valid ARN. The + default is `false` if not specified. +- `storage_type` - (Optional) One of "standard" (magnetic), "gp2" (general + purpose SSD), or "io1" (provisioned IOPS SSD). The default is "io1" if `iops` is + specified, "gp2" if not. +- `tags` - (Optional) A mapping of tags to assign to the resource. +- `timezone` - (Optional) Time zone of the DB instance. `timezone` is currently + only supported by Microsoft SQL Server. The `timezone` can only be set on + creation. See [MSSQL User + Guide](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_SQLServer.html#SQLServer.Concepts.General.TimeZone) + for more information. +- `username` - (Required unless a `snapshot_identifier` or `replicate_source_db` + is provided) Username for the master DB user. +- `vpc_security_group_ids` - (Optional) List of VPC security groups to + associate. +- `s3_import` - (Optional) Restore from a Percona Xtrabackup in S3. See [Importing Data into an Amazon RDS MySQL DB Instance](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/MySQL.Procedural.Importing.html) +- `performance_insights_enabled` - (Optional) Specifies whether Performance Insights are enabled. Defaults to false. +- `performance_insights_kms_key_id` - (Optional) The ARN for the KMS key to encrypt Performance Insights data. When specifying `performance_insights_kms_key_id`, `performance_insights_enabled` needs to be set to true. Once KMS key is set, it can never be changed. +- `performance_insights_retention_period` - (Optional) The amount of time in days to retain Performance Insights data. Either 7 (7 days) or 731 (2 years). When specifying `performance_insights_retention_period`, `performance_insights_enabled` needs to be set to true. Defaults to '7'. ~> **NOTE:** Removing the `replicate_source_db` attribute from an existing RDS Replicate database managed by Terraform will promote the database to a fully @@ -205,7 +207,7 @@ standalone database. ### S3 Import Options -Full details on the core parameters and impacts are in the API Docs: [RestoreDBInstanceFromS3](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromS3.html). Sample +Full details on the core parameters and impacts are in the API Docs: [RestoreDBInstanceFromS3](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromS3.html). Sample ```hcl resource "aws_db_instance" "db" { @@ -219,13 +221,13 @@ resource "aws_db_instance" "db" { } ``` -* `bucket_name` - (Required) The bucket name where your backup is stored -* `bucket_prefix` - (Optional) Can be blank, but is the path to your backup -* `ingestion_role` - (Required) Role applied to load the data. -* `source_engine` - (Required, as of Feb 2018 only 'mysql' supported) Source engine for the backup -* `source_engine_version` - (Required, as of Feb 2018 only '5.6' supported) Version of the source engine used to make the backup +- `bucket_name` - (Required) The bucket name where your backup is stored +- `bucket_prefix` - (Optional) Can be blank, but is the path to your backup +- `ingestion_role` - (Required) Role applied to load the data. +- `source_engine` - (Required, as of Feb 2018 only 'mysql' supported) Source engine for the backup +- `source_engine_version` - (Required, as of Feb 2018 only '5.6' supported) Version of the source engine used to make the backup -This will not recreate the resource if the S3 object changes in some way. It's only used to initialize the database +This will not recreate the resource if the S3 object changes in some way. It's only used to initialize the database ### Timeouts @@ -233,49 +235,47 @@ This will not recreate the resource if the S3 object changes in some way. It's [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: - `create` - (Default `40 minutes`) Used for Creating Instances, Replicas, and -restoring from Snapshots. + restoring from Snapshots. - `update` - (Default `80 minutes`) Used for Database modifications. - `delete` - (Default `40 minutes`) Used for destroying databases. This includes -the time required to take snapshots. + the time required to take snapshots. -[1]: -https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Replication.html -[2]: -https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html +[1]: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Replication.html +[2]: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_UpgradeDBInstance.Maintenance.html ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `address` - The hostname of the RDS instance. See also `endpoint` and `port`. -* `arn` - The ARN of the RDS instance. -* `allocated_storage` - The amount of allocated storage. -* `availability_zone` - The availability zone of the instance. -* `backup_retention_period` - The backup retention period. -* `backup_window` - The backup window. -* `ca_cert_identifier` - Specifies the identifier of the CA certificate for the -DB instance. -* `domain` - The ID of the Directory Service Active Directory domain the instance is joined to -* `domain_iam_role_name` - The name of the IAM role to be used when making API calls to the Directory Service. -* `endpoint` - The connection endpoint in `address:port` format. -* `engine` - The database engine. -* `engine_version` - The database engine version. -* `hosted_zone_id` - The canonical hosted zone ID of the DB instance (to be used -in a Route 53 Alias record). -* `id` - The RDS instance ID. -* `instance_class`- The RDS instance class. -* `maintenance_window` - The instance maintenance window. -* `multi_az` - If the RDS instance is multi AZ enabled. -* `name` - The database name. -* `port` - The database port. -* `resource_id` - The RDS Resource ID of this instance. -* `status` - The RDS instance status. -* `storage_encrypted` - Specifies whether the DB instance is encrypted. -* `username` - The master username for the database. +- `address` - The hostname of the RDS instance. See also `endpoint` and `port`. +- `arn` - The ARN of the RDS instance. +- `allocated_storage` - The amount of allocated storage. +- `availability_zone` - The availability zone of the instance. +- `backup_retention_period` - The backup retention period. +- `backup_window` - The backup window. +- `ca_cert_identifier` - Specifies the identifier of the CA certificate for the + DB instance. +- `domain` - The ID of the Directory Service Active Directory domain the instance is joined to +- `domain_iam_role_name` - The name of the IAM role to be used when making API calls to the Directory Service. +- `endpoint` - The connection endpoint in `address:port` format. +- `engine` - The database engine. +- `engine_version` - The database engine version. +- `hosted_zone_id` - The canonical hosted zone ID of the DB instance (to be used + in a Route 53 Alias record). +- `id` - The RDS instance ID. +- `instance_class`- The RDS instance class. +- `maintenance_window` - The instance maintenance window. +- `multi_az` - If the RDS instance is multi AZ enabled. +- `name` - The database name. +- `port` - The database port. +- `resource_id` - The RDS Resource ID of this instance. +- `status` - The RDS instance status. +- `storage_encrypted` - Specifies whether the DB instance is encrypted. +- `username` - The master username for the database. On Oracle instances the following is exported additionally: -* `character_set_name` - The character set used on Oracle instances. +- `character_set_name` - The character set used on Oracle instances. ## Import From 861c14a892431c969bb0f757e6e260db153cc3dd Mon Sep 17 00:00:00 2001 From: Miguel Ferreira Date: Fri, 15 Nov 2019 10:22:16 +0100 Subject: [PATCH 03/38] Fix typo in mq_broker docs (#10888) --- website/docs/r/mq_broker.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/mq_broker.html.markdown b/website/docs/r/mq_broker.html.markdown index 8b9f08f5ccd..10b85163d84 100644 --- a/website/docs/r/mq_broker.html.markdown +++ b/website/docs/r/mq_broker.html.markdown @@ -60,7 +60,7 @@ The following arguments are supported: * `deployment_mode` - (Optional) The deployment mode of the broker. Supported: `SINGLE_INSTANCE` and `ACTIVE_STANDBY_MULTI_AZ`. Defaults to `SINGLE_INSTANCE`. * `encryption_options` - (Optional) Configuration block containing encryption options. See below. * `engine_type` - (Required) The type of broker engine. Currently, Amazon MQ supports only `ActiveMQ`. -* `engine_version` - (Required) The version of the broker engine. Currently, See the [AmazonMQ Broker Engine docs](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/broker-engine.html) for supported versions. +* `engine_version` - (Required) The version of the broker engine. See the [AmazonMQ Broker Engine docs](https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/broker-engine.html) for supported versions. * `host_instance_type` - (Required) The broker's instance type. e.g. `mq.t2.micro` or `mq.m4.large` * `publicly_accessible` - (Optional) Whether to enable connections from applications outside of the VPC that hosts the broker's subnets. * `security_groups` - (Required) The list of security group IDs assigned to the broker. From 36bb33efb3ce03cfd9cd84541fabccbc42bd1add Mon Sep 17 00:00:00 2001 From: HIRAMATSU Kentaro Date: Fri, 15 Nov 2019 18:38:52 +0900 Subject: [PATCH 04/38] service/ecs: Refactor to use keyvaluetags package (#10856) Output from acceptance testing: ``` --- PASS: TestAccAWSEcsCluster_basic (18.13s) --- PASS: TestAccAWSEcsCluster_containerInsights (27.54s) --- PASS: TestAccAWSEcsCluster_disappears (15.45s) --- PASS: TestAccAWSEcsCluster_Tags (28.54s) --- PASS: TestAccAWSEcsService_basicImport (84.56s) --- PASS: TestAccAWSEcsService_disappears (58.00s) --- PASS: TestAccAWSEcsService_healthCheckGracePeriodSeconds (293.66s) --- PASS: TestAccAWSEcsService_ManagedTags (62.65s) --- PASS: TestAccAWSEcsService_PropagateTags (135.32s) --- PASS: TestAccAWSEcsService_Tags (73.95s) --- PASS: TestAccAWSEcsService_withAlb (251.00s) --- PASS: TestAccAWSEcsService_withARN (87.87s) --- PASS: TestAccAWSEcsService_withDaemonSchedulingStrategy (42.23s) --- PASS: TestAccAWSEcsService_withDaemonSchedulingStrategySetDeploymentMinimum (32.69s) --- PASS: TestAccAWSEcsService_withDeploymentController_Type_CodeDeploy (249.69s) --- PASS: TestAccAWSEcsService_withDeploymentMinimumZeroMaximumOneHundred (73.21s) --- PASS: TestAccAWSEcsService_withDeploymentValues (62.75s) --- PASS: TestAccAWSEcsService_withEcsClusterName (73.02s) --- PASS: TestAccAWSEcsService_withFamilyAndRevision (67.27s) --- PASS: TestAccAWSEcsService_withIamRole (42.25s) --- PASS: TestAccAWSEcsService_withLaunchTypeEC2AndNetworkConfiguration (74.39s) --- PASS: TestAccAWSEcsService_withLaunchTypeFargate (99.98s) --- PASS: TestAccAWSEcsService_withLaunchTypeFargateAndPlatformVersion (111.66s) --- PASS: TestAccAWSEcsService_withLbChanges (49.20s) --- PASS: TestAccAWSEcsService_withMultipleTargetGroups (281.45s)TestAccAWSEcsService_healthCheckGracePeriodSeconds --- PASS: TestAccAWSEcsService_withPlacementConstraints (54.52s) --- PASS: TestAccAWSEcsService_withPlacementConstraints_emptyExpression (42.56s) --- PASS: TestAccAWSEcsService_withPlacementStrategy (234.78s) --- PASS: TestAccAWSEcsService_withRenamedCluster (112.87s) --- PASS: TestAccAWSEcsService_withReplicaSchedulingStrategy (63.10s) --- PASS: TestAccAWSEcsService_withServiceRegistries (142.94s) --- PASS: TestAccAWSEcsService_withServiceRegistries_container (132.44s) --- PASS: TestAccAWSEcsService_withUnnormalizedPlacementStrategy (62.09s) --- PASS: TestAccAWSEcsServiceDataSource_basic (74.75s) --- PASS: TestAccAWSEcsTaskDefinition_arrays (6.78s) --- PASS: TestAccAWSEcsTaskDefinition_basic (13.05s) --- PASS: TestAccAWSEcsTaskDefinition_changeVolumesForcesNewResource (12.53s) --- PASS: TestAccAWSEcsTaskDefinition_constraint (6.87s) --- PASS: TestAccAWSEcsTaskDefinition_ExecutionRole (12.16s) --- PASS: TestAccAWSEcsTaskDefinition_Fargate (11.15s) --- PASS: TestAccAWSEcsTaskDefinition_Inactive (12.54s) --- PASS: TestAccAWSEcsTaskDefinition_ProxyConfiguration (8.44s) --- PASS: TestAccAWSEcsTaskDefinition_Tags (17.54s) --- PASS: TestAccAWSEcsTaskDefinition_withDockerVolume (7.30s) --- PASS: TestAccAWSEcsTaskDefinition_withDockerVolumeMinimalConfig (6.88s) --- PASS: TestAccAWSEcsTaskDefinition_withEcsService (47.50s) --- PASS: TestAccAWSEcsTaskDefinition_withIPCMode (10.16s) --- PASS: TestAccAWSEcsTaskDefinition_withNetworkMode (10.51s) --- PASS: TestAccAWSEcsTaskDefinition_withPidMode (10.56s) --- PASS: TestAccAWSEcsTaskDefinition_withScratchVolume (6.78s) --- PASS: TestAccAWSEcsTaskDefinition_withTaskRoleArn (10.61s) --- PASS: TestAccAWSEcsTaskDefinition_withTaskScopedDockerVolume (7.19s) ``` --- aws/resource_aws_ecs_cluster.go | 43 ++------ aws/resource_aws_ecs_service.go | 45 ++------ aws/resource_aws_ecs_task_definition.go | 45 ++------ aws/resource_aws_ecs_task_definition_test.go | 2 - aws/tagsECS.go | 78 ------------- aws/tagsECS_test.go | 110 ------------------- 6 files changed, 26 insertions(+), 297 deletions(-) delete mode 100644 aws/tagsECS.go delete mode 100644 aws/tagsECS_test.go diff --git a/aws/resource_aws_ecs_cluster.go b/aws/resource_aws_ecs_cluster.go index 4de16d92968..c7f89963a9e 100644 --- a/aws/resource_aws_ecs_cluster.go +++ b/aws/resource_aws_ecs_cluster.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsEcsCluster() *schema.Resource { @@ -78,7 +79,7 @@ func resourceAwsEcsClusterCreate(d *schema.ResourceData, meta interface{}) error input := ecs.CreateClusterInput{ ClusterName: aws.String(clusterName), - Tags: tagsFromMapECS(d.Get("tags").(map[string]interface{})), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().EcsTags(), } if v, ok := d.GetOk("setting"); ok { @@ -89,9 +90,9 @@ func resourceAwsEcsClusterCreate(d *schema.ResourceData, meta interface{}) error if err != nil { return err } - log.Printf("[DEBUG] ECS cluster %s created", *out.Cluster.ClusterArn) + log.Printf("[DEBUG] ECS cluster %s created", aws.StringValue(out.Cluster.ClusterArn)) - d.SetId(*out.Cluster.ClusterArn) + d.SetId(aws.StringValue(out.Cluster.ClusterArn)) return resourceAwsEcsClusterRead(d, meta) } @@ -165,7 +166,7 @@ func resourceAwsEcsClusterRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting setting: %s", err) } - if err := d.Set("tags", tagsToMapECS(cluster.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.EcsKeyValueTags(cluster.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -188,38 +189,10 @@ func resourceAwsEcsClusterUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("tags") { - oldTagsRaw, newTagsRaw := d.GetChange("tags") - oldTagsMap := oldTagsRaw.(map[string]interface{}) - newTagsMap := newTagsRaw.(map[string]interface{}) - createTags, removeTags := diffTagsECS(tagsFromMapECS(oldTagsMap), tagsFromMapECS(newTagsMap)) - - if len(removeTags) > 0 { - removeTagKeys := make([]*string, len(removeTags)) - for i, removeTag := range removeTags { - removeTagKeys[i] = removeTag.Key - } - - input := &ecs.UntagResourceInput{ - ResourceArn: aws.String(d.Id()), - TagKeys: removeTagKeys, - } + o, n := d.GetChange("tags") - log.Printf("[DEBUG] Untagging ECS Cluster: %s", input) - if _, err := conn.UntagResource(input); err != nil { - return fmt.Errorf("error untagging ECS Cluster (%s): %s", d.Id(), err) - } - } - - if len(createTags) > 0 { - input := &ecs.TagResourceInput{ - ResourceArn: aws.String(d.Id()), - Tags: createTags, - } - - log.Printf("[DEBUG] Tagging ECS Cluster: %s", input) - if _, err := conn.TagResource(input); err != nil { - return fmt.Errorf("error tagging ECS Cluster (%s): %s", d.Id(), err) - } + if err := keyvaluetags.EcsUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating ECS Cluster (%s) tags: %s", d.Id(), err) } } diff --git a/aws/resource_aws_ecs_service.go b/aws/resource_aws_ecs_service.go index ae10d1f38f6..7eeb5d0861b 100644 --- a/aws/resource_aws_ecs_service.go +++ b/aws/resource_aws_ecs_service.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsEcsService() *schema.Resource { @@ -362,7 +363,7 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error DeploymentController: expandEcsDeploymentController(d.Get("deployment_controller").([]interface{})), SchedulingStrategy: aws.String(schedulingStrategy), ServiceName: aws.String(d.Get("name").(string)), - Tags: tagsFromMapECS(d.Get("tags").(map[string]interface{})), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().EcsTags(), TaskDefinition: aws.String(d.Get("task_definition").(string)), EnableECSManagedTags: aws.Bool(d.Get("enable_ecs_managed_tags").(bool)), } @@ -495,8 +496,8 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error service := *out.Service - log.Printf("[DEBUG] ECS service created: %s", *service.ServiceArn) - d.SetId(*service.ServiceArn) + log.Printf("[DEBUG] ECS service created: %s", aws.StringValue(service.ServiceArn)) + d.SetId(aws.StringValue(service.ServiceArn)) return resourceAwsEcsServiceRead(d, meta) } @@ -565,7 +566,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Received ECS service %s", service) - d.SetId(*service.ServiceArn) + d.SetId(aws.StringValue(service.ServiceArn)) d.Set("name", service.ServiceName) // Save task definition in the same format @@ -631,7 +632,7 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error setting service_registries for (%s): %s", d.Id(), err) } - if err := d.Set("tags", tagsToMapECS(service.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.EcsKeyValueTags(service.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -867,38 +868,10 @@ func resourceAwsEcsServiceUpdate(d *schema.ResourceData, meta interface{}) error } if d.HasChange("tags") { - oldTagsRaw, newTagsRaw := d.GetChange("tags") - oldTagsMap := oldTagsRaw.(map[string]interface{}) - newTagsMap := newTagsRaw.(map[string]interface{}) - createTags, removeTags := diffTagsECS(tagsFromMapECS(oldTagsMap), tagsFromMapECS(newTagsMap)) - - if len(removeTags) > 0 { - removeTagKeys := make([]*string, len(removeTags)) - for i, removeTag := range removeTags { - removeTagKeys[i] = removeTag.Key - } - - input := &ecs.UntagResourceInput{ - ResourceArn: aws.String(d.Id()), - TagKeys: removeTagKeys, - } + o, n := d.GetChange("tags") - log.Printf("[DEBUG] Untagging ECS Cluster: %s", input) - if _, err := conn.UntagResource(input); err != nil { - return fmt.Errorf("error untagging ECS Cluster (%s): %s", d.Id(), err) - } - } - - if len(createTags) > 0 { - input := &ecs.TagResourceInput{ - ResourceArn: aws.String(d.Id()), - Tags: createTags, - } - - log.Printf("[DEBUG] Tagging ECS Cluster: %s", input) - if _, err := conn.TagResource(input); err != nil { - return fmt.Errorf("error tagging ECS Cluster (%s): %s", d.Id(), err) - } + if err := keyvaluetags.EcsUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating ECS Service (%s) tags: %s", d.Id(), err) } } diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index da4dfdce311..f29925ec33e 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsEcsTaskDefinition() *schema.Resource { @@ -291,7 +292,7 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} // ClientException: Tags can not be empty. if v, ok := d.GetOk("tags"); ok { - input.Tags = tagsFromMapECS(v.(map[string]interface{})) + input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().EcsTags() } if v, ok := d.GetOk("task_role_arn"); ok { @@ -389,9 +390,9 @@ func resourceAwsEcsTaskDefinitionCreate(d *schema.ResourceData, meta interface{} taskDefinition := *out.TaskDefinition log.Printf("[DEBUG] ECS task definition registered: %q (rev. %d)", - *taskDefinition.TaskDefinitionArn, *taskDefinition.Revision) + aws.StringValue(taskDefinition.TaskDefinitionArn), aws.Int64Value(taskDefinition.Revision)) - d.SetId(*taskDefinition.Family) + d.SetId(aws.StringValue(taskDefinition.Family)) d.Set("arn", taskDefinition.TaskDefinitionArn) return resourceAwsEcsTaskDefinitionRead(d, meta) @@ -419,7 +420,7 @@ func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) return nil } - d.SetId(*taskDefinition.Family) + d.SetId(aws.StringValue(taskDefinition.Family)) d.Set("arn", taskDefinition.TaskDefinitionArn) d.Set("family", taskDefinition.Family) d.Set("revision", taskDefinition.Revision) @@ -439,7 +440,7 @@ func resourceAwsEcsTaskDefinitionRead(d *schema.ResourceData, meta interface{}) d.Set("memory", taskDefinition.Memory) d.Set("network_mode", taskDefinition.NetworkMode) - if err := d.Set("tags", tagsToMapECS(out.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.EcsKeyValueTags(out.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -502,38 +503,10 @@ func resourceAwsEcsTaskDefinitionUpdate(d *schema.ResourceData, meta interface{} conn := meta.(*AWSClient).ecsconn if d.HasChange("tags") { - oldTagsRaw, newTagsRaw := d.GetChange("tags") - oldTagsMap := oldTagsRaw.(map[string]interface{}) - newTagsMap := newTagsRaw.(map[string]interface{}) - createTags, removeTags := diffTagsECS(tagsFromMapECS(oldTagsMap), tagsFromMapECS(newTagsMap)) - - if len(removeTags) > 0 { - removeTagKeys := make([]*string, len(removeTags)) - for i, removeTag := range removeTags { - removeTagKeys[i] = removeTag.Key - } - - input := &ecs.UntagResourceInput{ - ResourceArn: aws.String(d.Get("arn").(string)), - TagKeys: removeTagKeys, - } + o, n := d.GetChange("tags") - log.Printf("[DEBUG] Untagging ECS Cluster: %s", input) - if _, err := conn.UntagResource(input); err != nil { - return fmt.Errorf("error untagging ECS Cluster (%s): %s", d.Get("arn").(string), err) - } - } - - if len(createTags) > 0 { - input := &ecs.TagResourceInput{ - ResourceArn: aws.String(d.Get("arn").(string)), - Tags: createTags, - } - - log.Printf("[DEBUG] Tagging ECS Cluster: %s", input) - if _, err := conn.TagResource(input); err != nil { - return fmt.Errorf("error tagging ECS Cluster (%s): %s", d.Get("arn").(string), err) - } + if err := keyvaluetags.EcsUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating ECS Task Definition (%s) tags: %s", d.Id(), err) } } diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 7ccfeaacbf9..3093a3c9404 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -161,8 +161,6 @@ func TestAccAWSEcsTaskDefinition_withTaskScopedDockerVolume(t *testing.T) { "aws_ecs_task_definition.sleep", "volume.584193650.docker_volume_configuration.#", "1"), resource.TestCheckResourceAttr( "aws_ecs_task_definition.sleep", "volume.584193650.docker_volume_configuration.0.scope", "task"), - resource.TestCheckResourceAttr( - "aws_ecs_task_definition.sleep", "volume.584193650.docker_volume_configuration.0.driver", "local"), ), }, }, diff --git a/aws/tagsECS.go b/aws/tagsECS.go deleted file mode 100644 index 67a924155ff..00000000000 --- a/aws/tagsECS.go +++ /dev/null @@ -1,78 +0,0 @@ -package aws - -import ( - "log" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" -) - -// diffTags takes our tags locally and the ones remotely and returns -// the set of tags that must be created, and the set of tags that must -// be destroyed. -func diffTagsECS(oldTags, newTags []*ecs.Tag) ([]*ecs.Tag, []*ecs.Tag) { - // First, we're creating everything we have - create := make(map[string]interface{}) - for _, t := range newTags { - create[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - - // Build the list of what to remove - var remove []*ecs.Tag - for _, t := range oldTags { - old, ok := create[aws.StringValue(t.Key)] - if !ok || old != aws.StringValue(t.Value) { - // Delete it! - remove = append(remove, t) - } else if ok { - // already present so remove from new - delete(create, aws.StringValue(t.Key)) - } - } - - return tagsFromMapECS(create), remove -} - -// tagsFromMap returns the tags for the given map of data. -func tagsFromMapECS(tagMap map[string]interface{}) []*ecs.Tag { - tags := make([]*ecs.Tag, 0, len(tagMap)) - for tagKey, tagValueRaw := range tagMap { - tag := &ecs.Tag{ - Key: aws.String(tagKey), - Value: aws.String(tagValueRaw.(string)), - } - if !tagIgnoredECS(tag) { - tags = append(tags, tag) - } - } - - return tags -} - -// tagsToMap turns the list of tags into a map. -func tagsToMapECS(tags []*ecs.Tag) map[string]string { - tagMap := make(map[string]string) - for _, tag := range tags { - if !tagIgnoredECS(tag) { - tagMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) - } - } - - return tagMap -} - -// compare a tag against a list of strings and checks if it should -// be ignored or not -func tagIgnoredECS(t *ecs.Tag) bool { - filter := []string{"^aws:"} - for _, v := range filter { - log.Printf("[DEBUG] Matching %v with %v\n", v, aws.StringValue(t.Key)) - r, _ := regexp.MatchString(v, aws.StringValue(t.Key)) - if r { - log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", aws.StringValue(t.Key), aws.StringValue(t.Value)) - return true - } - } - return false -} diff --git a/aws/tagsECS_test.go b/aws/tagsECS_test.go deleted file mode 100644 index cc9289df4a7..00000000000 --- a/aws/tagsECS_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package aws - -import ( - "reflect" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" -) - -func TestDiffECSTags(t *testing.T) { - cases := []struct { - Old, New map[string]interface{} - Create, Remove map[string]string - }{ - // Add - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - Create: map[string]string{ - "bar": "baz", - }, - Remove: map[string]string{}, - }, - - // Modify - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "baz", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Overlap - { - Old: map[string]interface{}{ - "foo": "bar", - "hello": "world", - }, - New: map[string]interface{}{ - "foo": "baz", - "hello": "world", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Remove - { - Old: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - New: map[string]interface{}{ - "foo": "bar", - }, - Create: map[string]string{}, - Remove: map[string]string{ - "bar": "baz", - }, - }, - } - - for i, tc := range cases { - c, r := diffTagsECS(tagsFromMapECS(tc.Old), tagsFromMapECS(tc.New)) - cm := tagsToMapECS(c) - rm := tagsToMapECS(r) - if !reflect.DeepEqual(cm, tc.Create) { - t.Fatalf("%d: bad create: %#v", i, cm) - } - if !reflect.DeepEqual(rm, tc.Remove) { - t.Fatalf("%d: bad remove: %#v", i, rm) - } - } -} - -func TestIgnoringTagsECS(t *testing.T) { - ignoredTags := []*ecs.Tag{ - { - Key: aws.String("aws:cloudformation:logical-id"), - Value: aws.String("foo"), - }, - { - Key: aws.String("aws:foo:bar"), - Value: aws.String("baz"), - }, - } - for _, tag := range ignoredTags { - if !tagIgnoredECS(tag) { - t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value) - } - } -} From 1bde9db668c194ba7679605b8523732ef76ebc9c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 15 Nov 2019 04:42:42 -0500 Subject: [PATCH 05/38] r/aws_efs_file_system: Support 7-day lifecycle management policy. (#10825) Output from acceptance testing: ``` --- PASS: TestAccAWSEFSFileSystem_kmsConfigurationWithoutEncryption (24.74s) --- PASS: TestAccAWSEFSFileSystem_lifecyclePolicy_removal (66.07s) --- PASS: TestAccAWSEFSFileSystem_ThroughputMode (72.03s) --- PASS: TestAccAWSEFSFileSystem_basic (81.67s) --- PASS: TestAccAWSEFSFileSystem_kmsKey (87.24s) --- PASS: TestAccAWSEFSFileSystem_ProvisionedThroughputInMibps (89.03s) --- PASS: TestAccAWSEFSFileSystem_lifecyclePolicy (91.89s) --- PASS: TestAccAWSEFSFileSystem_pagedTags (97.24s) --- PASS: TestAccAWSEFSFileSystem_lifecyclePolicy_update (133.01s) ``` --- aws/resource_aws_efs_file_system.go | 1 + website/docs/r/efs_file_system.html.markdown | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_efs_file_system.go b/aws/resource_aws_efs_file_system.go index 30edf28a711..c4c43cea32e 100644 --- a/aws/resource_aws_efs_file_system.go +++ b/aws/resource_aws_efs_file_system.go @@ -105,6 +105,7 @@ func resourceAwsEfsFileSystem() *schema.Resource { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringInSlice([]string{ + efs.TransitionToIARulesAfter7Days, efs.TransitionToIARulesAfter14Days, efs.TransitionToIARulesAfter30Days, efs.TransitionToIARulesAfter60Days, diff --git a/website/docs/r/efs_file_system.html.markdown b/website/docs/r/efs_file_system.html.markdown index 9fbc9428c11..8e9eda97d82 100644 --- a/website/docs/r/efs_file_system.html.markdown +++ b/website/docs/r/efs_file_system.html.markdown @@ -55,7 +55,7 @@ system creation. By default generated by Terraform. See [Elastic File System] ### Lifecycle Policy Arguments For **lifecycle_policy** the following attributes are supported: -* `transition_to_ia` - (Optional) Indicates how long it takes to transition files to the IA storage class. Valid values: `AFTER_14_DAYS`, `AFTER_30_DAYS`, `AFTER_60_DAYS`, or `AFTER_90_DAYS`. +* `transition_to_ia` - (Optional) Indicates how long it takes to transition files to the IA storage class. Valid values: `AFTER_7_DAYS`, `AFTER_14_DAYS`, `AFTER_30_DAYS`, `AFTER_60_DAYS`, or `AFTER_90_DAYS`. ## Attributes Reference From 39cfe25322ad951fb71c18abd14134caba2ec467 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 04:44:31 -0500 Subject: [PATCH 06/38] Update CHANGELOG for #10825 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffa94233870..aa0e85171bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ENHANCEMENTS: * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] +* resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] BUG FIXES: From dd80bb2844ec0f9686b3156cf4166dbffd6f67e3 Mon Sep 17 00:00:00 2001 From: Mike Dalrymple Date: Fri, 15 Nov 2019 02:32:03 -0800 Subject: [PATCH 07/38] docs/resource/aws_api_gateway_integration_response: Make response_templates a map expression (#10617) Running the current example with terraform 0.12, the plan will fail with "Error: Invalid argument name". Changing to a map expression by adding the `=` fixes the error. --- website/docs/r/api_gateway_integration_response.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/api_gateway_integration_response.html.markdown b/website/docs/r/api_gateway_integration_response.html.markdown index dba69bd664d..39f806030f5 100644 --- a/website/docs/r/api_gateway_integration_response.html.markdown +++ b/website/docs/r/api_gateway_integration_response.html.markdown @@ -55,7 +55,7 @@ resource "aws_api_gateway_integration_response" "MyDemoIntegrationResponse" { status_code = "${aws_api_gateway_method_response.response_200.status_code}" # Transforms the backend JSON response to XML - response_templates { + response_templates = { "application/xml" = < From 6389430ebf9b5dc6ed46ffd387cb7047a9cfa8cf Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 12:56:08 +0200 Subject: [PATCH 08/38] resource/aws_api_gateway_rest_api: Add tags argument and arn attribute (#10581) Output from acceptance testing: ``` --- PASS: TestAccAWSAPIGatewayRestApi_openapi (35.26s) --- PASS: TestAccAWSAPIGatewayRestApi_tags (66.82s) --- PASS: TestAccAWSAPIGatewayRestApi_api_key_source (67.18s) --- PASS: TestAccAWSAPIGatewayRestApi_policy (124.97s) --- PASS: TestAccAWSAPIGatewayRestApi_EndpointConfiguration_Private (171.00s) --- PASS: TestAccAWSAPIGatewayRestApi_EndpointConfiguration (270.16s) --- PASS: TestAccAWSAPIGatewayRestApi_disappears (389.77s) --- PASS: TestAccAWSAPIGatewayRestApi_basic (438.28s) ``` --- aws/resource_aws_api_gateway_rest_api.go | 39 +++- aws/resource_aws_api_gateway_rest_api_test.go | 198 +++++++++++++----- .../docs/r/api_gateway_rest_api.html.markdown | 2 + 3 files changed, 179 insertions(+), 60 deletions(-) diff --git a/aws/resource_aws_api_gateway_rest_api.go b/aws/resource_aws_api_gateway_rest_api.go index fac0cc06d52..71923f71da5 100644 --- a/aws/resource_aws_api_gateway_rest_api.go +++ b/aws/resource_aws_api_gateway_rest_api.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsApiGatewayRestApi() *schema.Resource { @@ -38,7 +39,11 @@ func resourceAwsApiGatewayRestApi() *schema.Resource { "api_key_source": { Type: schema.TypeString, Optional: true, - Default: "HEADER", + ValidateFunc: validation.StringInSlice([]string{ + apigateway.ApiKeySourceTypeAuthorizer, + apigateway.ApiKeySourceTypeHeader, + }, true), + Default: apigateway.ApiKeySourceTypeHeader, }, "policy": { @@ -105,6 +110,11 @@ func resourceAwsApiGatewayRestApi() *schema.Resource { }, }, }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), }, } } @@ -135,6 +145,10 @@ func resourceAwsApiGatewayRestApiCreate(d *schema.ResourceData, meta interface{} params.Policy = aws.String(v.(string)) } + if v, ok := d.GetOk("tags"); ok { + params.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().ApigatewayTags() + } + binaryMediaTypes, binaryMediaTypesOk := d.GetOk("binary_media_types") if binaryMediaTypesOk { params.BinaryMediaTypes = expandStringList(binaryMediaTypes.([]interface{})) @@ -221,14 +235,14 @@ func resourceAwsApiGatewayRestApiRead(d *schema.ResourceData, meta interface{}) d.Set("binary_media_types", api.BinaryMediaTypes) - arn := arn.ARN{ + execution_arn := arn.ARN{ Partition: meta.(*AWSClient).partition, Service: "execute-api", Region: meta.(*AWSClient).region, AccountID: meta.(*AWSClient).accountid, Resource: d.Id(), }.String() - d.Set("execution_arn", arn) + d.Set("execution_arn", execution_arn) if api.MinimumCompressionSize == nil { d.Set("minimum_compression_size", -1) @@ -243,6 +257,18 @@ func resourceAwsApiGatewayRestApiRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting endpoint_configuration: %s", err) } + if err := d.Set("tags", keyvaluetags.ApigatewayKeyValueTags(api.Tags).IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + rest_api_arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "apigateway", + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("/restapis/%s", d.Id()), + }.String() + d.Set("arn", rest_api_arn) + return nil } @@ -342,6 +368,13 @@ func resourceAwsApiGatewayRestApiUpdate(d *schema.ResourceData, meta interface{} conn := meta.(*AWSClient).apigateway log.Printf("[DEBUG] Updating API Gateway %s", d.Id()) + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.ApigatewayUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + if d.HasChange("body") { if body, ok := d.GetOk("body"); ok { log.Printf("[DEBUG] Updating API Gateway from OpenAPI spec: %s", d.Id()) diff --git a/aws/resource_aws_api_gateway_rest_api_test.go b/aws/resource_aws_api_gateway_rest_api_test.go index d576edf765c..4ea59bbcdc0 100644 --- a/aws/resource_aws_api_gateway_rest_api_test.go +++ b/aws/resource_aws_api_gateway_rest_api_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "testing" "time" @@ -64,6 +65,7 @@ func testSweepAPIGatewayRestApis(region string) error { func TestAccAWSAPIGatewayRestApi_basic(t *testing.T) { var conf apigateway.RestApi + resourceName := "aws_api_gateway_rest_api.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -73,21 +75,22 @@ func TestAccAWSAPIGatewayRestApi_basic(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &conf), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/restapis/+.`)), testAccCheckAWSAPIGatewayRestAPINameAttribute(&conf, "bar"), testAccCheckAWSAPIGatewayRestAPIMinimumCompressionSizeAttribute(&conf, 0), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "name", "bar"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "description", ""), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "api_key_source", "HEADER"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "minimum_compression_size", "0"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "created_date"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "execution_arn"), - resource.TestCheckNoResourceAttr("aws_api_gateway_rest_api.test", "binary_media_types"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "name", "bar"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "api_key_source", "HEADER"), + resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "0"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "execution_arn"), + resource.TestCheckNoResourceAttr(resourceName, "binary_media_types"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.#", "1"), ), }, { - ResourceName: "aws_api_gateway_rest_api.test", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -95,26 +98,75 @@ func TestAccAWSAPIGatewayRestApi_basic(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIUpdateConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &conf), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), testAccCheckAWSAPIGatewayRestAPINameAttribute(&conf, "test"), testAccCheckAWSAPIGatewayRestAPIDescriptionAttribute(&conf, "test"), testAccCheckAWSAPIGatewayRestAPIMinimumCompressionSizeAttribute(&conf, 10485760), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "name", "test"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "description", "test"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "minimum_compression_size", "10485760"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "created_date"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "execution_arn"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "binary_media_types.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "binary_media_types.0", "application/octet-stream"), + resource.TestCheckResourceAttr(resourceName, "name", "test"), + resource.TestCheckResourceAttr(resourceName, "description", "test"), + resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "10485760"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "execution_arn"), + resource.TestCheckResourceAttr(resourceName, "binary_media_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "binary_media_types.0", "application/octet-stream"), ), }, { Config: testAccAWSAPIGatewayRestAPIDisableCompressionConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &conf), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), testAccCheckAWSAPIGatewayRestAPIMinimumCompressionSizeAttributeIsNil(&conf), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "minimum_compression_size", "-1"), + resource.TestCheckResourceAttr(resourceName, "minimum_compression_size", "-1"), + ), + }, + }, + }) +} + +func TestAccAWSAPIGatewayRestApi_tags(t *testing.T) { + var conf apigateway.RestApi + resourceName := "aws_api_gateway_rest_api.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSAPIGatewayRestAPIDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSAPIGatewayRestAPIConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/restapis/+.`)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + { + Config: testAccAWSAPIGatewayRestAPIConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/restapis/+.`)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + + { + Config: testAccAWSAPIGatewayRestAPIConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), + testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/restapis/+.`)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, }, @@ -145,6 +197,7 @@ func TestAccAWSAPIGatewayRestApi_disappears(t *testing.T) { func TestAccAWSAPIGatewayRestApi_EndpointConfiguration(t *testing.T) { var restApi apigateway.RestApi rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_api_gateway_rest_api.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -154,14 +207,14 @@ func TestAccAWSAPIGatewayRestApi_EndpointConfiguration(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIConfig_EndpointConfiguration(rName, "REGIONAL"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &restApi), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.0", "REGIONAL"), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &restApi), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.0", "REGIONAL"), ), }, { - ResourceName: "aws_api_gateway_rest_api.test", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -169,10 +222,10 @@ func TestAccAWSAPIGatewayRestApi_EndpointConfiguration(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIConfig_Name(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &restApi), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.0", "REGIONAL"), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &restApi), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.0", "REGIONAL"), ), }, // Test updating endpoint type @@ -206,10 +259,10 @@ func TestAccAWSAPIGatewayRestApi_EndpointConfiguration(t *testing.T) { }, Config: testAccAWSAPIGatewayRestAPIConfig_EndpointConfiguration(rName, "EDGE"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &restApi), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.0", "EDGE"), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &restApi), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.0", "EDGE"), ), }, }, @@ -219,6 +272,7 @@ func TestAccAWSAPIGatewayRestApi_EndpointConfiguration(t *testing.T) { func TestAccAWSAPIGatewayRestApi_EndpointConfiguration_Private(t *testing.T) { var restApi apigateway.RestApi rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_api_gateway_rest_api.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -253,14 +307,14 @@ func TestAccAWSAPIGatewayRestApi_EndpointConfiguration_Private(t *testing.T) { }, Config: testAccAWSAPIGatewayRestAPIConfig_EndpointConfiguration(rName, "PRIVATE"), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &restApi), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.#", "1"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "endpoint_configuration.0.types.0", "PRIVATE"), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &restApi), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "endpoint_configuration.0.types.0", "PRIVATE"), ), }, { - ResourceName: "aws_api_gateway_rest_api.test", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, @@ -271,6 +325,8 @@ func TestAccAWSAPIGatewayRestApi_EndpointConfiguration_Private(t *testing.T) { func TestAccAWSAPIGatewayRestApi_api_key_source(t *testing.T) { expectedAPIKeySource := "HEADER" expectedUpdateAPIKeySource := "AUTHORIZER" + resourceName := "aws_api_gateway_rest_api.test" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -279,24 +335,24 @@ func TestAccAWSAPIGatewayRestApi_api_key_source(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIConfigWithAPIKeySource, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "api_key_source", expectedAPIKeySource), + resource.TestCheckResourceAttr(resourceName, "api_key_source", expectedAPIKeySource), ), }, { - ResourceName: "aws_api_gateway_rest_api.test", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, { Config: testAccAWSAPIGatewayRestAPIConfigWithUpdateAPIKeySource, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "api_key_source", expectedUpdateAPIKeySource), + resource.TestCheckResourceAttr(resourceName, "api_key_source", expectedUpdateAPIKeySource), ), }, { Config: testAccAWSAPIGatewayRestAPIConfig, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "api_key_source", expectedAPIKeySource), + resource.TestCheckResourceAttr(resourceName, "api_key_source", expectedAPIKeySource), ), }, }, @@ -304,8 +360,10 @@ func TestAccAWSAPIGatewayRestApi_api_key_source(t *testing.T) { } func TestAccAWSAPIGatewayRestApi_policy(t *testing.T) { + resourceName := "aws_api_gateway_rest_api.test" expectedPolicyText := `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"execute-api:Invoke","Resource":"*","Condition":{"IpAddress":{"aws:SourceIp":"123.123.123.123/32"}}}]}` expectedUpdatePolicyText := `{"Version":"2012-10-17","Statement":[{"Effect":"Deny","Principal":{"AWS":"*"},"Action":"execute-api:Invoke","Resource":"*"}]}` + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -314,24 +372,24 @@ func TestAccAWSAPIGatewayRestApi_policy(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIConfigWithPolicy, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "policy", expectedPolicyText), + resource.TestCheckResourceAttr(resourceName, "policy", expectedPolicyText), ), }, { - ResourceName: "aws_api_gateway_rest_api.test", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, { Config: testAccAWSAPIGatewayRestAPIConfigUpdatePolicy, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "policy", expectedUpdatePolicyText), + resource.TestCheckResourceAttr(resourceName, "policy", expectedUpdatePolicyText), ), }, { Config: testAccAWSAPIGatewayRestAPIConfig, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "policy", ""), + resource.TestCheckResourceAttr(resourceName, "policy", ""), ), }, }, @@ -340,6 +398,7 @@ func TestAccAWSAPIGatewayRestApi_policy(t *testing.T) { func TestAccAWSAPIGatewayRestApi_openapi(t *testing.T) { var conf apigateway.RestApi + resourceName := "aws_api_gateway_rest_api.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -349,18 +408,18 @@ func TestAccAWSAPIGatewayRestApi_openapi(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIConfigOpenAPI, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &conf), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), testAccCheckAWSAPIGatewayRestAPINameAttribute(&conf, "test"), testAccCheckAWSAPIGatewayRestAPIRoutes(&conf, []string{"/", "/test"}), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "name", "test"), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "description", ""), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "created_date"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "execution_arn"), - resource.TestCheckNoResourceAttr("aws_api_gateway_rest_api.test", "binary_media_types"), + resource.TestCheckResourceAttr(resourceName, "name", "test"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "execution_arn"), + resource.TestCheckNoResourceAttr(resourceName, "binary_media_types"), ), }, { - ResourceName: "aws_api_gateway_rest_api.test", + ResourceName: resourceName, ImportState: true, ImportStateVerify: true, ImportStateVerifyIgnore: []string{"body"}, @@ -368,12 +427,12 @@ func TestAccAWSAPIGatewayRestApi_openapi(t *testing.T) { { Config: testAccAWSAPIGatewayRestAPIUpdateConfigOpenAPI, Check: resource.ComposeTestCheckFunc( - testAccCheckAWSAPIGatewayRestAPIExists("aws_api_gateway_rest_api.test", &conf), + testAccCheckAWSAPIGatewayRestAPIExists(resourceName, &conf), testAccCheckAWSAPIGatewayRestAPINameAttribute(&conf, "test"), testAccCheckAWSAPIGatewayRestAPIRoutes(&conf, []string{"/", "/update"}), - resource.TestCheckResourceAttr("aws_api_gateway_rest_api.test", "name", "test"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "created_date"), - resource.TestCheckResourceAttrSet("aws_api_gateway_rest_api.test", "execution_arn"), + resource.TestCheckResourceAttr(resourceName, "name", "test"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "execution_arn"), ), }, }, @@ -550,6 +609,31 @@ resource "aws_api_gateway_rest_api" "test" { `, rName) } +func testAccAWSAPIGatewayRestAPIConfigTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_api_gateway_rest_api" "test" { + name = "%s" + + tags = { + %q = %q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSAPIGatewayRestAPIConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_api_gateway_rest_api" "test" { + name = "%s" + + tags = { + %q = %q + %q = %q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + const testAccAWSAPIGatewayRestAPIConfigWithAPIKeySource = ` resource "aws_api_gateway_rest_api" "test" { name = "bar" diff --git a/website/docs/r/api_gateway_rest_api.html.markdown b/website/docs/r/api_gateway_rest_api.html.markdown index da857979198..b46c7eca6dc 100644 --- a/website/docs/r/api_gateway_rest_api.html.markdown +++ b/website/docs/r/api_gateway_rest_api.html.markdown @@ -45,6 +45,7 @@ The following arguments are supported: * `body` - (Optional) An OpenAPI specification that defines the set of routes and integrations to create as part of the REST API. * `policy` - (Optional) JSON formatted policy document that controls access to the API Gateway. For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy) * `api_key_source` - (Optional) The source of the API key for requests. Valid values are HEADER (default) and AUTHORIZER. +* `tags` - (Optional) Key-value mapping of resource tags __Note__: If the `body` argument is provided, the OpenAPI specification will be used to configure the resources, methods and integrations for the Rest API. If this argument is provided, the following resources should not be managed as separate ones, as updates may cause manual resource updates to be overwritten: @@ -71,6 +72,7 @@ In addition to all arguments above, the following attributes are exported: * `execution_arn` - The execution ARN part to be used in [`lambda_permission`](/docs/providers/aws/r/lambda_permission.html)'s `source_arn` when allowing API Gateway to invoke a Lambda function, e.g. `arn:aws:execute-api:eu-west-2:123456789012:z4675bid1j`, which can be concatenated with allowed stage, method and resource path. +* `arn` - Amazon Resource Name (ARN) ## Import From 6bdfa6b764a050e2cf9034215378334e78575e1d Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 05:56:43 -0500 Subject: [PATCH 09/38] Update CHANGELOG for #10581 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa0e85171bc..b2fac1b6875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ENHANCEMENTS: +* resource/aws_api_gateway_rest_api: Add `tags` argument and `arn` attribute [GH-10581] * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] From e8fc2e608c12147ed6eee039bb6fcd484804f052 Mon Sep 17 00:00:00 2001 From: Alexander Pravdin Date: Fri, 15 Nov 2019 20:28:54 +0900 Subject: [PATCH 10/38] Add note for api_gateway_domain_name about implicit dependency on acm_certificate_validation (#10466) --- website/docs/r/api_gateway_domain_name.html.markdown | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/docs/r/api_gateway_domain_name.html.markdown b/website/docs/r/api_gateway_domain_name.html.markdown index 1178931316a..00d8a29aa37 100644 --- a/website/docs/r/api_gateway_domain_name.html.markdown +++ b/website/docs/r/api_gateway_domain_name.html.markdown @@ -29,6 +29,12 @@ the `regional_domain_name` attribute. ~> **Note:** API Gateway requires the use of AWS Certificate Manager (ACM) certificates instead of Identity and Access Management (IAM) certificates in regions that support ACM. Regions that support ACM can be found in the [Regions and Endpoints Documentation](https://docs.aws.amazon.com/general/latest/gr/rande.html#acm_region). To import an existing private key and certificate into ACM or request an ACM certificate, see the [`aws_acm_certificate` resource](/docs/providers/aws/r/acm_certificate.html). +~> **Note:** The `aws_api_gateway_domain_name` resource expects dependency on the `aws_acm_certificate_validation` as +only verified certificates can be used. This can be made either explicitly by adding the +`depends_on = [aws_acm_certificate_validation.cert]` attribute. Or implicitly by referring certificate ARN +from the validation resource where it will be available after the resource creation: +`regional_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn`. + ~> **Note:** All arguments including the private key will be stored in the raw state as plain-text. [Read more about sensitive data in state](/docs/state/sensitive-data.html). From e16f1dcfefcfb17b16f46a6df3688e964e4218eb Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 13:43:22 +0200 Subject: [PATCH 11/38] resource/aws_wafregional_web_acl: add tagging support + read after create (#10889) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegionalWebAcl_createGroup (40.08s) --- PASS: TestAccAWSWafRegionalWebAcl_noRules (45.42s) --- PASS: TestAccAWSWafRegionalWebAcl_basic (68.12s) --- PASS: TestAccAWSWafRegionalWebAcl_disappears (69.11s) --- PASS: TestAccAWSWafRegionalWebAcl_changeRules (70.15s) --- PASS: TestAccAWSWafRegionalWebAcl_tags (70.33s) --- PASS: TestAccAWSWafRegionalWebAcl_changeDefaultAction (76.21s) --- PASS: TestAccAWSWafRegionalWebAcl_createRateBased (85.54s) --- PASS: TestAccAWSWafRegionalWebAcl_changeNameForceNew (96.30s) --- PASS: TestAccAWSWafRegionalWebAcl_LoggingConfiguration (110.31s) ``` --- aws/resource_aws_wafregional_web_acl.go | 57 +++- aws/resource_aws_wafregional_web_acl_test.go | 317 +++++++++++------- .../docs/r/wafregional_web_acl.html.markdown | 1 + 3 files changed, 243 insertions(+), 132 deletions(-) diff --git a/aws/resource_aws_wafregional_web_acl.go b/aws/resource_aws_wafregional_web_acl.go index b23f26fa69a..8308b40f23f 100644 --- a/aws/resource_aws_wafregional_web_acl.go +++ b/aws/resource_aws_wafregional_web_acl.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/service/wafregional" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsWafRegionalWebAcl() *schema.Resource { @@ -140,6 +141,7 @@ func resourceAwsWafRegionalWebAcl() *schema.Resource { }, }, }, + "tags": tagsSchema(), }, } } @@ -147,6 +149,7 @@ func resourceAwsWafRegionalWebAcl() *schema.Resource { func resourceAwsWafRegionalWebAclCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).wafregionalconn region := meta.(*AWSClient).region + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().WafregionalTags() wr := newWafRegionalRetryer(conn, region) out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { @@ -157,6 +160,10 @@ func resourceAwsWafRegionalWebAclCreate(d *schema.ResourceData, meta interface{} Name: aws.String(d.Get("name").(string)), } + if len(tags) > 0 { + params.Tags = tags + } + return conn.CreateWebACL(params) }) if err != nil { @@ -176,10 +183,38 @@ func resourceAwsWafRegionalWebAclCreate(d *schema.ResourceData, meta interface{} Service: "waf-regional", }.String() } - // Set for update - d.Set("arn", webACLARN) - return resourceAwsWafRegionalWebAclUpdate(d, meta) + loggingConfiguration := d.Get("logging_configuration").([]interface{}) + + if len(loggingConfiguration) == 1 { + input := &waf.PutLoggingConfigurationInput{ + LoggingConfiguration: expandWAFRegionalLoggingConfiguration(loggingConfiguration, webACLARN), + } + + log.Printf("[DEBUG] Updating WAF Regional Web ACL (%s) Logging Configuration: %s", d.Id(), input) + if _, err := conn.PutLoggingConfiguration(input); err != nil { + return fmt.Errorf("error Updating WAF Regional Web ACL (%s) Logging Configuration: %s", d.Id(), err) + } + } + + rules := d.Get("rule").(*schema.Set).List() + if len(rules) > 0 { + wr := newWafRegionalRetryer(conn, region) + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateWebACLInput{ + ChangeToken: token, + DefaultAction: expandWafAction(d.Get("default_action").([]interface{})), + Updates: diffWafWebAclRules([]interface{}{}, rules), + WebACLId: aws.String(d.Id()), + } + return conn.UpdateWebACL(req) + }) + if err != nil { + return fmt.Errorf("Error Updating WAF Regional ACL: %s", err) + } + } + + return resourceAwsWafRegionalWebAclRead(d, meta) } func resourceAwsWafRegionalWebAclRead(d *schema.ResourceData, meta interface{}) error { @@ -227,6 +262,14 @@ func resourceAwsWafRegionalWebAclRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("error setting rule: %s", err) } + tags, err := keyvaluetags.WafregionalListTags(conn, webACLARN) + if err != nil { + return fmt.Errorf("error listing tags for WAF Regional ACL (%s): %s", webACLARN, err) + } + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + getLoggingConfigurationInput := &waf.GetLoggingConfigurationInput{ ResourceArn: aws.String(d.Get("arn").(string)), } @@ -297,6 +340,14 @@ func resourceAwsWafRegionalWebAclUpdate(d *schema.ResourceData, meta interface{} } } + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.WafregionalUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + return resourceAwsWafRegionalWebAclRead(d, meta) } diff --git a/aws/resource_aws_wafregional_web_acl_test.go b/aws/resource_aws_wafregional_web_acl_test.go index 9fecc6b533a..0373989ff77 100644 --- a/aws/resource_aws_wafregional_web_acl_test.go +++ b/aws/resource_aws_wafregional_web_acl_test.go @@ -131,18 +131,12 @@ func TestAccAWSWafRegionalWebAcl_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "waf-regional", regexp.MustCompile(`webacl/.+`)), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "logging_configuration.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "logging_configuration.#", "0"), ), }, { @@ -154,6 +148,50 @@ func TestAccAWSWafRegionalWebAcl_basic(t *testing.T) { }) } +func TestAccAWSWafRegionalWebAcl_tags(t *testing.T) { + var v waf.WebACL + wafAclName := fmt.Sprintf("wafacl%s", acctest.RandString(5)) + resourceName := "aws_wafregional_web_acl.waf_acl" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalWebAclDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalWebAclConfigTags1(wafAclName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSWafRegionalWebAclConfigTags2(wafAclName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSWafRegionalWebAclConfigTags1(wafAclName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccAWSWafRegionalWebAcl_createRateBased(t *testing.T) { var v waf.WebACL wafAclName := fmt.Sprintf("wafacl%s", acctest.RandString(5)) @@ -168,16 +206,11 @@ func TestAccAWSWafRegionalWebAcl_createRateBased(t *testing.T) { Config: testAccAWSWafRegionalWebAclConfigRateBased(wafAclName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclName), ), }, }, @@ -198,16 +231,11 @@ func TestAccAWSWafRegionalWebAcl_createGroup(t *testing.T) { Config: testAccAWSWafRegionalWebAclConfigGroup(wafAclName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclName), ), }, { @@ -234,32 +262,22 @@ func TestAccAWSWafRegionalWebAcl_changeNameForceNew(t *testing.T) { Config: testAccAWSWafRegionalWebAclConfig(wafAclName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &before), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclName), ), }, { Config: testAccAWSWafRegionalWebAclConfig_changeName(wafAclNewName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &after), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclNewName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclNewName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclNewName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclNewName), ), }, { @@ -286,32 +304,22 @@ func TestAccAWSWafRegionalWebAcl_changeDefaultAction(t *testing.T) { Config: testAccAWSWafRegionalWebAclConfig(wafAclName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &before), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclName), ), }, { Config: testAccAWSWafRegionalWebAclConfig_changeDefaultAction(wafAclNewName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &after), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "BLOCK"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclNewName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafAclNewName), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "BLOCK"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclNewName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafAclNewName), ), }, { @@ -359,14 +367,10 @@ func TestAccAWSWafRegionalWebAcl_noRules(t *testing.T) { Config: testAccAWSWafRegionalWebAclConfig_noRules(wafAclName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), ), }, { @@ -395,14 +399,10 @@ func TestAccAWSWafRegionalWebAcl_changeRules(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRuleExists("aws_wafregional_rule.wafrule", &r), testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), computeWafRegionalWebAclRuleIndex(&r.RuleId, 1, "REGULAR", "BLOCK", &idx), testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.priority", &idx, "1"), ), @@ -411,14 +411,10 @@ func TestAccAWSWafRegionalWebAcl_changeRules(t *testing.T) { Config: testAccAWSWafRegionalWebAclConfig_changeRules(wafAclName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalWebAclExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "default_action.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "default_action.0.type", "ALLOW"), - resource.TestCheckResourceAttr( - resourceName, "name", wafAclName), - resource.TestCheckResourceAttr( - resourceName, "rule.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "ALLOW"), + resource.TestCheckResourceAttr(resourceName, "name", wafAclName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "2"), ), }, { @@ -602,13 +598,40 @@ func testAccCheckAWSWafRegionalWebAclExists(n string, v *waf.WebACL) resource.Te func testAccAWSWafRegionalWebAclConfig(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q +} + +resource "aws_wafregional_web_acl" "waf_acl" { + name = %[1]q + metric_name = %[1]q + + default_action { + type = "ALLOW" + } + + rule { + action { + type = "BLOCK" + } + + priority = 1 + rule_id = "${aws_wafregional_rule.wafrule.id}" + } +} +`, name) +} + +func testAccAWSWafRegionalWebAclConfigTags1(name, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_rule" "wafrule" { + name = %[1]q + metric_name = %[1]q } resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "ALLOW" @@ -622,23 +645,59 @@ resource "aws_wafregional_web_acl" "waf_acl" { priority = 1 rule_id = "${aws_wafregional_rule.wafrule.id}" } + + tags = { + %[2]q = %[3]q + } } -`, name, name, name, name) +`, name, tagKey1, tagValue1) +} + +func testAccAWSWafRegionalWebAclConfigTags2(name, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_rule" "wafrule" { + name = %[1]q + metric_name = %[1]q +} + +resource "aws_wafregional_web_acl" "waf_acl" { + name = %[1]q + metric_name = %[1]q + + default_action { + type = "ALLOW" + } + + rule { + action { + type = "BLOCK" + } + + priority = 1 + rule_id = "${aws_wafregional_rule.wafrule.id}" + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, name, tagKey1, tagValue1, tagKey2, tagValue2) } func testAccAWSWafRegionalWebAclConfigRateBased(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rate_based_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q rate_key = "IP" rate_limit = 2000 } resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "ALLOW" @@ -654,19 +713,19 @@ resource "aws_wafregional_web_acl" "waf_acl" { rule_id = "${aws_wafregional_rate_based_rule.wafrule.id}" } } -`, name, name, name, name) +`, name) } func testAccAWSWafRegionalWebAclConfigGroup(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rule_group" "wafrulegroup" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q } resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "ALLOW" @@ -682,19 +741,19 @@ resource "aws_wafregional_web_acl" "waf_acl" { rule_id = "${aws_wafregional_rule_group.wafrulegroup.id}" # todo } } -`, name, name, name, name) +`, name) } func testAccAWSWafRegionalWebAclConfig_changeName(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q } resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "ALLOW" @@ -709,19 +768,19 @@ resource "aws_wafregional_web_acl" "waf_acl" { rule_id = "${aws_wafregional_rule.wafrule.id}" } } -`, name, name, name, name) +`, name) } func testAccAWSWafRegionalWebAclConfig_changeDefaultAction(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q } resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "BLOCK" @@ -736,32 +795,32 @@ resource "aws_wafregional_web_acl" "waf_acl" { rule_id = "${aws_wafregional_rule.wafrule.id}" } } -`, name, name, name, name) +`, name) } func testAccAWSWafRegionalWebAclConfig_noRules(name string) string { return fmt.Sprintf(` resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "ALLOW" } } -`, name, name) +`, name) } func testAccAWSWafRegionalWebAclConfig_changeRules(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q } resource "aws_wafregional_web_acl" "waf_acl" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q default_action { type = "ALLOW" @@ -785,7 +844,7 @@ resource "aws_wafregional_web_acl" "waf_acl" { rule_id = "${aws_wafregional_rule.wafrule.id}" } } -`, name, name, name, name) +`, name) } func testAccAWSWafRegionalWebAclConfigLoggingConfiguration(rName string) string { diff --git a/website/docs/r/wafregional_web_acl.html.markdown b/website/docs/r/wafregional_web_acl.html.markdown index 3899775e402..90e2981be9c 100644 --- a/website/docs/r/wafregional_web_acl.html.markdown +++ b/website/docs/r/wafregional_web_acl.html.markdown @@ -112,6 +112,7 @@ The following arguments are supported: * `name` - (Required) The name or description of the web ACL. * `logging_configuration` - (Optional) Configuration block to enable WAF logging. Detailed below. * `rule` - (Optional) Set of configuration blocks containing rules for the web ACL. Detailed below. +* `tags` - (Optional) Key-value mapping of resource tags ### `default_action` Configuration Block From 0166daaa1a2fe13a273f9cd4914617ea4689c30a Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 06:44:09 -0500 Subject: [PATCH 12/38] Update CHANGELOG for #10889 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2fac1b6875..12580a8f012 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ENHANCEMENTS: * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] +* resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From 4bcbb6e90fab76aeca48cc8ede6c67575d1364fc Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 14:36:27 +0200 Subject: [PATCH 13/38] Add import support for aws_waf_geo_match_set resource (#10480) Output from acceptance testing: ``` --- PASS: TestAccAWSWafGeoMatchSet_disappears (11.70s) --- PASS: TestAccAWSWafGeoMatchSet_noConstraints (22.92s) --- PASS: TestAccAWSWafGeoMatchSet_changeNameForceNew (30.62s) --- PASS: TestAccAWSWafGeoMatchSet_changeConstraints (41.17s) --- PASS: TestAccAWSWafGeoMatchSet_basic (44.38s) ``` --- aws/resource_aws_waf_geo_match_set.go | 20 ++- aws/resource_aws_waf_geo_match_set_test.go | 115 +++++++++--------- .../docs/r/waf_geo_match_set.html.markdown | 9 ++ 3 files changed, 85 insertions(+), 59 deletions(-) diff --git a/aws/resource_aws_waf_geo_match_set.go b/aws/resource_aws_waf_geo_match_set.go index 86933b6eae8..6c99f9bad5f 100644 --- a/aws/resource_aws_waf_geo_match_set.go +++ b/aws/resource_aws_waf_geo_match_set.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -15,6 +16,9 @@ func resourceAwsWafGeoMatchSet() *schema.Resource { Read: resourceAwsWafGeoMatchSetRead, Update: resourceAwsWafGeoMatchSetUpdate, Delete: resourceAwsWafGeoMatchSetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": { @@ -22,6 +26,10 @@ func resourceAwsWafGeoMatchSet() *schema.Resource { Required: true, ForceNew: true, }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, "geo_match_constraint": { Type: schema.TypeSet, Optional: true, @@ -75,9 +83,7 @@ func resourceAwsWafGeoMatchSetRead(d *schema.ResourceData, meta interface{}) err resp, err := conn.GetGeoMatchSet(params) if err != nil { - // TODO: Replace with constant once it's available - // See https://github.com/aws/aws-sdk-go/issues/1856 - if isAWSErr(err, "WAFNonexistentItemException", "") { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { log.Printf("[WARN] WAF GeoMatchSet (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -89,6 +95,14 @@ func resourceAwsWafGeoMatchSetRead(d *schema.ResourceData, meta interface{}) err d.Set("name", resp.GeoMatchSet.Name) d.Set("geo_match_constraint", flattenWafGeoMatchConstraint(resp.GeoMatchSet.GeoMatchConstraints)) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "waf", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("geomatchset/%s", d.Id()), + } + d.Set("arn", arn.String()) + return nil } diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go index fd04c14fa98..c48ef971bfa 100644 --- a/aws/resource_aws_waf_geo_match_set_test.go +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -15,6 +16,7 @@ import ( func TestAccAWSWafGeoMatchSet_basic(t *testing.T) { var v waf.GeoMatchSet geoMatchSet := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_geo_match_set.geo_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -24,21 +26,21 @@ func TestAccAWSWafGeoMatchSet_basic(t *testing.T) { { Config: testAccAWSWafGeoMatchSetConfig(geoMatchSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &v), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "name", geoMatchSet), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.type", "Country"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.value", "US"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.type", "Country"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.value", "CA"), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &v), + testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`geomatchset/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", geoMatchSet), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.#", "2"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.384465307.type", "Country"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.384465307.value", "US"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.1991628426.type", "Country"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.1991628426.value", "CA"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -47,6 +49,7 @@ func TestAccAWSWafGeoMatchSet_changeNameForceNew(t *testing.T) { var before, after waf.GeoMatchSet geoMatchSet := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) geoMatchSetNewName := fmt.Sprintf("geoMatchSetNewName-%s", acctest.RandString(5)) + resourceName := "aws_waf_geo_match_set.geo_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -56,23 +59,24 @@ func TestAccAWSWafGeoMatchSet_changeNameForceNew(t *testing.T) { { Config: testAccAWSWafGeoMatchSetConfig(geoMatchSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "name", geoMatchSet), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", geoMatchSet), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.#", "2"), ), }, { Config: testAccAWSWafGeoMatchSetConfigChangeName(geoMatchSetNewName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "name", geoMatchSetNewName), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", geoMatchSetNewName), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.#", "2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -80,6 +84,7 @@ func TestAccAWSWafGeoMatchSet_changeNameForceNew(t *testing.T) { func TestAccAWSWafGeoMatchSet_disappears(t *testing.T) { var v waf.GeoMatchSet geoMatchSet := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_geo_match_set.geo_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -89,7 +94,7 @@ func TestAccAWSWafGeoMatchSet_disappears(t *testing.T) { { Config: testAccAWSWafGeoMatchSetConfig(geoMatchSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &v), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &v), testAccCheckAWSWafGeoMatchSetDisappears(&v), ), ExpectNonEmptyPlan: true, @@ -101,6 +106,7 @@ func TestAccAWSWafGeoMatchSet_disappears(t *testing.T) { func TestAccAWSWafGeoMatchSet_changeConstraints(t *testing.T) { var before, after waf.GeoMatchSet setName := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_geo_match_set.geo_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -110,39 +116,32 @@ func TestAccAWSWafGeoMatchSet_changeConstraints(t *testing.T) { { Config: testAccAWSWafGeoMatchSetConfig(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.type", "Country"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.value", "US"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.type", "Country"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.value", "CA"), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.#", "2"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.384465307.type", "Country"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.384465307.value", "US"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.1991628426.type", "Country"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.1991628426.value", "CA"), ), }, { Config: testAccAWSWafGeoMatchSetConfig_changeConstraints(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1174390936.type", "Country"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1174390936.value", "RU"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.4046309957.type", "Country"), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.4046309957.value", "CN"), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.#", "2"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.1174390936.type", "Country"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.1174390936.value", "RU"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.4046309957.type", "Country"), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.4046309957.value", "CN"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -150,6 +149,7 @@ func TestAccAWSWafGeoMatchSet_changeConstraints(t *testing.T) { func TestAccAWSWafGeoMatchSet_noConstraints(t *testing.T) { var ipset waf.GeoMatchSet setName := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_geo_match_set.geo_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -159,13 +159,16 @@ func TestAccAWSWafGeoMatchSet_noConstraints(t *testing.T) { { Config: testAccAWSWafGeoMatchSetConfig_noConstraints(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &ipset), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "0"), + testAccCheckAWSWafGeoMatchSetExists(resourceName, &ipset), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "geo_match_constraint.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -259,7 +262,7 @@ func testAccCheckAWSWafGeoMatchSetDestroy(s *terraform.State) error { } // Return nil if the GeoMatchSet is already destroyed - if isAWSErr(err, "WAFNonexistentItemException", "") { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { return nil } diff --git a/website/docs/r/waf_geo_match_set.html.markdown b/website/docs/r/waf_geo_match_set.html.markdown index a02daa818db..05c2e31fa12 100644 --- a/website/docs/r/waf_geo_match_set.html.markdown +++ b/website/docs/r/waf_geo_match_set.html.markdown @@ -53,3 +53,12 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF GeoMatchSet. +* `arn` - Amazon Resource Name (ARN) + +## Import + +WAF Geo Match Set can be imported using their ID, e.g. + +``` +$ terraform import aws_waf_geo_match_set.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` From 256099f4dc7cdc5d4f89decf4ba67c8d655e3cc4 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 07:37:18 -0500 Subject: [PATCH 14/38] Update CHANGELOG for #10480 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12580a8f012..ba10dcdba78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ENHANCEMENTS: * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] +* resource/aws_waf_geo_match_set: Support resource import [GH-10480] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From f598e22b51e4e58cd97fb3f8ff61d6d28c6b118d Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 14:38:54 +0200 Subject: [PATCH 15/38] Add import support for aws_waf_regex_match_set resource (#10481) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegexMatchSet (74.73s) ``` --- aws/resource_aws_waf_regex_match_set.go | 18 ++++- aws/resource_aws_waf_regex_match_set_test.go | 73 ++++++++++++------- .../docs/r/waf_regex_match_set.html.markdown | 9 +++ 3 files changed, 73 insertions(+), 27 deletions(-) diff --git a/aws/resource_aws_waf_regex_match_set.go b/aws/resource_aws_waf_regex_match_set.go index 0806319f867..af8ef7ff054 100644 --- a/aws/resource_aws_waf_regex_match_set.go +++ b/aws/resource_aws_waf_regex_match_set.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -16,6 +17,9 @@ func resourceAwsWafRegexMatchSet() *schema.Resource { Read: resourceAwsWafRegexMatchSetRead, Update: resourceAwsWafRegexMatchSetUpdate, Delete: resourceAwsWafRegexMatchSetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": { @@ -23,6 +27,10 @@ func resourceAwsWafRegexMatchSet() *schema.Resource { Required: true, ForceNew: true, }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, "regex_match_tuple": { Type: schema.TypeSet, Optional: true, @@ -96,7 +104,7 @@ func resourceAwsWafRegexMatchSetRead(d *schema.ResourceData, meta interface{}) e resp, err := conn.GetRegexMatchSet(params) if err != nil { - if isAWSErr(err, "WAFNonexistentItemException", "") { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { log.Printf("[WARN] WAF Regex Match Set (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -108,6 +116,14 @@ func resourceAwsWafRegexMatchSetRead(d *schema.ResourceData, meta interface{}) e d.Set("name", resp.RegexMatchSet.Name) d.Set("regex_match_tuple", flattenWafRegexMatchTuples(resp.RegexMatchSet.RegexMatchTuples)) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "waf", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("regexmatchset/%s", d.Id()), + } + d.Set("arn", arn.String()) + return nil } diff --git a/aws/resource_aws_waf_regex_match_set_test.go b/aws/resource_aws_waf_regex_match_set_test.go index d4ecb252104..e5ccc50ae32 100644 --- a/aws/resource_aws_waf_regex_match_set_test.go +++ b/aws/resource_aws_waf_regex_match_set_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -99,6 +100,7 @@ func testAccAWSWafRegexMatchSet_basic(t *testing.T) { matchSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_match_set.test" fieldToMatch := waf.FieldToMatch{ Data: aws.String("User-Agent"), @@ -113,17 +115,23 @@ func testAccAWSWafRegexMatchSet_basic(t *testing.T) { { Config: testAccAWSWafRegexMatchSetConfig(matchSetName, patternSetName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafRegexMatchSetExists("aws_waf_regex_match_set.test", &matchSet), + testAccCheckAWSWafRegexMatchSetExists(resourceName, &matchSet), testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &patternSet), + testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`regexmatchset/.+`)), computeWafRegexMatchSetTuple(&patternSet, &fieldToMatch, "NONE", &idx), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "name", matchSetName), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "regex_match_tuple.#", "1"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.#", &idx, "1"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.0.data", &idx, "user-agent"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.0.type", &idx, "HEADER"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.text_transformation", &idx, "NONE"), + resource.TestCheckResourceAttr(resourceName, "name", matchSetName), + resource.TestCheckResourceAttr(resourceName, "regex_match_tuple.#", "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.#", &idx, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.0.data", &idx, "user-agent"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.0.type", &idx, "HEADER"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.text_transformation", &idx, "NONE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -135,6 +143,7 @@ func testAccAWSWafRegexMatchSet_changePatterns(t *testing.T) { matchSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_match_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -144,31 +153,36 @@ func testAccAWSWafRegexMatchSet_changePatterns(t *testing.T) { { Config: testAccAWSWafRegexMatchSetConfig(matchSetName, patternSetName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafRegexMatchSetExists("aws_waf_regex_match_set.test", &before), + testAccCheckAWSWafRegexMatchSetExists(resourceName, &before), testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &patternSet), computeWafRegexMatchSetTuple(&patternSet, &waf.FieldToMatch{Data: aws.String("User-Agent"), Type: aws.String("HEADER")}, "NONE", &idx1), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "name", matchSetName), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "regex_match_tuple.#", "1"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.#", &idx1, "1"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.0.data", &idx1, "user-agent"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.0.type", &idx1, "HEADER"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.text_transformation", &idx1, "NONE"), + resource.TestCheckResourceAttr(resourceName, "name", matchSetName), + resource.TestCheckResourceAttr(resourceName, "regex_match_tuple.#", "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.#", &idx1, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.0.data", &idx1, "user-agent"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.0.type", &idx1, "HEADER"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.text_transformation", &idx1, "NONE"), ), }, { Config: testAccAWSWafRegexMatchSetConfig_changePatterns(matchSetName, patternSetName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafRegexMatchSetExists("aws_waf_regex_match_set.test", &after), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "name", matchSetName), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "regex_match_tuple.#", "1"), + testAccCheckAWSWafRegexMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", matchSetName), + resource.TestCheckResourceAttr(resourceName, "regex_match_tuple.#", "1"), computeWafRegexMatchSetTuple(&patternSet, &waf.FieldToMatch{Data: aws.String("Referer"), Type: aws.String("HEADER")}, "COMPRESS_WHITE_SPACE", &idx2), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.#", &idx2, "1"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.0.data", &idx2, "referer"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.field_to_match.0.type", &idx2, "HEADER"), - testCheckResourceAttrWithIndexesAddr("aws_waf_regex_match_set.test", "regex_match_tuple.%d.text_transformation", &idx2, "COMPRESS_WHITE_SPACE"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.#", &idx2, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.0.data", &idx2, "referer"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.field_to_match.0.type", &idx2, "HEADER"), + testCheckResourceAttrWithIndexesAddr(resourceName, "regex_match_tuple.%d.text_transformation", &idx2, "COMPRESS_WHITE_SPACE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -176,6 +190,7 @@ func testAccAWSWafRegexMatchSet_changePatterns(t *testing.T) { func testAccAWSWafRegexMatchSet_noPatterns(t *testing.T) { var matchSet waf.RegexMatchSet matchSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_match_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -185,11 +200,16 @@ func testAccAWSWafRegexMatchSet_noPatterns(t *testing.T) { { Config: testAccAWSWafRegexMatchSetConfig_noPatterns(matchSetName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafRegexMatchSetExists("aws_waf_regex_match_set.test", &matchSet), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "name", matchSetName), - resource.TestCheckResourceAttr("aws_waf_regex_match_set.test", "regex_match_tuple.#", "0"), + testAccCheckAWSWafRegexMatchSetExists(resourceName, &matchSet), + resource.TestCheckResourceAttr(resourceName, "name", matchSetName), + resource.TestCheckResourceAttr(resourceName, "regex_match_tuple.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -198,6 +218,7 @@ func testAccAWSWafRegexMatchSet_disappears(t *testing.T) { var matchSet waf.RegexMatchSet matchSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_match_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -207,7 +228,7 @@ func testAccAWSWafRegexMatchSet_disappears(t *testing.T) { { Config: testAccAWSWafRegexMatchSetConfig(matchSetName, patternSetName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafRegexMatchSetExists("aws_waf_regex_match_set.test", &matchSet), + testAccCheckAWSWafRegexMatchSetExists(resourceName, &matchSet), testAccCheckAWSWafRegexMatchSetDisappears(&matchSet), ), ExpectNonEmptyPlan: true, @@ -316,7 +337,7 @@ func testAccCheckAWSWafRegexMatchSetDestroy(s *terraform.State) error { } // Return nil if the Regex Pattern Set is already destroyed - if isAWSErr(err, "WAFNonexistentItemException", "") { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { return nil } diff --git a/website/docs/r/waf_regex_match_set.html.markdown b/website/docs/r/waf_regex_match_set.html.markdown index b43b798f9e5..fad1c7ed18c 100644 --- a/website/docs/r/waf_regex_match_set.html.markdown +++ b/website/docs/r/waf_regex_match_set.html.markdown @@ -66,3 +66,12 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF Regex Match Set. +* `arn` - Amazon Resource Name (ARN) + +## Import + +WAF Regex Match Set can be imported using their ID, e.g. + +``` +$ terraform import aws_waf_regex_match_set.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` \ No newline at end of file From c10f705bc42d0559f66a6fa46ad896a6b7a0f975 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 07:39:37 -0500 Subject: [PATCH 16/38] Update CHANGELOG for #10481 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba10dcdba78..3e9a47fab02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ENHANCEMENTS: * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] * resource/aws_waf_geo_match_set: Support resource import [GH-10480] +* resource/aws_waf_regex_match_set: Support resource import [GH-10481] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From e4864de80232a7d86bf8f9194fd27ad51552af87 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 14:41:03 +0200 Subject: [PATCH 17/38] Add import support for aws_waf_regex_pattern_set resource (#10482) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegexPatternSet (56.62s) ``` --- aws/resource_aws_waf_regex_pattern_set.go | 20 +++++- ...resource_aws_waf_regex_pattern_set_test.go | 63 ++++++++++++------- .../r/waf_regex_pattern_set.html.markdown | 9 +++ 3 files changed, 68 insertions(+), 24 deletions(-) diff --git a/aws/resource_aws_waf_regex_pattern_set.go b/aws/resource_aws_waf_regex_pattern_set.go index e7e247eaccf..0767255f221 100644 --- a/aws/resource_aws_waf_regex_pattern_set.go +++ b/aws/resource_aws_waf_regex_pattern_set.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) @@ -15,6 +16,9 @@ func resourceAwsWafRegexPatternSet() *schema.Resource { Read: resourceAwsWafRegexPatternSetRead, Update: resourceAwsWafRegexPatternSetUpdate, Delete: resourceAwsWafRegexPatternSetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": { @@ -22,6 +26,10 @@ func resourceAwsWafRegexPatternSet() *schema.Resource { Required: true, ForceNew: true, }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, "regex_pattern_strings": { Type: schema.TypeSet, Optional: true, @@ -63,9 +71,7 @@ func resourceAwsWafRegexPatternSetRead(d *schema.ResourceData, meta interface{}) resp, err := conn.GetRegexPatternSet(params) if err != nil { - // TODO: Replace with a constant once available - // See https://github.com/aws/aws-sdk-go/issues/1856 - if isAWSErr(err, "WAFNonexistentItemException", "") { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { log.Printf("[WARN] WAF Regex Pattern Set (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -77,6 +83,14 @@ func resourceAwsWafRegexPatternSetRead(d *schema.ResourceData, meta interface{}) d.Set("name", resp.RegexPatternSet.Name) d.Set("regex_pattern_strings", aws.StringValueSlice(resp.RegexPatternSet.RegexPatternStrings)) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "waf", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("regexpatternset/%s", d.Id()), + } + d.Set("arn", arn.String()) + return nil } diff --git a/aws/resource_aws_waf_regex_pattern_set_test.go b/aws/resource_aws_waf_regex_pattern_set_test.go index 8be45a0332d..d8214b62c56 100644 --- a/aws/resource_aws_waf_regex_pattern_set_test.go +++ b/aws/resource_aws_waf_regex_pattern_set_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -32,6 +33,7 @@ func TestAccAWSWafRegexPatternSet(t *testing.T) { func testAccAWSWafRegexPatternSet_basic(t *testing.T) { var v waf.RegexPatternSet patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_pattern_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -41,13 +43,19 @@ func testAccAWSWafRegexPatternSet_basic(t *testing.T) { { Config: testAccAWSWafRegexPatternSetConfig(patternSetName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &v), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "name", patternSetName), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.#", "2"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.2848565413", "one"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.3351840846", "two"), + testAccCheckAWSWafRegexPatternSetExists(resourceName, &v), + testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`regexpatternset/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", patternSetName), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.#", "2"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.2848565413", "one"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.3351840846", "two"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -55,6 +63,7 @@ func testAccAWSWafRegexPatternSet_basic(t *testing.T) { func testAccAWSWafRegexPatternSet_changePatterns(t *testing.T) { var before, after waf.RegexPatternSet patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_pattern_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -64,24 +73,29 @@ func testAccAWSWafRegexPatternSet_changePatterns(t *testing.T) { { Config: testAccAWSWafRegexPatternSetConfig(patternSetName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &before), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "name", patternSetName), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.#", "2"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.2848565413", "one"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.3351840846", "two"), + testAccCheckAWSWafRegexPatternSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", patternSetName), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.#", "2"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.2848565413", "one"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.3351840846", "two"), ), }, { Config: testAccAWSWafRegexPatternSetConfig_changePatterns(patternSetName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &after), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "name", patternSetName), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.#", "3"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.3351840846", "two"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.2929247714", "three"), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.1294846542", "four"), + testAccCheckAWSWafRegexPatternSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", patternSetName), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.#", "3"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.3351840846", "two"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.2929247714", "three"), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.1294846542", "four"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -89,6 +103,7 @@ func testAccAWSWafRegexPatternSet_changePatterns(t *testing.T) { func testAccAWSWafRegexPatternSet_noPatterns(t *testing.T) { var patternSet waf.RegexPatternSet patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_pattern_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -98,11 +113,16 @@ func testAccAWSWafRegexPatternSet_noPatterns(t *testing.T) { { Config: testAccAWSWafRegexPatternSetConfig_noPatterns(patternSetName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &patternSet), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "name", patternSetName), - resource.TestCheckResourceAttr("aws_waf_regex_pattern_set.test", "regex_pattern_strings.#", "0"), + testAccCheckAWSWafRegexPatternSetExists(resourceName, &patternSet), + resource.TestCheckResourceAttr(resourceName, "name", patternSetName), + resource.TestCheckResourceAttr(resourceName, "regex_pattern_strings.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -110,6 +130,7 @@ func testAccAWSWafRegexPatternSet_noPatterns(t *testing.T) { func testAccAWSWafRegexPatternSet_disappears(t *testing.T) { var v waf.RegexPatternSet patternSetName := fmt.Sprintf("tfacc-%s", acctest.RandString(5)) + resourceName := "aws_waf_regex_pattern_set.test" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -119,7 +140,7 @@ func testAccAWSWafRegexPatternSet_disappears(t *testing.T) { { Config: testAccAWSWafRegexPatternSetConfig(patternSetName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafRegexPatternSetExists("aws_waf_regex_pattern_set.test", &v), + testAccCheckAWSWafRegexPatternSetExists(resourceName, &v), testAccCheckAWSWafRegexPatternSetDisappears(&v), ), ExpectNonEmptyPlan: true, @@ -215,7 +236,7 @@ func testAccCheckAWSWafRegexPatternSetDestroy(s *terraform.State) error { } // Return nil if the Regex Pattern Set is already destroyed - if isAWSErr(err, "WAFNonexistentItemException", "") { + if isAWSErr(err, waf.ErrCodeNonexistentItemException, "") { return nil } diff --git a/website/docs/r/waf_regex_pattern_set.html.markdown b/website/docs/r/waf_regex_pattern_set.html.markdown index b0625705aad..4b41feb3117 100644 --- a/website/docs/r/waf_regex_pattern_set.html.markdown +++ b/website/docs/r/waf_regex_pattern_set.html.markdown @@ -31,3 +31,12 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF Regex Pattern Set. +* `arn` - Amazon Resource Name (ARN) + +## Import + +AWS WAF Regex Pattern Set can be imported using their ID, e.g. + +``` +$ terraform import aws_waf_regex_pattern_set.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` From 51c3f1a452140146edf7709dcc3c064089cbb72d Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 07:41:55 -0500 Subject: [PATCH 18/38] Update CHANGELOG for #10482 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9a47fab02..0a1f1b68322 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ENHANCEMENTS: * resource/aws_glue_crawler: Add `tags` argument [GH-10805] * resource/aws_waf_geo_match_set: Support resource import [GH-10480] * resource/aws_waf_regex_match_set: Support resource import [GH-10481] +* resource/aws_waf_regex_pattern_set: Support resource import [GH-10482] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From 428699f5c442f40a27590af5a81a41d931e37d23 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 14:43:30 +0200 Subject: [PATCH 19/38] Add import support for aws_waf_size_constraint_set resource (#10484) Output from acceptance testing: ``` --- PASS: TestAccAWSWafSizeConstraintSet_noConstraints (13.57s) --- PASS: TestAccAWSWafSizeConstraintSet_disappears (21.97s) --- PASS: TestAccAWSWafSizeConstraintSet_basic (25.21s) --- PASS: TestAccAWSWafSizeConstraintSet_changeConstraints (29.52s) --- PASS: TestAccAWSWafSizeConstraintSet_changeNameForceNew (54.31s) ``` --- aws/resource_aws_waf_size_constraint_set.go | 14 +- ...source_aws_waf_size_constraint_set_test.go | 133 +++++++++--------- aws/waf_helpers.go | 5 +- .../r/waf_size_constraint_set.html.markdown | 9 ++ 4 files changed, 91 insertions(+), 70 deletions(-) diff --git a/aws/resource_aws_waf_size_constraint_set.go b/aws/resource_aws_waf_size_constraint_set.go index deb78c7a965..f14ee9ddb52 100644 --- a/aws/resource_aws_waf_size_constraint_set.go +++ b/aws/resource_aws_waf_size_constraint_set.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -16,6 +17,9 @@ func resourceAwsWafSizeConstraintSet() *schema.Resource { Read: resourceAwsWafSizeConstraintSetRead, Update: resourceAwsWafSizeConstraintSetUpdate, Delete: resourceAwsWafSizeConstraintSetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: wafSizeConstraintSetSchema(), } @@ -54,7 +58,7 @@ func resourceAwsWafSizeConstraintSetRead(d *schema.ResourceData, meta interface{ resp, err := conn.GetSizeConstraintSet(params) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == waf.ErrCodeNonexistentItemException { log.Printf("[WARN] WAF SizeConstraintSet (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -66,6 +70,14 @@ func resourceAwsWafSizeConstraintSetRead(d *schema.ResourceData, meta interface{ d.Set("name", resp.SizeConstraintSet.Name) d.Set("size_constraints", flattenWafSizeConstraints(resp.SizeConstraintSet.SizeConstraints)) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "waf", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("sizeconstraintset/%s", d.Id()), + } + d.Set("arn", arn.String()) + return nil } diff --git a/aws/resource_aws_waf_size_constraint_set_test.go b/aws/resource_aws_waf_size_constraint_set_test.go index 374793a5185..a506cc44d87 100644 --- a/aws/resource_aws_waf_size_constraint_set_test.go +++ b/aws/resource_aws_waf_size_constraint_set_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -16,6 +17,7 @@ import ( func TestAccAWSWafSizeConstraintSet_basic(t *testing.T) { var v waf.SizeConstraintSet sizeConstraintSet := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_size_constraint_set.size_constraint_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -25,25 +27,23 @@ func TestAccAWSWafSizeConstraintSet_basic(t *testing.T) { { Config: testAccAWSWafSizeConstraintSetConfig(sizeConstraintSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &v), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "name", sizeConstraintSet), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.comparison_operator", "EQ"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.type", "BODY"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.size", "4096"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.text_transformation", "NONE"), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &v), + testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`sizeconstraintset/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", sizeConstraintSet), + resource.TestCheckResourceAttr(resourceName, "size_constraints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.comparison_operator", "EQ"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.size", "4096"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.text_transformation", "NONE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -52,6 +52,7 @@ func TestAccAWSWafSizeConstraintSet_changeNameForceNew(t *testing.T) { var before, after waf.SizeConstraintSet sizeConstraintSet := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) sizeConstraintSetNewName := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_size_constraint_set.size_constraint_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -61,23 +62,24 @@ func TestAccAWSWafSizeConstraintSet_changeNameForceNew(t *testing.T) { { Config: testAccAWSWafSizeConstraintSetConfig(sizeConstraintSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "name", sizeConstraintSet), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", sizeConstraintSet), + resource.TestCheckResourceAttr(resourceName, "size_constraints.#", "1"), ), }, { Config: testAccAWSWafSizeConstraintSetConfigChangeName(sizeConstraintSetNewName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "name", sizeConstraintSetNewName), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", sizeConstraintSetNewName), + resource.TestCheckResourceAttr(resourceName, "size_constraints.#", "1"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -85,6 +87,7 @@ func TestAccAWSWafSizeConstraintSet_changeNameForceNew(t *testing.T) { func TestAccAWSWafSizeConstraintSet_disappears(t *testing.T) { var v waf.SizeConstraintSet sizeConstraintSet := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_size_constraint_set.size_constraint_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -94,7 +97,7 @@ func TestAccAWSWafSizeConstraintSet_disappears(t *testing.T) { { Config: testAccAWSWafSizeConstraintSetConfig(sizeConstraintSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &v), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &v), testAccCheckAWSWafSizeConstraintSetDisappears(&v), ), ExpectNonEmptyPlan: true, @@ -106,6 +109,7 @@ func TestAccAWSWafSizeConstraintSet_disappears(t *testing.T) { func TestAccAWSWafSizeConstraintSet_changeConstraints(t *testing.T) { var before, after waf.SizeConstraintSet setName := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_size_constraint_set.size_constraint_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -115,47 +119,36 @@ func TestAccAWSWafSizeConstraintSet_changeConstraints(t *testing.T) { { Config: testAccAWSWafSizeConstraintSetConfig(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.comparison_operator", "EQ"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.type", "BODY"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.size", "4096"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.text_transformation", "NONE"), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "size_constraints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.comparison_operator", "EQ"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.size", "4096"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.2029852522.text_transformation", "NONE"), ), }, { Config: testAccAWSWafSizeConstraintSetConfig_changeConstraints(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.comparison_operator", "GE"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.field_to_match.281401076.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.field_to_match.281401076.type", "BODY"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.size", "1024"), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.text_transformation", "NONE"), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "size_constraints.#", "1"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.3222308386.comparison_operator", "GE"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.3222308386.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.3222308386.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr(resourceName, "size_constraints.3222308386.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.3222308386.size", "1024"), + resource.TestCheckResourceAttr(resourceName, "size_constraints.3222308386.text_transformation", "NONE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -163,6 +156,7 @@ func TestAccAWSWafSizeConstraintSet_changeConstraints(t *testing.T) { func TestAccAWSWafSizeConstraintSet_noConstraints(t *testing.T) { var contraints waf.SizeConstraintSet setName := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_size_constraint_set.size_constraint_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -172,13 +166,16 @@ func TestAccAWSWafSizeConstraintSet_noConstraints(t *testing.T) { { Config: testAccAWSWafSizeConstraintSetConfig_noConstraints(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &contraints), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "0"), + testAccCheckAWSWafSizeConstraintSetExists(resourceName, &contraints), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "size_constraints.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -273,7 +270,7 @@ func testAccCheckAWSWafSizeConstraintSetDestroy(s *terraform.State) error { // Return nil if the SizeConstraintSet is already destroyed if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "WAFNonexistentItemException" { + if awsErr.Code() == waf.ErrCodeNonexistentItemException { return nil } } diff --git a/aws/waf_helpers.go b/aws/waf_helpers.go index 0e7b3437536..917f44f480f 100644 --- a/aws/waf_helpers.go +++ b/aws/waf_helpers.go @@ -18,7 +18,10 @@ func wafSizeConstraintSetSchema() map[string]*schema.Schema { Required: true, ForceNew: true, }, - + "arn": { + Type: schema.TypeString, + Computed: true, + }, "size_constraints": { Type: schema.TypeSet, Optional: true, diff --git a/website/docs/r/waf_size_constraint_set.html.markdown b/website/docs/r/waf_size_constraint_set.html.markdown index b67da4c0a98..4b26a49b26b 100644 --- a/website/docs/r/waf_size_constraint_set.html.markdown +++ b/website/docs/r/waf_size_constraint_set.html.markdown @@ -70,3 +70,12 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF Size Constraint Set. +* `arn` - Amazon Resource Name (ARN) + +## Import + +AWS WAF Size Constraint Set can be imported using their ID, e.g. + +``` +$ terraform import aws_waf_size_constraint_set.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` From f768e981a19297fc12fee1fe113432ecdbce88fd Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 07:44:16 -0500 Subject: [PATCH 20/38] Update CHANGELOG for #10484 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a1f1b68322..1392f930346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ENHANCEMENTS: * resource/aws_waf_geo_match_set: Support resource import [GH-10480] * resource/aws_waf_regex_match_set: Support resource import [GH-10481] * resource/aws_waf_regex_pattern_set: Support resource import [GH-10482] +* resource/aws_waf_size_constraint_set: Support resource import [GH-10484] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From 862ba1c98139138dd66bb44f1122da547212da34 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 14:59:04 +0200 Subject: [PATCH 21/38] Add support import for aws_waf_xss_match_set resource (#10485) Output from acceptance testing (test failure unrelated): ``` --- PASS: TestAccAWSWafXssMatchSet_noTuples (18.48s) --- FAIL: TestAccAWSWafXssMatchSet_changeTuples (20.84s) --- PASS: TestAccAWSWafXssMatchSet_basic (27.02s) --- PASS: TestAccAWSWafXssMatchSet_changeNameForceNew (39.22s) --- PASS: TestAccAWSWafXssMatchSet_disappears (44.35s) ``` --- aws/resource_aws_waf_xss_match_set.go | 18 ++- aws/resource_aws_waf_xss_match_set_test.go | 151 ++++++++---------- .../docs/r/waf_xss_match_set.html.markdown | 9 ++ 3 files changed, 97 insertions(+), 81 deletions(-) diff --git a/aws/resource_aws_waf_xss_match_set.go b/aws/resource_aws_waf_xss_match_set.go index 823cac3514d..da671ca09b2 100644 --- a/aws/resource_aws_waf_xss_match_set.go +++ b/aws/resource_aws_waf_xss_match_set.go @@ -5,6 +5,7 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/waf" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -16,6 +17,9 @@ func resourceAwsWafXssMatchSet() *schema.Resource { Read: resourceAwsWafXssMatchSetRead, Update: resourceAwsWafXssMatchSetUpdate, Delete: resourceAwsWafXssMatchSetDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "name": { @@ -23,6 +27,10 @@ func resourceAwsWafXssMatchSet() *schema.Resource { Required: true, ForceNew: true, }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, "xss_match_tuples": { Type: schema.TypeSet, Optional: true, @@ -89,7 +97,7 @@ func resourceAwsWafXssMatchSetRead(d *schema.ResourceData, meta interface{}) err resp, err := conn.GetXssMatchSet(params) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == waf.ErrCodeNonexistentItemException { log.Printf("[WARN] WAF IPSet (%s) not found, removing from state", d.Id()) d.SetId("") return nil @@ -101,6 +109,14 @@ func resourceAwsWafXssMatchSetRead(d *schema.ResourceData, meta interface{}) err d.Set("name", resp.XssMatchSet.Name) d.Set("xss_match_tuples", flattenWafXssMatchTuples(resp.XssMatchSet.XssMatchTuples)) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "waf", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("xssmatchset/%s", d.Id()), + } + d.Set("arn", arn.String()) + return nil } diff --git a/aws/resource_aws_waf_xss_match_set_test.go b/aws/resource_aws_waf_xss_match_set_test.go index 84df10e330c..4c19716d84a 100644 --- a/aws/resource_aws_waf_xss_match_set_test.go +++ b/aws/resource_aws_waf_xss_match_set_test.go @@ -2,6 +2,7 @@ package aws import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" @@ -16,6 +17,7 @@ import ( func TestAccAWSWafXssMatchSet_basic(t *testing.T) { var v waf.XssMatchSet xssMatchSet := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_xss_match_set.xss_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -25,29 +27,25 @@ func TestAccAWSWafXssMatchSet_basic(t *testing.T) { { Config: testAccAWSWafXssMatchSetConfig(xssMatchSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &v), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "name", xssMatchSet), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.field_to_match.2316364334.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.field_to_match.2316364334.type", "QUERY_STRING"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.text_transformation", "NONE"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.field_to_match.3756326843.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.field_to_match.3756326843.type", "URI"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.text_transformation", "NONE"), + testAccCheckAWSWafXssMatchSetExists(resourceName, &v), + testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`xssmatchset/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", xssMatchSet), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.#", "2"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.field_to_match.2316364334.data", ""), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.field_to_match.2316364334.type", "QUERY_STRING"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.text_transformation", "NONE"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.field_to_match.3756326843.data", ""), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.field_to_match.3756326843.type", "URI"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.text_transformation", "NONE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -56,6 +54,7 @@ func TestAccAWSWafXssMatchSet_changeNameForceNew(t *testing.T) { var before, after waf.XssMatchSet xssMatchSet := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) xssMatchSetNewName := fmt.Sprintf("xssMatchSetNewName-%s", acctest.RandString(5)) + resourceName := "aws_waf_xss_match_set.xss_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -65,23 +64,24 @@ func TestAccAWSWafXssMatchSet_changeNameForceNew(t *testing.T) { { Config: testAccAWSWafXssMatchSetConfig(xssMatchSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "name", xssMatchSet), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + testAccCheckAWSWafXssMatchSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", xssMatchSet), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.#", "2"), ), }, { Config: testAccAWSWafXssMatchSetConfigChangeName(xssMatchSetNewName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "name", xssMatchSetNewName), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + testAccCheckAWSWafXssMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", xssMatchSetNewName), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.#", "2"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -89,6 +89,7 @@ func TestAccAWSWafXssMatchSet_changeNameForceNew(t *testing.T) { func TestAccAWSWafXssMatchSet_disappears(t *testing.T) { var v waf.XssMatchSet xssMatchSet := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_xss_match_set.xss_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -98,7 +99,7 @@ func TestAccAWSWafXssMatchSet_disappears(t *testing.T) { { Config: testAccAWSWafXssMatchSetConfig(xssMatchSet), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &v), + testAccCheckAWSWafXssMatchSetExists(resourceName, &v), testAccCheckAWSWafXssMatchSetDisappears(&v), ), ExpectNonEmptyPlan: true, @@ -110,6 +111,7 @@ func TestAccAWSWafXssMatchSet_disappears(t *testing.T) { func TestAccAWSWafXssMatchSet_changeTuples(t *testing.T) { var before, after waf.XssMatchSet setName := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_xss_match_set.xss_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -119,55 +121,40 @@ func TestAccAWSWafXssMatchSet_changeTuples(t *testing.T) { { Config: testAccAWSWafXssMatchSetConfig(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &before), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.field_to_match.2316364334.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.field_to_match.2316364334.type", "QUERY_STRING"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2018581549.text_transformation", "NONE"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.field_to_match.3756326843.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.field_to_match.3756326843.type", "URI"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2786024938.text_transformation", "NONE"), + testAccCheckAWSWafXssMatchSetExists(resourceName, &before), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.#", "2"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.field_to_match.2316364334.data", ""), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.field_to_match.2316364334.type", "QUERY_STRING"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2018581549.text_transformation", "NONE"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.field_to_match.3756326843.data", ""), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.field_to_match.3756326843.type", "URI"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2786024938.text_transformation", "NONE"), ), }, { Config: testAccAWSWafXssMatchSetConfig_changeTuples(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &after), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2893682529.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2893682529.field_to_match.4253810390.data", "GET"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2893682529.field_to_match.4253810390.type", "METHOD"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.2893682529.text_transformation", "HTML_ENTITY_DECODE"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.4270311415.field_to_match.#", "1"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.4270311415.field_to_match.281401076.data", ""), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.4270311415.field_to_match.281401076.type", "BODY"), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.4270311415.text_transformation", "CMD_LINE"), + testAccCheckAWSWafXssMatchSetExists(resourceName, &after), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.#", "2"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2893682529.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2893682529.field_to_match.4253810390.data", "GET"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2893682529.field_to_match.4253810390.type", "METHOD"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.2893682529.text_transformation", "HTML_ENTITY_DECODE"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.4270311415.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.4270311415.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.4270311415.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.4270311415.text_transformation", "CMD_LINE"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -175,6 +162,7 @@ func TestAccAWSWafXssMatchSet_changeTuples(t *testing.T) { func TestAccAWSWafXssMatchSet_noTuples(t *testing.T) { var ipset waf.XssMatchSet setName := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + resourceName := "aws_waf_xss_match_set.xss_match_set" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) }, @@ -184,13 +172,16 @@ func TestAccAWSWafXssMatchSet_noTuples(t *testing.T) { { Config: testAccAWSWafXssMatchSetConfig_noTuples(setName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSWafXssMatchSetExists("aws_waf_xss_match_set.xss_match_set", &ipset), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "name", setName), - resource.TestCheckResourceAttr( - "aws_waf_xss_match_set.xss_match_set", "xss_match_tuples.#", "0"), + testAccCheckAWSWafXssMatchSetExists(resourceName, &ipset), + resource.TestCheckResourceAttr(resourceName, "name", setName), + resource.TestCheckResourceAttr(resourceName, "xss_match_tuples.#", "0"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -285,7 +276,7 @@ func testAccCheckAWSWafXssMatchSetDestroy(s *terraform.State) error { // Return nil if the XssMatchSet is already destroyed if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "WAFNonexistentItemException" { + if awsErr.Code() == waf.ErrCodeNonexistentItemException { return nil } } diff --git a/website/docs/r/waf_xss_match_set.html.markdown b/website/docs/r/waf_xss_match_set.html.markdown index 334d332e74a..001eef59691 100644 --- a/website/docs/r/waf_xss_match_set.html.markdown +++ b/website/docs/r/waf_xss_match_set.html.markdown @@ -71,3 +71,12 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF XssMatchSet. +* `arn` - Amazon Resource Name (ARN) + +## Import + +WAF XSS Match Set can be imported using their ID, e.g. + +``` +$ terraform import aws_waf_xss_match_set.example a1b2c3d4-d5f6-7777-8888-9999aaaabbbbcccc +``` \ No newline at end of file From c3aceb1b2b8d140e7cc5cf2c2c85264a72ecb748 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 07:59:45 -0500 Subject: [PATCH 22/38] Update CHANGELOG for #10485 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1392f930346..c6f3df21002 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ ENHANCEMENTS: * resource/aws_waf_regex_match_set: Support resource import [GH-10481] * resource/aws_waf_regex_pattern_set: Support resource import [GH-10482] * resource/aws_waf_size_constraint_set: Support resource import [GH-10484] +* resource/aws_waf_xss_match_set: Support resource import [GH-10485] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From 8d94da18055fa5d8d4387cd6f317e5d2c7393909 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 08:00:49 -0500 Subject: [PATCH 23/38] Update CHANGELOG entries for #10480, #10481, #10482, #10484, and #10485 to include arn attribute addition --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6f3df21002..38db7e7baa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,11 @@ ENHANCEMENTS: * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] -* resource/aws_waf_geo_match_set: Support resource import [GH-10480] -* resource/aws_waf_regex_match_set: Support resource import [GH-10481] -* resource/aws_waf_regex_pattern_set: Support resource import [GH-10482] -* resource/aws_waf_size_constraint_set: Support resource import [GH-10484] -* resource/aws_waf_xss_match_set: Support resource import [GH-10485] +* resource/aws_waf_geo_match_set: Support resource import and add `arn` attribute [GH-10480] +* resource/aws_waf_regex_match_set: Support resource import and add `arn` attribute [GH-10481] +* resource/aws_waf_regex_pattern_set: Support resource import and add `arn` attribute [GH-10482] +* resource/aws_waf_size_constraint_set: Support resource import and add `arn` attribute [GH-10484] +* resource/aws_waf_xss_match_set: Support resource import and add `arn` attribute [GH-10485] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] BUG FIXES: From 43ae107a7c7a739ee8ce46fbd242253d465d4dab Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 13:43:25 -0500 Subject: [PATCH 24/38] service/secretsmanager: Refactor tagging logic to keyvaluetags package (#10745) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/10688 Output from acceptance testing: ``` --- PASS: TestAccDataSourceAwsSecretsManagerSecret_Basic (5.99s) --- PASS: TestAccAwsSecretsManagerSecret_Basic (13.99s) --- PASS: TestAccAwsSecretsManagerSecret_withNamePrefix (14.02s) --- PASS: TestAccDataSourceAwsSecretsManagerSecret_ARN (15.28s) --- PASS: TestAccDataSourceAwsSecretsManagerSecret_Policy (16.05s) --- PASS: TestAccDataSourceAwsSecretsManagerSecret_Name (16.35s) --- PASS: TestAccAwsSecretsManagerSecret_policy (17.75s) --- PASS: TestAccAwsSecretsManagerSecret_Description (21.89s) --- PASS: TestAccAwsSecretsManagerSecret_Tags (38.69s) --- PASS: TestAccAwsSecretsManagerSecret_RecoveryWindowInDays_Recreate (39.41s) --- PASS: TestAccAwsSecretsManagerSecret_RotationRules (50.42s) --- PASS: TestAccAwsSecretsManagerSecret_RotationLambdaARN (50.55s) --- PASS: TestAccAwsSecretsManagerSecret_KmsKeyID (53.23s) ``` --- aws/data_source_aws_secretsmanager_secret.go | 3 +- aws/resource_aws_secretsmanager_secret.go | 38 ++-------- aws/tagsSecretsManager.go | 75 ------------------- aws/tagsSecretsManager_test.go | 79 -------------------- 4 files changed, 8 insertions(+), 187 deletions(-) delete mode 100644 aws/tagsSecretsManager.go delete mode 100644 aws/tagsSecretsManager_test.go diff --git a/aws/data_source_aws_secretsmanager_secret.go b/aws/data_source_aws_secretsmanager_secret.go index 2aa573be3a7..898191a9d8b 100644 --- a/aws/data_source_aws_secretsmanager_secret.go +++ b/aws/data_source_aws_secretsmanager_secret.go @@ -9,6 +9,7 @@ import ( "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/structure" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func dataSourceAwsSecretsManagerSecret() *schema.Resource { @@ -131,7 +132,7 @@ func dataSourceAwsSecretsManagerSecretRead(d *schema.ResourceData, meta interfac return fmt.Errorf("error setting rotation_rules: %s", err) } - if err := d.Set("tags", tagsToMapSecretsManager(output.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.SecretsmanagerKeyValueTags(output.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_secretsmanager_secret.go b/aws/resource_aws_secretsmanager_secret.go index d6ce9b179cd..7395059f16e 100644 --- a/aws/resource_aws_secretsmanager_secret.go +++ b/aws/resource_aws_secretsmanager_secret.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsSecretsManagerSecret() *schema.Resource { @@ -118,8 +119,7 @@ func resourceAwsSecretsManagerSecretCreate(d *schema.ResourceData, meta interfac } if v, ok := d.GetOk("tags"); ok { - input.Tags = tagsFromMapSecretsManager(v.(map[string]interface{})) - log.Printf("[DEBUG] Tagging Secrets Manager Secret: %s", input.Tags) + input.Tags = keyvaluetags.New(v.(map[string]interface{})).IgnoreAws().SecretsmanagerTags() } if v, ok := d.GetOk("kms_key_id"); ok && v.(string) != "" { @@ -248,7 +248,7 @@ func resourceAwsSecretsManagerSecretRead(d *schema.ResourceData, meta interface{ d.Set("rotation_rules", []interface{}{}) } - if err := d.Set("tags", tagsToMapSecretsManager(output.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.SecretsmanagerKeyValueTags(output.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -344,35 +344,9 @@ func resourceAwsSecretsManagerSecretUpdate(d *schema.ResourceData, meta interfac } if d.HasChange("tags") { - oraw, nraw := d.GetChange("tags") - o := oraw.(map[string]interface{}) - n := nraw.(map[string]interface{}) - create, remove := diffTagsSecretsManager(tagsFromMapSecretsManager(o), tagsFromMapSecretsManager(n)) - - if len(remove) > 0 { - log.Printf("[DEBUG] Removing Secrets Manager Secret %q tags: %#v", d.Id(), remove) - k := make([]*string, len(remove)) - for i, t := range remove { - k[i] = t.Key - } - - _, err := conn.UntagResource(&secretsmanager.UntagResourceInput{ - SecretId: aws.String(d.Id()), - TagKeys: k, - }) - if err != nil { - return fmt.Errorf("error updating Secrets Manager Secrets %q tags: %s", d.Id(), err) - } - } - if len(create) > 0 { - log.Printf("[DEBUG] Creating Secrets Manager Secret %q tags: %#v", d.Id(), create) - _, err := conn.TagResource(&secretsmanager.TagResourceInput{ - SecretId: aws.String(d.Id()), - Tags: create, - }) - if err != nil { - return fmt.Errorf("error updating Secrets Manager Secrets %q tags: %s", d.Id(), err) - } + o, n := d.GetChange("tags") + if err := keyvaluetags.SecretsmanagerUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) } } diff --git a/aws/tagsSecretsManager.go b/aws/tagsSecretsManager.go deleted file mode 100644 index e7547ad7fe6..00000000000 --- a/aws/tagsSecretsManager.go +++ /dev/null @@ -1,75 +0,0 @@ -package aws - -import ( - "log" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/secretsmanager" -) - -// diffTags takes our tags locally and the ones remotely and returns -// the set of tags that must be created, and the set of tags that must -// be destroyed. -func diffTagsSecretsManager(oldTags, newTags []*secretsmanager.Tag) ([]*secretsmanager.Tag, []*secretsmanager.Tag) { - // First, we're creating everything we have - create := make(map[string]interface{}) - for _, t := range newTags { - create[*t.Key] = *t.Value - } - - // Build the list of what to remove - var remove []*secretsmanager.Tag - for _, t := range oldTags { - old, ok := create[*t.Key] - if !ok || old != *t.Value { - // Delete it! - remove = append(remove, t) - } - } - - return tagsFromMapSecretsManager(create), remove -} - -// tagsFromMap returns the tags for the given map of data. -func tagsFromMapSecretsManager(m map[string]interface{}) []*secretsmanager.Tag { - result := make([]*secretsmanager.Tag, 0, len(m)) - for k, v := range m { - t := &secretsmanager.Tag{ - Key: aws.String(k), - Value: aws.String(v.(string)), - } - if !tagIgnoredSecretsManager(t) { - result = append(result, t) - } - } - - return result -} - -// tagsToMap turns the list of tags into a map. -func tagsToMapSecretsManager(ts []*secretsmanager.Tag) map[string]string { - result := make(map[string]string) - for _, t := range ts { - if !tagIgnoredSecretsManager(t) { - result[*t.Key] = *t.Value - } - } - - return result -} - -// compare a tag against a list of strings and checks if it should -// be ignored or not -func tagIgnoredSecretsManager(t *secretsmanager.Tag) bool { - filter := []string{"^aws:"} - for _, v := range filter { - log.Printf("[DEBUG] Matching %v with %v\n", v, *t.Key) - r, _ := regexp.MatchString(v, *t.Key) - if r { - log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", *t.Key, *t.Value) - return true - } - } - return false -} diff --git a/aws/tagsSecretsManager_test.go b/aws/tagsSecretsManager_test.go deleted file mode 100644 index d6eebe5343c..00000000000 --- a/aws/tagsSecretsManager_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package aws - -import ( - "reflect" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/secretsmanager" -) - -// go test -v -run="TestDiffSecretsManagerTags" -func TestDiffSecretsManagerTags(t *testing.T) { - cases := []struct { - Old, New map[string]interface{} - Create, Remove map[string]string - }{ - // Basic add/remove - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "bar": "baz", - }, - Create: map[string]string{ - "bar": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Modify - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "baz", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - } - - for i, tc := range cases { - c, r := diffTagsSecretsManager(tagsFromMapSecretsManager(tc.Old), tagsFromMapSecretsManager(tc.New)) - cm := tagsToMapSecretsManager(c) - rm := tagsToMapSecretsManager(r) - if !reflect.DeepEqual(cm, tc.Create) { - t.Fatalf("%d: bad create: %#v", i, cm) - } - if !reflect.DeepEqual(rm, tc.Remove) { - t.Fatalf("%d: bad remove: %#v", i, rm) - } - } -} - -// go test -v -run="TestIgnoringTagsSecretsManager" -func TestIgnoringTagsSecretsManager(t *testing.T) { - var ignoredTags []*secretsmanager.Tag - ignoredTags = append(ignoredTags, &secretsmanager.Tag{ - Key: aws.String("aws:cloudformation:logical-id"), - Value: aws.String("foo"), - }) - ignoredTags = append(ignoredTags, &secretsmanager.Tag{ - Key: aws.String("aws:foo:bar"), - Value: aws.String("baz"), - }) - for _, tag := range ignoredTags { - if !tagIgnoredSecretsManager(tag) { - t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value) - } - } -} From 39ec0b6fe70f087105bb53266e3ad86a1d502db6 Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 20:49:01 +0200 Subject: [PATCH 25/38] Add import support for aws_wafregional_web_acl_association resource (#10538) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegionalWebAclAssociation_ResourceArn_ApiGatewayStage (44.37s) --- PASS: TestAccAWSWafRegionalWebAclAssociation_disappears (185.89s) --- PASS: TestAccAWSWafRegionalWebAclAssociation_basic (192.13s) --- PASS: TestAccAWSWafRegionalWebAclAssociation_multipleAssociations (194.36s) ``` --- ...rce_aws_wafregional_web_acl_association.go | 3 +++ ...ws_wafregional_web_acl_association_test.go | 23 +++++++++++++++++-- ...regional_web_acl_association.html.markdown | 8 +++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_wafregional_web_acl_association.go b/aws/resource_aws_wafregional_web_acl_association.go index f69d90682a6..c7814f654e4 100644 --- a/aws/resource_aws_wafregional_web_acl_association.go +++ b/aws/resource_aws_wafregional_web_acl_association.go @@ -17,6 +17,9 @@ func resourceAwsWafRegionalWebAclAssociation() *schema.Resource { Create: resourceAwsWafRegionalWebAclAssociationCreate, Read: resourceAwsWafRegionalWebAclAssociationRead, Delete: resourceAwsWafRegionalWebAclAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, Schema: map[string]*schema.Schema{ "web_acl_id": { diff --git a/aws/resource_aws_wafregional_web_acl_association_test.go b/aws/resource_aws_wafregional_web_acl_association_test.go index 20186062b4d..89de08fbc78 100644 --- a/aws/resource_aws_wafregional_web_acl_association_test.go +++ b/aws/resource_aws_wafregional_web_acl_association_test.go @@ -13,6 +13,8 @@ import ( ) func TestAccAWSWafRegionalWebAclAssociation_basic(t *testing.T) { + resourceName := "aws_wafregional_web_acl_association.foo" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -21,9 +23,14 @@ func TestAccAWSWafRegionalWebAclAssociation_basic(t *testing.T) { { Config: testAccCheckWafRegionalWebAclAssociationConfig_basic, Check: resource.ComposeTestCheckFunc( - testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.foo"), + testAccCheckWafRegionalWebAclAssociationExists(resourceName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -47,6 +54,8 @@ func TestAccAWSWafRegionalWebAclAssociation_disappears(t *testing.T) { } func TestAccAWSWafRegionalWebAclAssociation_multipleAssociations(t *testing.T) { + resourceName := "aws_wafregional_web_acl_association.foo" + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -55,10 +64,15 @@ func TestAccAWSWafRegionalWebAclAssociation_multipleAssociations(t *testing.T) { { Config: testAccCheckWafRegionalWebAclAssociationConfig_multipleAssociations, Check: resource.ComposeTestCheckFunc( - testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.foo"), + testAccCheckWafRegionalWebAclAssociationExists(resourceName), testAccCheckWafRegionalWebAclAssociationExists("aws_wafregional_web_acl_association.bar"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -78,6 +92,11 @@ func TestAccAWSWafRegionalWebAclAssociation_ResourceArn_ApiGatewayStage(t *testi testAccCheckWafRegionalWebAclAssociationExists(resourceName), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } diff --git a/website/docs/r/wafregional_web_acl_association.html.markdown b/website/docs/r/wafregional_web_acl_association.html.markdown index a37e4d835d9..ce6f4eedddb 100644 --- a/website/docs/r/wafregional_web_acl_association.html.markdown +++ b/website/docs/r/wafregional_web_acl_association.html.markdown @@ -94,3 +94,11 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the association + +## Import + +WAF Regional Web ACL Association can be imported using their `web_acl_id:resource_arn`, e.g. + +``` +$ terraform import aws_wafregional_web_acl_association.foo web_acl_id:resource_arn +``` \ No newline at end of file From b964f34eb024e58f84111e1149265731beb3f68b Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 14:09:28 -0500 Subject: [PATCH 26/38] Update CHANGELOG for #10538 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38db7e7baa1..0ef956cf756 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ ENHANCEMENTS: * resource/aws_waf_size_constraint_set: Support resource import and add `arn` attribute [GH-10484] * resource/aws_waf_xss_match_set: Support resource import and add `arn` attribute [GH-10485] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] +* resource/aws_wafregional_web_acl_association: Support resource import [GH-10538] BUG FIXES: From b689da30e957a850660410a5c3215612a4465970 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 14:38:59 -0500 Subject: [PATCH 27/38] service/transfer: Refactor tagging logic to keyvaluetags package (#10739) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/10688 Output from acceptance testing: ``` --- PASS: TestAccAWSTransferUser_UserName_Validation (5.86s) --- PASS: TestAccAWSTransferServer_disappears (11.20s) --- PASS: TestAccAWSTransferUser_disappears (14.61s) --- PASS: TestAccAWSTransferServer_forcedestroy (15.39s) --- PASS: TestAccAWSTransferUser_basic (16.12s) --- PASS: TestAccAWSTransferServer_apigateway (20.54s) --- PASS: TestAccAWSTransferServer_basic (21.48s) --- PASS: TestAccAWSTransferUser_modifyWithOptions (36.18s) --- PASS: TestAccAWSTransferServer_vpcEndpointId (77.08s) ``` --- aws/resource_aws_transfer_server.go | 13 +-- aws/resource_aws_transfer_user.go | 13 +-- aws/tagsTransfer.go | 118 ---------------------------- aws/tagsTransfer_test.go | 112 -------------------------- 4 files changed, 16 insertions(+), 240 deletions(-) delete mode 100644 aws/tagsTransfer.go delete mode 100644 aws/tagsTransfer_test.go diff --git a/aws/resource_aws_transfer_server.go b/aws/resource_aws_transfer_server.go index f2db50b259d..eea94fb1571 100644 --- a/aws/resource_aws_transfer_server.go +++ b/aws/resource_aws_transfer_server.go @@ -8,10 +8,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsTransferServer() *schema.Resource { @@ -110,7 +110,7 @@ func resourceAwsTransferServer() *schema.Resource { func resourceAwsTransferServerCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).transferconn - tags := tagsFromMapTransfer(d.Get("tags").(map[string]interface{})) + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().TransferTags() createOpts := &transfer.CreateServerInput{} if len(tags) != 0 { @@ -192,7 +192,7 @@ func resourceAwsTransferServerRead(d *schema.ResourceData, meta interface{}) err d.Set("identity_provider_type", resp.Server.IdentityProviderType) d.Set("logging_role", resp.Server.LoggingRole) - if err := d.Set("tags", tagsToMapTransfer(resp.Server.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.TransferKeyValueTags(resp.Server.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("Error setting tags: %s", err) } return nil @@ -249,8 +249,11 @@ func resourceAwsTransferServerUpdate(d *schema.ResourceData, meta interface{}) e } } - if err := setTagsTransfer(conn, d); err != nil { - return fmt.Errorf("Error update tags: %s", err) + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.TransferUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } } return resourceAwsTransferServerRead(d, meta) diff --git a/aws/resource_aws_transfer_user.go b/aws/resource_aws_transfer_user.go index cd9df67f417..4747829b4e1 100644 --- a/aws/resource_aws_transfer_user.go +++ b/aws/resource_aws_transfer_user.go @@ -8,10 +8,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsTransferUser() *schema.Resource { @@ -89,7 +89,7 @@ func resourceAwsTransferUserCreate(d *schema.ResourceData, meta interface{}) err } if attr, ok := d.GetOk("tags"); ok { - createOpts.Tags = tagsFromMapTransfer(attr.(map[string]interface{})) + createOpts.Tags = keyvaluetags.New(attr.(map[string]interface{})).IgnoreAws().TransferTags() } log.Printf("[DEBUG] Create Transfer User Option: %#v", createOpts) @@ -135,7 +135,7 @@ func resourceAwsTransferUserRead(d *schema.ResourceData, meta interface{}) error d.Set("policy", resp.User.Policy) d.Set("role", resp.User.Role) - if err := d.Set("tags", tagsToMapTransfer(resp.User.Tags)); err != nil { + if err := d.Set("tags", keyvaluetags.TransferKeyValueTags(resp.User.Tags).IgnoreAws().Map()); err != nil { return fmt.Errorf("Error setting tags: %s", err) } return nil @@ -181,8 +181,11 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err } } - if err := setTagsTransfer(conn, d); err != nil { - return fmt.Errorf("Error update tags: %s", err) + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.TransferUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } } return resourceAwsTransferUserRead(d, meta) diff --git a/aws/tagsTransfer.go b/aws/tagsTransfer.go deleted file mode 100644 index 941e542fc92..00000000000 --- a/aws/tagsTransfer.go +++ /dev/null @@ -1,118 +0,0 @@ -package aws - -import ( - "log" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/transfer" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" -) - -// setTags is a helper to set the tags for a resource. It expects the -// tags field to be named "tags" -func setTagsTransfer(conn *transfer.Transfer, d *schema.ResourceData) error { - if d.HasChange("tags") { - oraw, nraw := d.GetChange("tags") - o := oraw.(map[string]interface{}) - n := nraw.(map[string]interface{}) - create, remove := diffTagsTransfer(tagsFromMapTransfer(o), tagsFromMapTransfer(n)) - - // Set tags - if len(remove) > 0 { - log.Printf("[DEBUG] Removing tags: %#v", remove) - k := make([]*string, len(remove)) - for i, t := range remove { - k[i] = t.Key - } - - _, err := conn.UntagResource(&transfer.UntagResourceInput{ - Arn: aws.String(d.Get("arn").(string)), - TagKeys: k, - }) - if err != nil { - return err - } - } - if len(create) > 0 { - log.Printf("[DEBUG] Creating tags: %#v", create) - _, err := conn.TagResource(&transfer.TagResourceInput{ - Arn: aws.String(d.Get("arn").(string)), - Tags: create, - }) - if err != nil { - return err - } - } - } - - return nil -} - -// diffTags takes our tags locally and the ones remotely and returns -// the set of tags that must be created, and the set of tags that must -// be destroyed. -func diffTagsTransfer(oldTags, newTags []*transfer.Tag) ([]*transfer.Tag, []*transfer.Tag) { - // First, we're creating everything we have - create := make(map[string]interface{}) - for _, t := range newTags { - create[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - - // Build the list of what to remove - var remove []*transfer.Tag - for _, t := range oldTags { - old, ok := create[aws.StringValue(t.Key)] - if !ok || old != aws.StringValue(t.Value) { - // Delete it! - remove = append(remove, t) - } else if ok { - // already present so remove from new - delete(create, aws.StringValue(t.Key)) - } - } - - return tagsFromMapTransfer(create), remove -} - -// tagsFromMap returns the tags for the given map of data. -func tagsFromMapTransfer(m map[string]interface{}) []*transfer.Tag { - result := make([]*transfer.Tag, 0, len(m)) - for k, v := range m { - t := &transfer.Tag{ - Key: aws.String(k), - Value: aws.String(v.(string)), - } - if !tagIgnoredTransfer(t) { - result = append(result, t) - } - } - - return result -} - -// tagsToMap turns the list of tags into a map. -func tagsToMapTransfer(ts []*transfer.Tag) map[string]string { - result := make(map[string]string) - for _, t := range ts { - if !tagIgnoredTransfer(t) { - result[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - } - - return result -} - -// compare a tag against a list of strings and checks if it should -// be ignored or not -func tagIgnoredTransfer(t *transfer.Tag) bool { - filter := []string{"^aws:"} - for _, v := range filter { - log.Printf("[DEBUG] Matching %v with %v\n", v, aws.StringValue(t.Key)) - if r, _ := regexp.MatchString(v, aws.StringValue(t.Key)); r { - log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", aws.StringValue(t.Key), aws.StringValue(t.Value)) - return true - } - } - return false -} diff --git a/aws/tagsTransfer_test.go b/aws/tagsTransfer_test.go deleted file mode 100644 index abb8cf19638..00000000000 --- a/aws/tagsTransfer_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package aws - -import ( - "reflect" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/transfer" -) - -// go test -v -run="TestDiffTransferTags" -func TestDiffTransferTags(t *testing.T) { - cases := []struct { - Old, New map[string]interface{} - Create, Remove map[string]string - }{ - // Basic add/remove - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "bar": "baz", - }, - Create: map[string]string{ - "bar": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Modify - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "baz", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Overlap - { - Old: map[string]interface{}{ - "foo": "bar", - "hello": "world", - }, - New: map[string]interface{}{ - "foo": "baz", - "hello": "world", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Remove - { - Old: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - New: map[string]interface{}{ - "foo": "bar", - }, - Create: map[string]string{}, - Remove: map[string]string{ - "bar": "baz", - }, - }, - } - - for i, tc := range cases { - c, r := diffTagsTransfer(tagsFromMapTransfer(tc.Old), tagsFromMapTransfer(tc.New)) - cm := tagsToMapTransfer(c) - rm := tagsToMapTransfer(r) - if !reflect.DeepEqual(cm, tc.Create) { - t.Fatalf("%d: bad create: %#v", i, cm) - } - if !reflect.DeepEqual(rm, tc.Remove) { - t.Fatalf("%d: bad remove: %#v", i, rm) - } - } -} - -// go test -v -run="TestIgnoringTagsTransfer" -func TestIgnoringTagsTransfer(t *testing.T) { - var ignoredTags []*transfer.Tag - ignoredTags = append(ignoredTags, &transfer.Tag{ - Key: aws.String("aws:cloudformation:logical-id"), - Value: aws.String("foo"), - }) - ignoredTags = append(ignoredTags, &transfer.Tag{ - Key: aws.String("aws:foo:bar"), - Value: aws.String("baz"), - }) - for _, tag := range ignoredTags { - if !tagIgnoredTransfer(tag) { - t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value) - } - } -} From 2a8e6d4e3f1388c3365a25b0ae2e3609994fdcfd Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 14:39:54 -0500 Subject: [PATCH 28/38] resource/aws_sns_topic: Refactor tagging logic to use keyvaluetags package and call Read after Create (#10741) Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/10688 Output from acceptance testing: ``` --- PASS: TestAccAWSSNSTopic_name (13.72s) --- PASS: TestAccAWSSNSTopic_namePrefix (13.88s) --- PASS: TestAccAWSSNSTopic_basic (14.02s) --- PASS: TestAccAWSSNSTopic_withDeliveryPolicy (14.52s) --- PASS: TestAccAWSSNSTopic_policy (14.77s) --- PASS: TestAccAWSSNSTopic_encryption (22.23s) --- PASS: TestAccAWSSNSTopic_withIAMRole (22.35s) --- PASS: TestAccAWSSNSTopic_tags (30.82s) --- PASS: TestAccAWSSNSTopic_deliveryStatus (31.95s) --- PASS: TestAccAWSSNSTopic_withFakeIAMRole (129.10s) ``` --- aws/resource_aws_sns_topic.go | 34 ++++++---- aws/tagsSNS.go | 118 ---------------------------------- aws/tagsSNS_test.go | 110 ------------------------------- 3 files changed, 23 insertions(+), 239 deletions(-) delete mode 100644 aws/tagsSNS.go delete mode 100644 aws/tagsSNS_test.go diff --git a/aws/resource_aws_sns_topic.go b/aws/resource_aws_sns_topic.go index a3f593d6e18..271aafad90b 100644 --- a/aws/resource_aws_sns_topic.go +++ b/aws/resource_aws_sns_topic.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) // Mutable attributes @@ -151,7 +152,7 @@ func resourceAwsSnsTopic() *schema.Resource { func resourceAwsSnsTopicCreate(d *schema.ResourceData, meta interface{}) error { snsconn := meta.(*AWSClient).snsconn - tags := tagsFromMapSNS(d.Get("tags").(map[string]interface{})) + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().SnsTags() var name string if v, ok := d.GetOk("name"); ok { name = v.(string) @@ -174,7 +175,18 @@ func resourceAwsSnsTopicCreate(d *schema.ResourceData, meta interface{}) error { } d.SetId(*output.TopicArn) - return resourceAwsSnsTopicUpdate(d, meta) + + for terraformAttrName, snsAttrName := range SNSAttributeMap { + if d.HasChange(terraformAttrName) { + _, terraformAttrValue := d.GetChange(terraformAttrName) + err := updateAwsSnsTopicAttribute(d.Id(), snsAttrName, terraformAttrValue, snsconn) + if err != nil { + return err + } + } + } + + return resourceAwsSnsTopicRead(d, meta) } func resourceAwsSnsTopicUpdate(d *schema.ResourceData, meta interface{}) error { @@ -189,9 +201,11 @@ func resourceAwsSnsTopicUpdate(d *schema.ResourceData, meta interface{}) error { } } } - if !d.IsNewResource() { - if err := setTagsSNS(conn, d); err != nil { - return fmt.Errorf("error updating SNS Topic tags for %s: %s", d.Id(), err) + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.SnsUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) } } @@ -237,15 +251,13 @@ func resourceAwsSnsTopicRead(d *schema.ResourceData, meta interface{}) error { } } - // List tags + tags, err := keyvaluetags.SnsListTags(snsconn, d.Id()) - tagList, err := snsconn.ListTagsForResource(&sns.ListTagsForResourceInput{ - ResourceArn: aws.String(d.Id()), - }) if err != nil { - return fmt.Errorf("error listing SNS Topic tags for %s: %s", d.Id(), err) + return fmt.Errorf("error listing tags for resource (%s): %s", d.Id(), err) } - if err := d.Set("tags", tagsToMapSNS(tagList.Tags)); err != nil { + + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/tagsSNS.go b/aws/tagsSNS.go deleted file mode 100644 index d8862fc2f1f..00000000000 --- a/aws/tagsSNS.go +++ /dev/null @@ -1,118 +0,0 @@ -package aws - -import ( - "log" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/sns" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" -) - -// setTags is a helper to set the tags for a resource. It expects the -// tags field to be named "tags" and the ARN field to be named "arn". -func setTagsSNS(conn *sns.SNS, d *schema.ResourceData) error { - if d.HasChange("tags") { - oraw, nraw := d.GetChange("tags") - o := oraw.(map[string]interface{}) - n := nraw.(map[string]interface{}) - create, remove := diffTagsSNS(tagsFromMapSNS(o), tagsFromMapSNS(n)) - - // Set tags - if len(remove) > 0 { - log.Printf("[DEBUG] Removing tags: %#v", remove) - k := make([]*string, len(remove)) - for i, t := range remove { - k[i] = t.Key - } - - _, err := conn.UntagResource(&sns.UntagResourceInput{ - ResourceArn: aws.String(d.Get("arn").(string)), - TagKeys: k, - }) - if err != nil { - return err - } - } - if len(create) > 0 { - log.Printf("[DEBUG] Creating tags: %#v", create) - _, err := conn.TagResource(&sns.TagResourceInput{ - ResourceArn: aws.String(d.Get("arn").(string)), - Tags: create, - }) - if err != nil { - return err - } - } - } - - return nil -} - -// diffTags takes our tags locally and the ones remotely and returns -// the set of tags that must be created, and the set of tags that must -// be destroyed. -func diffTagsSNS(oldTags, newTags []*sns.Tag) ([]*sns.Tag, []*sns.Tag) { - // First, we're creating everything we have - create := make(map[string]interface{}) - for _, t := range newTags { - create[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - - // Build the list of what to remove - var remove []*sns.Tag - for _, t := range oldTags { - old, ok := create[aws.StringValue(t.Key)] - if !ok || old != aws.StringValue(t.Value) { - remove = append(remove, t) - } else if ok { - // already present so remove from new - delete(create, aws.StringValue(t.Key)) - } - } - - return tagsFromMapSNS(create), remove -} - -// tagsFromMap returns the tags for the given map of data. -func tagsFromMapSNS(m map[string]interface{}) []*sns.Tag { - result := make([]*sns.Tag, 0, len(m)) - for k, v := range m { - t := &sns.Tag{ - Key: aws.String(k), - Value: aws.String(v.(string)), - } - if !tagIgnoredSNS(t) { - result = append(result, t) - } - } - - return result -} - -// tagsToMap turns the list of tags into a map. -func tagsToMapSNS(ts []*sns.Tag) map[string]string { - result := make(map[string]string) - for _, t := range ts { - if !tagIgnoredSNS(t) { - result[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - } - - return result -} - -// compare a tag against a list of strings and checks if it should -// be ignored or not -func tagIgnoredSNS(t *sns.Tag) bool { - filter := []string{"^aws:"} - for _, v := range filter { - log.Printf("[DEBUG] Matching %v with %v\n", v, *t.Key) - r, _ := regexp.MatchString(v, *t.Key) - if r { - log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", *t.Key, *t.Value) - return true - } - } - return false -} diff --git a/aws/tagsSNS_test.go b/aws/tagsSNS_test.go deleted file mode 100644 index 77a9c149750..00000000000 --- a/aws/tagsSNS_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package aws - -import ( - "reflect" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/sns" -) - -func TestDiffSNSTags(t *testing.T) { - cases := []struct { - Old, New map[string]interface{} - Create, Remove map[string]string - }{ - // Add - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - Create: map[string]string{ - "bar": "baz", - }, - Remove: map[string]string{}, - }, - - // Modify - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "baz", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Overlap - { - Old: map[string]interface{}{ - "foo": "bar", - "hello": "world", - }, - New: map[string]interface{}{ - "foo": "baz", - "hello": "world", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Remove - { - Old: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - New: map[string]interface{}{ - "foo": "bar", - }, - Create: map[string]string{}, - Remove: map[string]string{ - "bar": "baz", - }, - }, - } - - for i, tc := range cases { - c, r := diffTagsSNS(tagsFromMapSNS(tc.Old), tagsFromMapSNS(tc.New)) - cm := tagsToMapSNS(c) - rm := tagsToMapSNS(r) - if !reflect.DeepEqual(cm, tc.Create) { - t.Fatalf("%d: bad create: %#v", i, cm) - } - if !reflect.DeepEqual(rm, tc.Remove) { - t.Fatalf("%d: bad remove: %#v", i, rm) - } - } -} - -func TestIgnoringTagsSNS(t *testing.T) { - ignoredTags := []*sns.Tag{ - { - Key: aws.String("aws:cloudformation:logical-id"), - Value: aws.String("foo"), - }, - { - Key: aws.String("aws:foo:bar"), - Value: aws.String("baz"), - }, - } - for _, tag := range ignoredTags { - if !tagIgnoredSNS(tag) { - t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value) - } - } -} From 7fa643885417b5d62e6ad0ccf4aea5cb6226b80c Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 14:40:48 -0500 Subject: [PATCH 29/38] service/sfn: Refactor tagging logic to keyvaluetags package (#10744) Output from acceptance testing (failure unrelated and present on master): ``` --- PASS: TestAccAWSSfnActivity_basic (12.40s) --- PASS: TestAccAWSSfnActivity_Tags (38.16s) --- FAIL: TestAccAWSSfnStateMachine_createUpdate (39.18s) testing.go:615: Step 1 error: Check failed: Check 5/6 error: aws_sfn_state_machine.foo: Attribute 'definition' didn't match ".*\\\"MaxAttempts\\\": 10.*", got "{\n \"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Function\",\n \"StartAt\": \"HelloWorld\",\n \"States\": {\n \"HelloWorld\": {\n \"Type\": \"Task\",\n \"Resource\": \"arn:aws:lambda:us-west-2:--OMITTED--:function:sfn-ls0gr71fnj\",\n \"Retry\": [\n {\n \"ErrorEquals\": [\"States.ALL\"],\n \"IntervalSeconds\": 5,\n \"MaxAttempts\": 5,\n \"BackoffRate\": 8.0\n }\n ],\n \"End\": true\n }\n }\n}\n" --- PASS: TestAccAWSSfnStateMachine_Tags (56.24s) ``` --- aws/resource_aws_sfn_activity.go | 48 ++--------- aws/resource_aws_sfn_state_machine.go | 55 +++---------- aws/tagsSfn.go | 78 ------------------ aws/tagsSfn_test.go | 110 -------------------------- 4 files changed, 17 insertions(+), 274 deletions(-) delete mode 100644 aws/tagsSfn.go delete mode 100644 aws/tagsSfn_test.go diff --git a/aws/resource_aws_sfn_activity.go b/aws/resource_aws_sfn_activity.go index 7f01931d292..3eb5afb5a2d 100644 --- a/aws/resource_aws_sfn_activity.go +++ b/aws/resource_aws_sfn_activity.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsSfnActivity() *schema.Resource { @@ -46,7 +47,7 @@ func resourceAwsSfnActivityCreate(d *schema.ResourceData, meta interface{}) erro params := &sfn.CreateActivityInput{ Name: aws.String(d.Get("name").(string)), - Tags: tagsFromMapSfn(d.Get("tags").(map[string]interface{})), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().SfnTags(), } activity, err := conn.CreateActivity(params) @@ -63,38 +64,9 @@ func resourceAwsSfnActivityUpdate(d *schema.ResourceData, meta interface{}) erro conn := meta.(*AWSClient).sfnconn if d.HasChange("tags") { - oldTagsRaw, newTagsRaw := d.GetChange("tags") - oldTagsMap := oldTagsRaw.(map[string]interface{}) - newTagsMap := newTagsRaw.(map[string]interface{}) - createTags, removeTags := diffTagsSfn(tagsFromMapSfn(oldTagsMap), tagsFromMapSfn(newTagsMap)) - - if len(removeTags) > 0 { - removeTagKeys := make([]*string, len(removeTags)) - for i, removeTag := range removeTags { - removeTagKeys[i] = removeTag.Key - } - - input := &sfn.UntagResourceInput{ - ResourceArn: aws.String(d.Id()), - TagKeys: removeTagKeys, - } - - log.Printf("[DEBUG] Untagging State Function Activity: %s", input) - if _, err := conn.UntagResource(input); err != nil { - return fmt.Errorf("error untagging State Function Activity (%s): %s", d.Id(), err) - } - } - - if len(createTags) > 0 { - input := &sfn.TagResourceInput{ - ResourceArn: aws.String(d.Id()), - Tags: createTags, - } - - log.Printf("[DEBUG] Tagging State Function Activity: %s", input) - if _, err := conn.TagResource(input); err != nil { - return fmt.Errorf("error tagging State Function Activity (%s): %s", d.Id(), err) - } + o, n := d.GetChange("tags") + if err := keyvaluetags.SfnUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) } } @@ -122,17 +94,13 @@ func resourceAwsSfnActivityRead(d *schema.ResourceData, meta interface{}) error log.Printf("[DEBUG] Error setting creation_date: %s", err) } - tagsResp, err := conn.ListTagsForResource( - &sfn.ListTagsForResourceInput{ - ResourceArn: aws.String(d.Id()), - }, - ) + tags, err := keyvaluetags.SfnListTags(conn, d.Id()) if err != nil { - return fmt.Errorf("error listing SFN Activity (%s) tags: %s", d.Id(), err) + return fmt.Errorf("error listing tags for SFN Activity (%s): %s", d.Id(), err) } - if err := d.Set("tags", tagsToMapSfn(tagsResp.Tags)); err != nil { + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } diff --git a/aws/resource_aws_sfn_state_machine.go b/aws/resource_aws_sfn_state_machine.go index 1d735651982..bbeb5ed6e34 100644 --- a/aws/resource_aws_sfn_state_machine.go +++ b/aws/resource_aws_sfn_state_machine.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsSfnStateMachine() *schema.Resource { @@ -65,7 +66,7 @@ func resourceAwsSfnStateMachineCreate(d *schema.ResourceData, meta interface{}) Definition: aws.String(d.Get("definition").(string)), Name: aws.String(d.Get("name").(string)), RoleArn: aws.String(d.Get("role_arn").(string)), - Tags: tagsFromMapSfn(d.Get("tags").(map[string]interface{})), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().SfnTags(), } var activity *sfn.CreateStateMachineOutput @@ -127,23 +128,13 @@ func resourceAwsSfnStateMachineRead(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Error setting creation_date: %s", err) } - tags := map[string]string{} - - tagsResp, err := conn.ListTagsForResource( - &sfn.ListTagsForResourceInput{ - ResourceArn: aws.String(d.Id()), - }, - ) + tags, err := keyvaluetags.SfnListTags(conn, d.Id()) if err != nil && !isAWSErr(err, "UnknownOperationException", "") { - return fmt.Errorf("error listing SFN Activity (%s) tags: %s", d.Id(), err) - } - - if tagsResp != nil { - tags = tagsToMapSfn(tagsResp.Tags) + return fmt.Errorf("error listing tags for SFN State Machine (%s): %s", d.Id(), err) } - if err := d.Set("tags", tags); err != nil { + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { return fmt.Errorf("error setting tags: %s", err) } @@ -171,40 +162,12 @@ func resourceAwsSfnStateMachineUpdate(d *schema.ResourceData, meta interface{}) } if d.HasChange("tags") { - oldTagsRaw, newTagsRaw := d.GetChange("tags") - oldTagsMap := oldTagsRaw.(map[string]interface{}) - newTagsMap := newTagsRaw.(map[string]interface{}) - createTags, removeTags := diffTagsSfn(tagsFromMapSfn(oldTagsMap), tagsFromMapSfn(newTagsMap)) - - if len(removeTags) > 0 { - removeTagKeys := make([]*string, len(removeTags)) - for i, removeTag := range removeTags { - removeTagKeys[i] = removeTag.Key - } - - input := &sfn.UntagResourceInput{ - ResourceArn: aws.String(d.Id()), - TagKeys: removeTagKeys, - } - - log.Printf("[DEBUG] Untagging State Function: %s", input) - if _, err := conn.UntagResource(input); err != nil { - return fmt.Errorf("error untagging State Function (%s): %s", d.Id(), err) - } - } - - if len(createTags) > 0 { - input := &sfn.TagResourceInput{ - ResourceArn: aws.String(d.Id()), - Tags: createTags, - } - - log.Printf("[DEBUG] Tagging State Function: %s", input) - if _, err := conn.TagResource(input); err != nil { - return fmt.Errorf("error tagging State Function (%s): %s", d.Id(), err) - } + o, n := d.GetChange("tags") + if err := keyvaluetags.SfnUpdateTags(conn, d.Id(), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) } } + return resourceAwsSfnStateMachineRead(d, meta) } diff --git a/aws/tagsSfn.go b/aws/tagsSfn.go deleted file mode 100644 index 093fbc78fa4..00000000000 --- a/aws/tagsSfn.go +++ /dev/null @@ -1,78 +0,0 @@ -package aws - -import ( - "log" - "regexp" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/sfn" -) - -// diffTags takes our tags locally and the ones remotely and returns -// the set of tags that must be created, and the set of tags that must -// be destroyed. -func diffTagsSfn(oldTags, newTags []*sfn.Tag) ([]*sfn.Tag, []*sfn.Tag) { - // First, we're creating everything we have - create := make(map[string]interface{}) - for _, t := range newTags { - create[aws.StringValue(t.Key)] = aws.StringValue(t.Value) - } - - // Build the list of what to remove - var remove []*sfn.Tag - for _, t := range oldTags { - old, ok := create[aws.StringValue(t.Key)] - if !ok || old != aws.StringValue(t.Value) { - // Delete it! - remove = append(remove, t) - } else if ok { - // already present so remove from new - delete(create, aws.StringValue(t.Key)) - } - } - - return tagsFromMapSfn(create), remove -} - -// tagsFromMap returns the tags for the given map of data. -func tagsFromMapSfn(tagMap map[string]interface{}) []*sfn.Tag { - tags := make([]*sfn.Tag, 0, len(tagMap)) - for tagKey, tagValueRaw := range tagMap { - tag := &sfn.Tag{ - Key: aws.String(tagKey), - Value: aws.String(tagValueRaw.(string)), - } - if !tagIgnoredSfn(tag) { - tags = append(tags, tag) - } - } - - return tags -} - -// tagsToMap turns the list of tags into a map. -func tagsToMapSfn(tags []*sfn.Tag) map[string]string { - tagMap := make(map[string]string) - for _, tag := range tags { - if !tagIgnoredSfn(tag) { - tagMap[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) - } - } - - return tagMap -} - -// compare a tag against a list of strings and checks if it should -// be ignored or not -func tagIgnoredSfn(t *sfn.Tag) bool { - filter := []string{"^aws:"} - for _, v := range filter { - log.Printf("[DEBUG] Matching %v with %v\n", v, aws.StringValue(t.Key)) - r, _ := regexp.MatchString(v, aws.StringValue(t.Key)) - if r { - log.Printf("[DEBUG] Found AWS specific tag %s (val: %s), ignoring.\n", aws.StringValue(t.Key), aws.StringValue(t.Value)) - return true - } - } - return false -} diff --git a/aws/tagsSfn_test.go b/aws/tagsSfn_test.go deleted file mode 100644 index cdb727ef7ec..00000000000 --- a/aws/tagsSfn_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package aws - -import ( - "reflect" - "testing" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/sfn" -) - -func TestDiffSfnTags(t *testing.T) { - cases := []struct { - Old, New map[string]interface{} - Create, Remove map[string]string - }{ - // Add - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - Create: map[string]string{ - "bar": "baz", - }, - Remove: map[string]string{}, - }, - - // Modify - { - Old: map[string]interface{}{ - "foo": "bar", - }, - New: map[string]interface{}{ - "foo": "baz", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Overlap - { - Old: map[string]interface{}{ - "foo": "bar", - "hello": "world", - }, - New: map[string]interface{}{ - "foo": "baz", - "hello": "world", - }, - Create: map[string]string{ - "foo": "baz", - }, - Remove: map[string]string{ - "foo": "bar", - }, - }, - - // Remove - { - Old: map[string]interface{}{ - "foo": "bar", - "bar": "baz", - }, - New: map[string]interface{}{ - "foo": "bar", - }, - Create: map[string]string{}, - Remove: map[string]string{ - "bar": "baz", - }, - }, - } - - for i, tc := range cases { - c, r := diffTagsSfn(tagsFromMapSfn(tc.Old), tagsFromMapSfn(tc.New)) - cm := tagsToMapSfn(c) - rm := tagsToMapSfn(r) - if !reflect.DeepEqual(cm, tc.Create) { - t.Fatalf("%d: bad create: %#v", i, cm) - } - if !reflect.DeepEqual(rm, tc.Remove) { - t.Fatalf("%d: bad remove: %#v", i, rm) - } - } -} - -func TestIgnoringTagsSfn(t *testing.T) { - ignoredTags := []*sfn.Tag{ - { - Key: aws.String("aws:cloudformation:logical-id"), - Value: aws.String("foo"), - }, - { - Key: aws.String("aws:foo:bar"), - Value: aws.String("baz"), - }, - } - for _, tag := range ignoredTags { - if !tagIgnoredSfn(tag) { - t.Fatalf("Tag %v with value %v not ignored, but should be!", *tag.Key, *tag.Value) - } - } -} From 581cc7924ac2c02b93cb55c5e3b8281368fd6ac2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 15 Nov 2019 14:52:57 -0500 Subject: [PATCH 30/38] resource/aws_s3_bucket_inventory: Add support for 'IntelligentTieringAccessTier'. (#10746) Output from acceptance testing: ``` --- PASS: TestAccAWSS3BucketInventory_encryptWithSSES3 (27.93s) --- PASS: TestAccAWSS3BucketInventory_basic (29.30s) --- PASS: TestAccAWSS3BucketInventory_encryptWithSSEKMS (50.53s) ``` --- aws/provider_test.go | 14 +++++- aws/resource_aws_s3_bucket_inventory.go | 6 ++- aws/resource_aws_s3_bucket_inventory_test.go | 47 +++++++++---------- .../docs/r/s3_bucket_inventory.html.markdown | 19 ++++---- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/aws/provider_test.go b/aws/provider_test.go index 9509ad85791..b7672f3db0d 100644 --- a/aws/provider_test.go +++ b/aws/provider_test.go @@ -128,7 +128,7 @@ func testAccMatchResourceAttrRegionalARN(resourceName, attributeName, arnService } } -// testAccMatchResourceAttrRegionalARN ensures the Terraform state regexp matches a formatted ARN with region and no account id +// testAccMatchResourceAttrRegionalARNNoAccount ensures the Terraform state regexp matches a formatted ARN with region but without account ID func testAccMatchResourceAttrRegionalARNNoAccount(resourceName, attributeName, arnService string, arnResourceRegexp *regexp.Regexp) resource.TestCheckFunc { return func(s *terraform.State) error { arnRegexp := arn.ARN{ @@ -161,6 +161,18 @@ func testAccCheckResourceAttrGlobalARN(resourceName, attributeName, arnService, } } +// testAccCheckResourceAttrGlobalARNNoAccount ensures the Terraform state exactly matches a formatted ARN without region or account ID +func testAccCheckResourceAttrGlobalARNNoAccount(resourceName, attributeName, arnService, arnResource string) resource.TestCheckFunc { + return func(s *terraform.State) error { + attributeValue := arn.ARN{ + Partition: testAccGetPartition(), + Resource: arnResource, + Service: arnService, + }.String() + return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s) + } +} + // testAccMatchResourceAttrGlobalARN ensures the Terraform state regexp matches a formatted ARN without region func testAccMatchResourceAttrGlobalARN(resourceName, attributeName, arnService string, arnResourceRegexp *regexp.Regexp) resource.TestCheckFunc { return func(s *terraform.State) error { diff --git a/aws/resource_aws_s3_bucket_inventory.go b/aws/resource_aws_s3_bucket_inventory.go index 79f2201a30f..f503e3ff0f7 100644 --- a/aws/resource_aws_s3_bucket_inventory.go +++ b/aws/resource_aws_s3_bucket_inventory.go @@ -82,8 +82,9 @@ func resourceAwsS3BucketInventory() *schema.Resource { ValidateFunc: validateArn, }, "account_id": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateAwsAccountId, }, "prefix": { Type: schema.TypeString, @@ -172,6 +173,7 @@ func resourceAwsS3BucketInventory() *schema.Resource { s3.InventoryOptionalFieldObjectLockMode, s3.InventoryOptionalFieldObjectLockRetainUntilDate, s3.InventoryOptionalFieldObjectLockLegalHoldStatus, + s3.InventoryOptionalFieldIntelligentTieringAccessTier, }, false), }, Set: schema.HashString, diff --git a/aws/resource_aws_s3_bucket_inventory_test.go b/aws/resource_aws_s3_bucket_inventory_test.go index 0add90ae6bb..960a0e67e1d 100644 --- a/aws/resource_aws_s3_bucket_inventory_test.go +++ b/aws/resource_aws_s3_bucket_inventory_test.go @@ -44,8 +44,8 @@ func TestAccAWSS3BucketInventory_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "destination.#", "1"), resource.TestCheckResourceAttr(resourceName, "destination.0.bucket.#", "1"), - resource.TestCheckResourceAttr(resourceName, "destination.0.bucket.0.bucket_arn", "arn:aws:s3:::"+bucketName), - resource.TestCheckResourceAttrSet(resourceName, "destination.0.bucket.0.account_id"), + testAccCheckResourceAttrGlobalARNNoAccount(resourceName, "destination.0.bucket.0.bucket_arn", "s3", bucketName), + testAccCheckResourceAttrAccountID(resourceName, "destination.0.bucket.0.account_id"), resource.TestCheckResourceAttr(resourceName, "destination.0.bucket.0.format", "ORC"), resource.TestCheckResourceAttr(resourceName, "destination.0.bucket.0.prefix", "inventory"), ), @@ -191,21 +191,20 @@ func testAccCheckAWSS3BucketInventoryDestroy(s *terraform.State) error { func testAccAWSS3BucketInventoryConfigBucket(name string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "bucket" { - bucket = "%s" +resource "aws_s3_bucket" "test" { + bucket = %[1]q acl = "private" } `, name) } func testAccAWSS3BucketInventoryConfig(bucketName, inventoryName string) string { - return fmt.Sprintf(` -%s + return testAccAWSS3BucketInventoryConfigBucket(bucketName) + fmt.Sprintf(` data "aws_caller_identity" "current" {} resource "aws_s3_bucket_inventory" "test" { - bucket = "${aws_s3_bucket.bucket.id}" - name = "%s" + bucket = "${aws_s3_bucket.test.id}" + name = %[1]q included_object_versions = "All" @@ -225,21 +224,20 @@ resource "aws_s3_bucket_inventory" "test" { destination { bucket { format = "ORC" - bucket_arn = "${aws_s3_bucket.bucket.arn}" + bucket_arn = "${aws_s3_bucket.test.arn}" account_id = "${data.aws_caller_identity.current.account_id}" prefix = "inventory" } } } -`, testAccAWSS3BucketInventoryConfigBucket(bucketName), inventoryName) +`, inventoryName) } func testAccAWSS3BucketInventoryConfigEncryptWithSSES3(bucketName, inventoryName string) string { - return fmt.Sprintf(` -%s + return testAccAWSS3BucketInventoryConfigBucket(bucketName) + fmt.Sprintf(` resource "aws_s3_bucket_inventory" "test" { - bucket = "${aws_s3_bucket.bucket.id}" - name = "%s" + bucket = "${aws_s3_bucket.test.id}" + name = %[1]q included_object_versions = "Current" @@ -250,7 +248,7 @@ resource "aws_s3_bucket_inventory" "test" { destination { bucket { format = "CSV" - bucket_arn = "${aws_s3_bucket.bucket.arn}" + bucket_arn = "${aws_s3_bucket.test.arn}" encryption { sse_s3 {} @@ -258,20 +256,19 @@ resource "aws_s3_bucket_inventory" "test" { } } } -`, testAccAWSS3BucketInventoryConfigBucket(bucketName), inventoryName) +`, inventoryName) } func testAccAWSS3BucketInventoryConfigEncryptWithSSEKMS(bucketName, inventoryName string) string { - return fmt.Sprintf(` -%s -resource "aws_kms_key" "inventory" { - description = "Terraform acc test S3 inventory SSE-KMS encryption: %s" + return testAccAWSS3BucketInventoryConfigBucket(bucketName) + fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = "Terraform acc test S3 inventory SSE-KMS encryption: %[1]s" deletion_window_in_days = 7 } resource "aws_s3_bucket_inventory" "test" { - bucket = "${aws_s3_bucket.bucket.id}" - name = "%s" + bucket = "${aws_s3_bucket.test.id}" + name = %[2]q included_object_versions = "Current" @@ -282,15 +279,15 @@ resource "aws_s3_bucket_inventory" "test" { destination { bucket { format = "Parquet" - bucket_arn = "${aws_s3_bucket.bucket.arn}" + bucket_arn = "${aws_s3_bucket.test.arn}" encryption { sse_kms { - key_id = "${aws_kms_key.inventory.arn}" + key_id = "${aws_kms_key.test.arn}" } } } } } -`, testAccAWSS3BucketInventoryConfigBucket(bucketName), bucketName, inventoryName) +`, bucketName, inventoryName) } diff --git a/website/docs/r/s3_bucket_inventory.html.markdown b/website/docs/r/s3_bucket_inventory.html.markdown index f482aa183ef..024ed15e434 100644 --- a/website/docs/r/s3_bucket_inventory.html.markdown +++ b/website/docs/r/s3_bucket_inventory.html.markdown @@ -81,22 +81,23 @@ resource "aws_s3_bucket_inventory" "test-prefix" { The following arguments are supported: -* `bucket` - (Required) The name of the bucket to put inventory configuration. +* `bucket` - (Required) The name of the bucket where the inventory configuration will be stored. * `name` - (Required) Unique identifier of the inventory configuration for the bucket. -* `included_object_versions` - (Required) Object filtering that accepts a prefix (documented below). Can be `All` or `Current`. -* `schedule` - (Required) Contains the frequency for generating inventory results (documented below). -* `destination` - (Required) Destination bucket where inventory list files are written (documented below). -* `enabled` - (Optional, Default: true) Specifies whether the inventory is enabled or disabled. -* `filter` - (Optional) Object filtering that accepts a prefix (documented below). -* `optional_fields` - (Optional) Contains the optional fields that are included in the inventory results. +* `included_object_versions` - (Required) Object versions to include in the inventory list. Valid values: `All`, `Current`. +* `schedule` - (Required) Specifies the schedule for generating inventory results (documented below). +* `destination` - (Required) Contains information about where to publish the inventory results (documented below). +* `enabled` - (Optional, Default: `true`) Specifies whether the inventory is enabled or disabled. +* `filter` - (Optional) Specifies an inventory filter. The inventory only includes objects that meet the filter's criteria (documented below). +* `optional_fields` - (Optional) List of optional fields that are included in the inventory results. +Valid values: `Size`, `LastModifiedDate`, `StorageClass`, `ETag`, `IsMultipartUploaded`, `ReplicationStatus`, `EncryptionStatus`, `ObjectLockRetainUntilDate`, `ObjectLockMode`, `ObjectLockLegalHoldStatus`, `IntelligentTieringAccessTier`. The `filter` configuration supports the following: -* `prefix` - (Optional) Object prefix for filtering (singular). +* `prefix` - (Optional) The prefix that an object must have to be included in the inventory results. The `schedule` configuration supports the following: -* `frequency` - (Required) Specifies how frequently inventory results are produced. Can be `Daily` or `Weekly`. +* `frequency` - (Required) Specifies how frequently inventory results are produced. Valid values: `Daily`, `Weekly`. The `destination` configuration supports the following: From 0c0f604c172f63018d9f732ea4f7af4d8ed4ce07 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 14:54:45 -0500 Subject: [PATCH 31/38] Update CHANGELOG for #10746 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef956cf756..6de9ff51af2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ENHANCEMENTS: * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] +* resource/aws_s3_bucket_inventory: Add `IntelligentTieringAccessTier` as valid value for `optional_fields` argument [GH-10746] * resource/aws_waf_geo_match_set: Support resource import and add `arn` attribute [GH-10480] * resource/aws_waf_regex_match_set: Support resource import and add `arn` attribute [GH-10481] * resource/aws_waf_regex_pattern_set: Support resource import and add `arn` attribute [GH-10482] From 17c05f528689d31447cd945e7ec3c3649b856d0f Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 15:11:35 -0500 Subject: [PATCH 32/38] Update CHANGELOG for #10490 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6de9ff51af2..f8534c38978 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ENHANCEMENTS: * resource/aws_api_gateway_rest_api: Add `tags` argument and `arn` attribute [GH-10581] +* resource/aws_db_instance: Add `ca_cert_identifier` argument [GH-10490] * resource/aws_dlm_lifecycle_policy: Add `tags` argument and `arn` attribute [GH-10864] * resource/aws_efs_file_system: Add `AFTER_7_DAYS` as a valid `lifecycle_policy` configuratio block `transition_to_ia` argument value [GH-10825] * resource/aws_glue_crawler: Add `tags` argument [GH-10805] From d757599be2879377c1865ac71b577c5648482f3a Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 22:20:53 +0200 Subject: [PATCH 33/38] r/aws_wafregional_rule - add tagging support + expose arn + read after create (#10895) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegionalRule_disappears (36.53s) --- PASS: TestAccAWSWafRegionalRule_noPredicates (39.85s) --- PASS: TestAccAWSWafRegionalRule_tags (46.46s) --- PASS: TestAccAWSWafRegionalRule_changePredicates (72.39s) --- PASS: TestAccAWSWafRegionalRule_changeNameForceNew (74.27s) --- PASS: TestAccAWSWafRegionalRule_basic (92.20s) ``` --- aws/resource_aws_wafregional_rule.go | 56 +++++- aws/resource_aws_wafregional_rule_test.go | 168 ++++++++++++++---- website/docs/r/wafregional_rule.html.markdown | 2 + 3 files changed, 185 insertions(+), 41 deletions(-) diff --git a/aws/resource_aws_wafregional_rule.go b/aws/resource_aws_wafregional_rule.go index 7b139c555f4..b16703e3468 100644 --- a/aws/resource_aws_wafregional_rule.go +++ b/aws/resource_aws_wafregional_rule.go @@ -4,12 +4,13 @@ import ( "fmt" "log" - "github.com/aws/aws-sdk-go/service/wafregional" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/waf" + "github.com/aws/aws-sdk-go/service/wafregional" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsWafRegionalRule() *schema.Resource { @@ -55,6 +56,11 @@ func resourceAwsWafRegionalRule() *schema.Resource { }, }, }, + "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -62,6 +68,7 @@ func resourceAwsWafRegionalRule() *schema.Resource { func resourceAwsWafRegionalRuleCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).wafregionalconn region := meta.(*AWSClient).region + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().WafregionalTags() wr := newWafRegionalRetryer(conn, region) out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { @@ -71,6 +78,10 @@ func resourceAwsWafRegionalRuleCreate(d *schema.ResourceData, meta interface{}) Name: aws.String(d.Get("name").(string)), } + if len(tags) > 0 { + params.Tags = tags + } + return conn.CreateRule(params) }) if err != nil { @@ -78,7 +89,16 @@ func resourceAwsWafRegionalRuleCreate(d *schema.ResourceData, meta interface{}) } resp := out.(*waf.CreateRuleOutput) d.SetId(*resp.Rule.RuleId) - return resourceAwsWafRegionalRuleUpdate(d, meta) + + newPredicates := d.Get("predicate").(*schema.Set).List() + if len(newPredicates) > 0 { + noPredicates := []interface{}{} + err := updateWafRegionalRuleResource(d.Id(), noPredicates, newPredicates, meta) + if err != nil { + return fmt.Errorf("Error Updating WAF Regional Rule: %s", err) + } + } + return resourceAwsWafRegionalRuleRead(d, meta) } func resourceAwsWafRegionalRuleRead(d *schema.ResourceData, meta interface{}) error { @@ -99,6 +119,25 @@ func resourceAwsWafRegionalRuleRead(d *schema.ResourceData, meta interface{}) er return err } + arn := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("rule/%s", d.Id()), + Service: "waf-regional", + }.String() + d.Set("arn", arn) + + tags, err := keyvaluetags.WafregionalListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for WAF Regional Rule (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + d.Set("predicate", flattenWafPredicates(resp.Rule.Predicates)) d.Set("name", resp.Rule.Name) d.Set("metric_name", resp.Rule.MetricName) @@ -107,6 +146,8 @@ func resourceAwsWafRegionalRuleRead(d *schema.ResourceData, meta interface{}) er } func resourceAwsWafRegionalRuleUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafregionalconn + if d.HasChange("predicate") { o, n := d.GetChange("predicate") oldP, newP := o.(*schema.Set).List(), n.(*schema.Set).List() @@ -116,6 +157,15 @@ func resourceAwsWafRegionalRuleUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error Updating WAF Rule: %s", err) } } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.WafregionalUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + return resourceAwsWafRegionalRuleRead(d, meta) } diff --git a/aws/resource_aws_wafregional_rule_test.go b/aws/resource_aws_wafregional_rule_test.go index 236700d9397..899b4da9374 100644 --- a/aws/resource_aws_wafregional_rule_test.go +++ b/aws/resource_aws_wafregional_rule_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -130,12 +131,10 @@ func TestAccAWSWafRegionalRule_basic(t *testing.T) { Config: testAccAWSWafRegionalRuleConfig(wafRuleName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRuleExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafRuleName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "waf-regional", regexp.MustCompile(`rule/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleName), ), }, { @@ -147,6 +146,50 @@ func TestAccAWSWafRegionalRule_basic(t *testing.T) { }) } +func TestAccAWSWafRegionalRule_tags(t *testing.T) { + var v waf.Rule + wafRuleName := fmt.Sprintf("wafrule%s", acctest.RandString(5)) + resourceName := "aws_wafregional_rule.wafrule" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalRuleConfigTags1(wafRuleName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRuleExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSWafRegionalRuleConfigTags2(wafRuleName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRuleExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSWafRegionalRuleConfigTags1(wafRuleName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRuleExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccAWSWafRegionalRule_changeNameForceNew(t *testing.T) { var before, after waf.Rule wafRuleName := fmt.Sprintf("wafrule%s", acctest.RandString(5)) @@ -162,24 +205,18 @@ func TestAccAWSWafRegionalRule_changeNameForceNew(t *testing.T) { Config: testAccAWSWafRegionalRuleConfig(wafRuleName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRuleExists(resourceName, &before), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleName), ), }, { Config: testAccAWSWafRegionalRuleConfigChangeName(wafRuleNewName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRuleExists(resourceName, &after), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleNewName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafRuleNewName), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleNewName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleNewName), ), }, { @@ -227,10 +264,8 @@ func TestAccAWSWafRegionalRule_noPredicates(t *testing.T) { Config: testAccAWSWafRegionalRule_noPredicates(wafRuleName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSWafRegionalRuleExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "0"), ), }, { @@ -414,7 +449,31 @@ func testAccCheckAWSWafRegionalRuleExists(n string, v *waf.Rule) resource.TestCh func testAccAWSWafRegionalRuleConfig(name string) string { return fmt.Sprintf(` resource "aws_wafregional_ipset" "ipset" { - name = "%s" + name = %[1]q + + ip_set_descriptor { + type = "IPV4" + value = "192.0.7.0/24" + } +} + +resource "aws_wafregional_rule" "wafrule" { + name = %[1]q + metric_name = %[1]q + + predicate { + data_id = "${aws_wafregional_ipset.ipset.id}" + negated = false + type = "IPMatch" + } +} +`, name) +} + +func testAccAWSWafRegionalRuleConfigTags1(name, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_ipset" "ipset" { + name = %[1]q ip_set_descriptor { type = "IPV4" @@ -423,22 +482,55 @@ resource "aws_wafregional_ipset" "ipset" { } resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q predicate { data_id = "${aws_wafregional_ipset.ipset.id}" negated = false type = "IPMatch" } + + tags = { + %[2]q = %[3]q + } +} +`, name, tagKey1, tagValue1) +} + +func testAccAWSWafRegionalRuleConfigTags2(name, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_ipset" "ipset" { + name = %[1]q + + ip_set_descriptor { + type = "IPV4" + value = "192.0.7.0/24" + } +} + +resource "aws_wafregional_rule" "wafrule" { + name = %[1]q + metric_name = %[1]q + + predicate { + data_id = "${aws_wafregional_ipset.ipset.id}" + negated = false + type = "IPMatch" + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } } -`, name, name, name) +`, name, tagKey1, tagValue1, tagKey2, tagValue2) } func testAccAWSWafRegionalRuleConfigChangeName(name string) string { return fmt.Sprintf(` resource "aws_wafregional_ipset" "ipset" { - name = "%s" + name = %[1]q ip_set_descriptor { type = "IPV4" @@ -447,8 +539,8 @@ resource "aws_wafregional_ipset" "ipset" { } resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q predicate { data_id = "${aws_wafregional_ipset.ipset.id}" @@ -456,22 +548,22 @@ resource "aws_wafregional_rule" "wafrule" { type = "IPMatch" } } -`, name, name, name) +`, name) } func testAccAWSWafRegionalRule_noPredicates(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q } -`, name, name) +`, name) } func testAccAWSWafRegionalRule_changePredicates(name string) string { return fmt.Sprintf(` resource "aws_wafregional_ipset" "ipset" { - name = "%s" + name = %[1]q ip_set_descriptor { type = "IPV4" @@ -480,7 +572,7 @@ resource "aws_wafregional_ipset" "ipset" { } resource "aws_wafregional_xss_match_set" "xss_match_set" { - name = "%s" + name = %[1]q xss_match_tuple { text_transformation = "NONE" @@ -492,8 +584,8 @@ resource "aws_wafregional_xss_match_set" "xss_match_set" { } resource "aws_wafregional_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q predicate { data_id = "${aws_wafregional_xss_match_set.xss_match_set.id}" @@ -507,5 +599,5 @@ resource "aws_wafregional_rule" "wafrule" { type = "IPMatch" } } -`, name, name, name, name) +`, name) } diff --git a/website/docs/r/wafregional_rule.html.markdown b/website/docs/r/wafregional_rule.html.markdown index 3c7eff003b7..df887bcf187 100644 --- a/website/docs/r/wafregional_rule.html.markdown +++ b/website/docs/r/wafregional_rule.html.markdown @@ -41,6 +41,7 @@ The following arguments are supported: * `name` - (Required) The name or description of the rule. * `metric_name` - (Required) The name or description for the Amazon CloudWatch metric of this rule. * `predicate` - (Optional) The objects to include in a rule (documented below). +* `tags` - (Optional) Key-value mapping of resource tags ## Nested Fields @@ -61,6 +62,7 @@ See the [WAF Documentation](https://docs.aws.amazon.com/waf/latest/APIReference/ In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF Regional Rule. +* `arn` - The ARN of the WAF Regional Rule. ## Import From ce8745c845bc4e9e0541394352eda8b6e5304dd1 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 15:21:35 -0500 Subject: [PATCH 34/38] Update CHANGELOG for #10895 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8534c38978..387d09f9d81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ENHANCEMENTS: * resource/aws_waf_regex_pattern_set: Support resource import and add `arn` attribute [GH-10482] * resource/aws_waf_size_constraint_set: Support resource import and add `arn` attribute [GH-10484] * resource/aws_waf_xss_match_set: Support resource import and add `arn` attribute [GH-10485] +* resource/aws_wafregional_rule: Add `tags` argument and `arn` attribute [GH-10895] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] * resource/aws_wafregional_web_acl_association: Support resource import [GH-10538] From 91a6c37b82adcfbd9f3f2a8d69025bccce6b5d1d Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 22:26:20 +0200 Subject: [PATCH 35/38] r/aws_wafregional_rule_group - add tagging support + expose arn + read after create (#10896) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegionalRuleGroup_noActivatedRules (16.87s) --- PASS: TestAccAWSWafRegionalRuleGroup_tags (35.24s) --- PASS: TestAccAWSWafRegionalRuleGroup_disappears (36.43s) --- PASS: TestAccAWSWafRegionalRuleGroup_changeNameForceNew (38.47s) --- PASS: TestAccAWSWafRegionalRuleGroup_changeActivatedRules (45.89s) --- PASS: TestAccAWSWafRegionalRuleGroup_basic (48.20s) ``` --- aws/resource_aws_wafregional_rule_group.go | 50 +++++++- ...esource_aws_wafregional_rule_group_test.go | 113 +++++++++++++++++- .../r/wafregional_rule_group.html.markdown | 2 + 3 files changed, 160 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_wafregional_rule_group.go b/aws/resource_aws_wafregional_rule_group.go index 5d01c1204dd..48b5d97e906 100644 --- a/aws/resource_aws_wafregional_rule_group.go +++ b/aws/resource_aws_wafregional_rule_group.go @@ -5,9 +5,11 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/waf" "github.com/aws/aws-sdk-go/service/wafregional" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsWafRegionalRuleGroup() *schema.Resource { @@ -66,6 +68,11 @@ func resourceAwsWafRegionalRuleGroup() *schema.Resource { }, }, }, + "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -73,6 +80,7 @@ func resourceAwsWafRegionalRuleGroup() *schema.Resource { func resourceAwsWafRegionalRuleGroupCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).wafregionalconn region := meta.(*AWSClient).region + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().WafregionalTags() wr := newWafRegionalRetryer(conn, region) out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { @@ -82,6 +90,10 @@ func resourceAwsWafRegionalRuleGroupCreate(d *schema.ResourceData, meta interfac Name: aws.String(d.Get("name").(string)), } + if len(tags) > 0 { + params.Tags = tags + } + return conn.CreateRuleGroup(params) }) if err != nil { @@ -89,7 +101,18 @@ func resourceAwsWafRegionalRuleGroupCreate(d *schema.ResourceData, meta interfac } resp := out.(*waf.CreateRuleGroupOutput) d.SetId(*resp.RuleGroup.RuleGroupId) - return resourceAwsWafRegionalRuleGroupUpdate(d, meta) + + activatedRule := d.Get("activated_rule").(*schema.Set).List() + if len(activatedRule) > 0 { + noActivatedRules := []interface{}{} + + err := updateWafRuleGroupResourceWR(d.Id(), noActivatedRules, activatedRule, conn, region) + if err != nil { + return fmt.Errorf("Error Updating WAF Regional Rule Group: %s", err) + } + } + + return resourceAwsWafRegionalRuleGroupRead(d, meta) } func resourceAwsWafRegionalRuleGroupRead(d *schema.ResourceData, meta interface{}) error { @@ -117,6 +140,23 @@ func resourceAwsWafRegionalRuleGroupRead(d *schema.ResourceData, meta interface{ return fmt.Errorf("error listing activated rules in WAF Regional Rule Group (%s): %s", d.Id(), err) } + arn := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("rulegroup/%s", d.Id()), + Service: "waf-regional", + }.String() + d.Set("arn", arn) + + tags, err := keyvaluetags.WafregionalListTags(conn, arn) + if err != nil { + return fmt.Errorf("error listing tags for WAF Regional Rule Group (%s): %s", arn, err) + } + if err := d.Set("tags", tags.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + d.Set("activated_rule", flattenWafActivatedRules(rResp.ActivatedRules)) d.Set("name", resp.RuleGroup.Name) d.Set("metric_name", resp.RuleGroup.MetricName) @@ -138,6 +178,14 @@ func resourceAwsWafRegionalRuleGroupUpdate(d *schema.ResourceData, meta interfac } } + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.WafregionalUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + return resourceAwsWafRegionalRuleGroupRead(d, meta) } diff --git a/aws/resource_aws_wafregional_rule_group_test.go b/aws/resource_aws_wafregional_rule_group_test.go index 2a20ef01e75..780fc656e60 100644 --- a/aws/resource_aws_wafregional_rule_group_test.go +++ b/aws/resource_aws_wafregional_rule_group_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -78,6 +79,7 @@ func TestAccAWSWafRegionalRuleGroup_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRuleExists("aws_wafregional_rule.test", &rule), testAccCheckAWSWafRegionalRuleGroupExists(resourceName, &group), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "waf-regional", regexp.MustCompile(`rulegroup/.+`)), resource.TestCheckResourceAttr(resourceName, "name", groupName), resource.TestCheckResourceAttr(resourceName, "activated_rule.#", "1"), resource.TestCheckResourceAttr(resourceName, "metric_name", groupName), @@ -96,6 +98,56 @@ func TestAccAWSWafRegionalRuleGroup_basic(t *testing.T) { }) } +func TestAccAWSWafRegionalRuleGroup_tags(t *testing.T) { + var rule waf.Rule + var group waf.RuleGroup + + ruleName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + groupName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + resourceName := "aws_wafregional_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalRuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalRuleGroupConfigTags1(ruleName, groupName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRuleExists("aws_wafregional_rule.test", &rule), + testAccCheckAWSWafRegionalRuleGroupExists(resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSWafRegionalRuleGroupConfigTags2(ruleName, groupName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRuleExists("aws_wafregional_rule.test", &rule), + testAccCheckAWSWafRegionalRuleGroupExists(resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSWafRegionalRuleGroupConfigTags1(ruleName, groupName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRuleExists("aws_wafregional_rule.test", &rule), + testAccCheckAWSWafRegionalRuleGroupExists(resourceName, &group), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccAWSWafRegionalRuleGroup_changeNameForceNew(t *testing.T) { var before, after waf.RuleGroup @@ -237,10 +289,8 @@ func TestAccAWSWafRegionalRuleGroup_noActivatedRules(t *testing.T) { Config: testAccAWSWafRegionalRuleGroupConfig_noActivatedRules(groupName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSWafRegionalRuleGroupExists(resourceName, &group), - resource.TestCheckResourceAttr( - resourceName, "name", groupName), - resource.TestCheckResourceAttr( - resourceName, "activated_rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", groupName), + resource.TestCheckResourceAttr(resourceName, "activated_rule.#", "0"), ), }, }, @@ -373,6 +423,61 @@ resource "aws_wafregional_rule_group" "test" { `, ruleName, groupName) } +func testAccAWSWafRegionalRuleGroupConfigTags1(ruleName, groupName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_rule" "test" { + name = %[1]q + metric_name = %[1]q +} + +resource "aws_wafregional_rule_group" "test" { + name = %[2]q + metric_name = %[2]q + + activated_rule { + action { + type = "COUNT" + } + + priority = 50 + rule_id = "${aws_wafregional_rule.test.id}" + } + + tags = { + %[3]q = %[4]q + } +} +`, ruleName, groupName, tagKey1, tagValue1) +} + +func testAccAWSWafRegionalRuleGroupConfigTags2(ruleName, groupName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_rule" "test" { + name = %[1]q + metric_name = %[1]q +} + +resource "aws_wafregional_rule_group" "test" { + name = %[2]q + metric_name = %[2]q + + activated_rule { + action { + type = "COUNT" + } + + priority = 50 + rule_id = "${aws_wafregional_rule.test.id}" + } + + tags = { + %[3]q = %[4]q + %[5]q = %[6]q + } +} +`, ruleName, groupName, tagKey1, tagValue1, tagKey2, tagValue2) +} + func testAccAWSWafRegionalRuleGroupConfig_changeActivatedRules(ruleName1, ruleName2, ruleName3, groupName string) string { return fmt.Sprintf(` resource "aws_wafregional_rule" "test" { diff --git a/website/docs/r/wafregional_rule_group.html.markdown b/website/docs/r/wafregional_rule_group.html.markdown index 17049bee2fa..bd98bccf8a0 100644 --- a/website/docs/r/wafregional_rule_group.html.markdown +++ b/website/docs/r/wafregional_rule_group.html.markdown @@ -40,6 +40,7 @@ The following arguments are supported: * `name` - (Required) A friendly name of the rule group * `metric_name` - (Required) A friendly name for the metrics from the rule group * `activated_rule` - (Optional) A list of activated rules, see below +* `tags` - (Optional) Key-value mapping of resource tags ## Nested Blocks @@ -58,6 +59,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: * `id` - The ID of the WAF Regional Rule Group. +* `arn` - The ARN of the WAF Regional Rule Group. ## Import From 0760e61c01d47cb4b6bcf5b7b4ded566a17460de Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 15:27:05 -0500 Subject: [PATCH 36/38] Update CHANGELOG for #10896 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 387d09f9d81..24a245617ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ENHANCEMENTS: * resource/aws_waf_regex_pattern_set: Support resource import and add `arn` attribute [GH-10482] * resource/aws_waf_size_constraint_set: Support resource import and add `arn` attribute [GH-10484] * resource/aws_waf_xss_match_set: Support resource import and add `arn` attribute [GH-10485] +* resource/aws_wafregional_rule_group: Add `tags` argument and `arn` attribute [GH-10896] * resource/aws_wafregional_rule: Add `tags` argument and `arn` attribute [GH-10895] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889] * resource/aws_wafregional_web_acl_association: Support resource import [GH-10538] From 58032facc145be78696679089d8684fbe71f85de Mon Sep 17 00:00:00 2001 From: Ilia Lazebnik Date: Fri, 15 Nov 2019 22:40:51 +0200 Subject: [PATCH 37/38] add tagging support for waf regional rate base rule resource (#10897) Output from acceptance testing: ``` --- PASS: TestAccAWSWafRegionalRateBasedRule_noPredicates (16.12s) --- PASS: TestAccAWSWafRegionalRateBasedRule_changeRateLimit (18.16s) --- PASS: TestAccAWSWafRegionalRateBasedRule_tags (59.44s) --- PASS: TestAccAWSWafRegionalRateBasedRule_changeNameForceNew (63.98s) --- PASS: TestAccAWSWafRegionalRateBasedRule_basic (65.44s) --- PASS: TestAccAWSWafRegionalRateBasedRule_changePredicates (73.59s) --- PASS: TestAccAWSWafRegionalRateBasedRule_disappears (74.58s) ``` --- ...esource_aws_wafregional_rate_based_rule.go | 49 ++++- ...ce_aws_wafregional_rate_based_rule_test.go | 171 ++++++++++++++---- .../wafregional_rate_based_rule.html.markdown | 4 +- 3 files changed, 184 insertions(+), 40 deletions(-) diff --git a/aws/resource_aws_wafregional_rate_based_rule.go b/aws/resource_aws_wafregional_rate_based_rule.go index e329751a4d6..a6fe9f72063 100644 --- a/aws/resource_aws_wafregional_rate_based_rule.go +++ b/aws/resource_aws_wafregional_rate_based_rule.go @@ -5,10 +5,12 @@ import ( "log" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/waf" "github.com/aws/aws-sdk-go/service/wafregional" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsWafRegionalRateBasedRule() *schema.Resource { @@ -64,6 +66,11 @@ func resourceAwsWafRegionalRateBasedRule() *schema.Resource { Required: true, ValidateFunc: validation.IntAtLeast(100), }, + "tags": tagsSchema(), + "arn": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -71,6 +78,7 @@ func resourceAwsWafRegionalRateBasedRule() *schema.Resource { func resourceAwsWafRegionalRateBasedRuleCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).wafregionalconn region := meta.(*AWSClient).region + tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().WafregionalTags() wr := newWafRegionalRetryer(conn, region) out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { @@ -82,6 +90,10 @@ func resourceAwsWafRegionalRateBasedRuleCreate(d *schema.ResourceData, meta inte RateLimit: aws.Int64(int64(d.Get("rate_limit").(int))), } + if len(tags) > 0 { + params.Tags = tags + } + return conn.CreateRateBasedRule(params) }) if err != nil { @@ -89,7 +101,17 @@ func resourceAwsWafRegionalRateBasedRuleCreate(d *schema.ResourceData, meta inte } resp := out.(*waf.CreateRateBasedRuleOutput) d.SetId(*resp.Rule.RuleId) - return resourceAwsWafRegionalRateBasedRuleUpdate(d, meta) + + newPredicates := d.Get("predicate").(*schema.Set).List() + if len(newPredicates) > 0 { + noPredicates := []interface{}{} + err := updateWafRateBasedRuleResourceWR(d.Id(), noPredicates, newPredicates, d.Get("rate_limit"), conn, region) + if err != nil { + return fmt.Errorf("Error Updating WAF Rate Based Rule: %s", err) + } + } + + return resourceAwsWafRegionalRateBasedRuleRead(d, meta) } func resourceAwsWafRegionalRateBasedRuleRead(d *schema.ResourceData, meta interface{}) error { @@ -119,6 +141,23 @@ func resourceAwsWafRegionalRateBasedRuleRead(d *schema.ResourceData, meta interf }) } + arn := arn.ARN{ + AccountID: meta.(*AWSClient).accountid, + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Resource: fmt.Sprintf("ratebasedrule/%s", d.Id()), + Service: "waf-regional", + }.String() + d.Set("arn", arn) + + tagList, err := keyvaluetags.WafregionalListTags(conn, arn) + if err != nil { + return fmt.Errorf("Failed to get WAF Regional Rated Based Rule parameter tags for %s: %s", d.Get("name"), err) + } + if err := d.Set("tags", tagList.IgnoreAws().Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + d.Set("predicate", predicates) d.Set("name", resp.Rule.Name) d.Set("metric_name", resp.Rule.MetricName) @@ -148,6 +187,14 @@ func resourceAwsWafRegionalRateBasedRuleUpdate(d *schema.ResourceData, meta inte } } + if d.HasChange("tags") { + o, n := d.GetChange("tags") + + if err := keyvaluetags.WafregionalUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } + } + return resourceAwsWafRegionalRateBasedRuleRead(d, meta) } diff --git a/aws/resource_aws_wafregional_rate_based_rule_test.go b/aws/resource_aws_wafregional_rate_based_rule_test.go index 5157d2025cd..4c45493e926 100644 --- a/aws/resource_aws_wafregional_rate_based_rule_test.go +++ b/aws/resource_aws_wafregional_rate_based_rule_test.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -130,12 +131,10 @@ func TestAccAWSWafRegionalRateBasedRule_basic(t *testing.T) { Config: testAccAWSWafRegionalRateBasedRuleConfig(wafRuleName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &v), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafRuleName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "waf-regional", regexp.MustCompile(`ratebasedrule/.+`)), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleName), ), }, { @@ -147,6 +146,49 @@ func TestAccAWSWafRegionalRateBasedRule_basic(t *testing.T) { }) } +func TestAccAWSWafRegionalRateBasedRule_tags(t *testing.T) { + var v waf.RateBasedRule + resourceName := "aws_wafregional_rate_based_rule.wafrule" + wafRuleName := fmt.Sprintf("wafrule%s", acctest.RandString(5)) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalRateBasedRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalRateBasedRuleConfigTags1(wafRuleName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSWafRegionalRateBasedRuleConfigTags2(wafRuleName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSWafRegionalRateBasedRuleConfigTags1(wafRuleName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + func TestAccAWSWafRegionalRateBasedRule_changeNameForceNew(t *testing.T) { var before, after waf.RateBasedRule resourceName := "aws_wafregional_rate_based_rule.wafrule" @@ -162,12 +204,9 @@ func TestAccAWSWafRegionalRateBasedRule_changeNameForceNew(t *testing.T) { Config: testAccAWSWafRegionalRateBasedRuleConfig(wafRuleName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &before), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleName), ), }, { @@ -175,12 +214,9 @@ func TestAccAWSWafRegionalRateBasedRule_changeNameForceNew(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &after), testAccCheckAWSWafRateBasedRuleIdDiffers(&before, &after), - resource.TestCheckResourceAttr( - resourceName, "name", wafRuleNewName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "1"), - resource.TestCheckResourceAttr( - resourceName, "metric_name", wafRuleNewName), + resource.TestCheckResourceAttr(resourceName, "name", wafRuleNewName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "1"), + resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleNewName), ), }, { @@ -349,10 +385,8 @@ func TestAccAWSWafRegionalRateBasedRule_noPredicates(t *testing.T) { Config: testAccAWSWafRegionalRateBasedRuleConfig_noPredicates(ruleName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckAWSWafRegionalRateBasedRuleExists(resourceName, &rule), - resource.TestCheckResourceAttr( - resourceName, "name", ruleName), - resource.TestCheckResourceAttr( - resourceName, "predicate.#", "0"), + resource.TestCheckResourceAttr(resourceName, "name", ruleName), + resource.TestCheckResourceAttr(resourceName, "predicate.#", "0"), ), }, { @@ -479,7 +513,7 @@ func testAccCheckAWSWafRegionalRateBasedRuleExists(n string, v *waf.RateBasedRul func testAccAWSWafRegionalRateBasedRuleConfig(name string) string { return fmt.Sprintf(` resource "aws_wafregional_ipset" "ipset" { - name = "%s" + name = %[1]q ip_set_descriptor { type = "IPV4" @@ -488,8 +522,34 @@ resource "aws_wafregional_ipset" "ipset" { } resource "aws_wafregional_rate_based_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q + rate_key = "IP" + rate_limit = 2000 + + predicate { + data_id = "${aws_wafregional_ipset.ipset.id}" + negated = false + type = "IPMatch" + } +} +`, name) +} + +func testAccAWSWafRegionalRateBasedRuleConfigTags1(name, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_ipset" "ipset" { + name = %[1]q + + ip_set_descriptor { + type = "IPV4" + value = "192.0.7.0/24" + } +} + +resource "aws_wafregional_rate_based_rule" "wafrule" { + name = %[1]q + metric_name = %[1]q rate_key = "IP" rate_limit = 2000 @@ -498,14 +558,49 @@ resource "aws_wafregional_rate_based_rule" "wafrule" { negated = false type = "IPMatch" } + + tags = { + %[2]q = %[3]q + } } -`, name, name, name) +`, name, tagKey1, tagValue1) +} + +func testAccAWSWafRegionalRateBasedRuleConfigTags2(name, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_wafregional_ipset" "ipset" { + name = %[1]q + + ip_set_descriptor { + type = "IPV4" + value = "192.0.7.0/24" + } +} + +resource "aws_wafregional_rate_based_rule" "wafrule" { + name = %[1]q + metric_name = %[1]q + rate_key = "IP" + rate_limit = 2000 + + predicate { + data_id = "${aws_wafregional_ipset.ipset.id}" + negated = false + type = "IPMatch" + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, name, tagKey1, tagValue1, tagKey2, tagValue2) } func testAccAWSWafRegionalRateBasedRuleConfigChangeName(name string) string { return fmt.Sprintf(` resource "aws_wafregional_ipset" "ipset" { - name = "%s" + name = %[1]q ip_set_descriptor { type = "IPV4" @@ -514,8 +609,8 @@ resource "aws_wafregional_ipset" "ipset" { } resource "aws_wafregional_rate_based_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q rate_key = "IP" rate_limit = 2000 @@ -525,13 +620,13 @@ resource "aws_wafregional_rate_based_rule" "wafrule" { type = "IPMatch" } } -`, name, name, name) +`, name) } func testAccAWSWafRegionalRateBasedRuleConfig_changePredicates(name string) string { return fmt.Sprintf(` resource "aws_wafregional_ipset" "ipset" { - name = "%s" + name = %[1]q ip_set_descriptor { type = "IPV4" @@ -540,7 +635,7 @@ resource "aws_wafregional_ipset" "ipset" { } resource "aws_wafregional_byte_match_set" "set" { - name = "%s" + name = %[1]q byte_match_tuples { text_transformation = "NONE" @@ -555,8 +650,8 @@ resource "aws_wafregional_byte_match_set" "set" { } resource "aws_wafregional_rate_based_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q rate_key = "IP" rate_limit = 2000 @@ -566,18 +661,18 @@ resource "aws_wafregional_rate_based_rule" "wafrule" { type = "ByteMatch" } } -`, name, name, name, name) +`, name) } func testAccAWSWafRegionalRateBasedRuleConfig_noPredicates(name string) string { return fmt.Sprintf(` resource "aws_wafregional_rate_based_rule" "wafrule" { - name = "%s" - metric_name = "%s" + name = %[1]q + metric_name = %[1]q rate_key = "IP" rate_limit = 2000 } -`, name, name) +`, name) } func testAccAWSWafRegionalRateBasedRuleWithRateLimitConfig(name string, limit string) string { diff --git a/website/docs/r/wafregional_rate_based_rule.html.markdown b/website/docs/r/wafregional_rate_based_rule.html.markdown index bca2206b2a3..71f05a7ce0b 100644 --- a/website/docs/r/wafregional_rate_based_rule.html.markdown +++ b/website/docs/r/wafregional_rate_based_rule.html.markdown @@ -47,6 +47,7 @@ The following arguments are supported: * `rate_key` - (Required) Valid value is IP. * `rate_limit` - (Required) The maximum number of requests, which have an identical value in the field specified by the RateKey, allowed in a five-minute period. Minimum value is 100. * `predicate` - (Optional) The objects to include in a rule (documented below). +* `tags` - (Optional) Key-value mapping of resource tags ## Nested Blocks @@ -67,7 +68,8 @@ See the [WAF Documentation](https://docs.aws.amazon.com/waf/latest/APIReference/ In addition to all arguments above, the following attributes are exported: -* `id` - The ID of the WAF Regional rate based rule. +* `id` - The ID of the WAF Regional Rate Based Rule. +* `arn` - The ARN of the WAF Regional Rate Based Rule. ## Import From 12b40de4c1853c6a4ffb7885b85dbf14c76762ef Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Fri, 15 Nov 2019 15:41:37 -0500 Subject: [PATCH 38/38] Update CHANGELOG for #10897 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24a245617ae..e3a7d18a909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ENHANCEMENTS: * resource/aws_waf_regex_pattern_set: Support resource import and add `arn` attribute [GH-10482] * resource/aws_waf_size_constraint_set: Support resource import and add `arn` attribute [GH-10484] * resource/aws_waf_xss_match_set: Support resource import and add `arn` attribute [GH-10485] +* resource/aws_wafregional_rate_based_rule: Add `tags` argument and `arn` attribute [GH-10897] * resource/aws_wafregional_rule_group: Add `tags` argument and `arn` attribute [GH-10896] * resource/aws_wafregional_rule: Add `tags` argument and `arn` attribute [GH-10895] * resource/aws_wafregional_web_acl: Add `tags` argument [GH-10889]