diff --git a/.changelog/35941.txt b/.changelog/35941.txt new file mode 100644 index 000000000000..4be8ac7d25c2 --- /dev/null +++ b/.changelog/35941.txt @@ -0,0 +1,15 @@ +```release-note:enhancement +resource/aws_fis_experiment_template: Add plan-time validation of `log_configuration.cloudwatch_logs_configuration.log_group_arn` +``` + +```release-note:enhancement +resource/aws_sfn_state_machine: Add plan-time validation of `logging_configuration.log_destination` +``` + +```release-note:enhancement +resource/aws_prometheus_query_logging_configuration: Add plan-time validation of `destination.cloudwatch_logs.log_group_arn` +``` + +```release-note:enhancement +resource/aws_prometheus_workspace: Add plan-time validation of `logging_configuration.log_group_arn` +``` \ No newline at end of file diff --git a/.changelog/39671.txt b/.changelog/39671.txt new file mode 100644 index 000000000000..0e4cf3035d91 --- /dev/null +++ b/.changelog/39671.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +data-source/aws_route53_zone: Support filtering by `tags` only or by `vpc_id` only +``` diff --git a/.changelog/41209.txt b/.changelog/41209.txt new file mode 100644 index 000000000000..d48881f8e051 --- /dev/null +++ b/.changelog/41209.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_fis_experiment_template: Add support for `Functions` to `action.*.target` +``` diff --git a/.changelog/41240.txt b/.changelog/41240.txt new file mode 100644 index 000000000000..479488039e0a --- /dev/null +++ b/.changelog/41240.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_lambda_invocation: Add import support +``` diff --git a/.changelog/41275.txt b/.changelog/41275.txt new file mode 100644 index 000000000000..ed3e52c544fd --- /dev/null +++ b/.changelog/41275.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_db_instance: Fix blue/green deployments failing with "not in available state" by improving stability and handling `storage-config-upgrade` and `storage-initialization` statuses +``` diff --git a/.changelog/42843.txt b/.changelog/42843.txt new file mode 100644 index 000000000000..7355a8c59519 --- /dev/null +++ b/.changelog/42843.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_sagemaker_endpoint: Fix bug where `endpoint_config_name` was not correctly updated, causing the endpoint to retain the old configuration +``` \ No newline at end of file diff --git a/.changelog/43908.txt b/.changelog/43908.txt new file mode 100644 index 000000000000..d830c896fb65 --- /dev/null +++ b/.changelog/43908.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_dynamodb_table: Add `global_table_witness` argument +``` diff --git a/.changelog/44407.txt b/.changelog/44407.txt new file mode 100644 index 000000000000..546c78333066 --- /dev/null +++ b/.changelog/44407.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_sagemaker_model: Add `container.additional_model_data_source` and `primary_container.additional_model_data_source` arguments +``` diff --git a/.changelog/44626.txt b/.changelog/44626.txt new file mode 100644 index 000000000000..c7a63788dfe4 --- /dev/null +++ b/.changelog/44626.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_opensearch_domain: Add `identity_center_options` configuration block +``` + +```release-note:enhancement +data-source/aws_opensearch_domain: Add `identity_center_options` attribute +``` diff --git a/.changelog/44782.txt b/.changelog/44782.txt new file mode 100644 index 000000000000..9095a9c704ff --- /dev/null +++ b/.changelog/44782.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +aws_networkflowmonitor_monitor +``` + +```release-note:new-resource +aws_networkflowmonitor_scope +``` \ No newline at end of file diff --git a/.changelog/44800.txt b/.changelog/44800.txt new file mode 100644 index 000000000000..f1454cb40748 --- /dev/null +++ b/.changelog/44800.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_ec2_allowed_images_settings +``` diff --git a/.changelog/44806.txt b/.changelog/44806.txt new file mode 100644 index 000000000000..8cee58187943 --- /dev/null +++ b/.changelog/44806.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_observabilityadmin_centralization_rule_for_organization +``` diff --git a/.changelog/44828.txt b/.changelog/44828.txt new file mode 100644 index 000000000000..639486abcd02 --- /dev/null +++ b/.changelog/44828.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +resource/aws_bedrockagentcore_browser: Rename `network_configuration.network_mode_config` to `network_configuration.vpc_config` +``` \ No newline at end of file diff --git a/.changelog/44842.txt b/.changelog/44842.txt new file mode 100644 index 000000000000..b323e0303d50 --- /dev/null +++ b/.changelog/44842.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_ecs_service: Add support for `LINEAR` and `CANARY` deployment strategies with `deployment_configuration.linear_configuration` and `deployment_configuration.canary_configuration` blocks +``` + +```release-note:enhancement +data-source/aws_ecs_service: Add `capacity_provider_strategy`, `created_at`, `created_by`, `deployment_configuration`, `deployment_controller`, `deployments`, `enable_ecs_managed_tags`, `enable_execute_command`, `events`, `health_check_grace_period_seconds`, `iam_role`, `network_configuration`, `ordered_placement_strategy`, `pending_count`, `placement_constraints`, `platform_family`, `platform_version`, `propagate_tags`, `running_count`, `service_connect_configuration`, `service_registries`, `status`, and `task_sets` attributes +``` diff --git a/.changelog/44899.txt b/.changelog/44899.txt new file mode 100644 index 000000000000..c4b2eec0754c --- /dev/null +++ b/.changelog/44899.txt @@ -0,0 +1,11 @@ +```release-note:bug +resource/aws_timestreaminfluxdb_db_cluster: Make `allocated_storage`, `bucket`, `organization`, `username`, and `password` optional to support InfluxDB V3 clusters +``` + +```release-note:enhancement +resource/aws_timestreaminfluxdb_db_cluster: Add `engine_type` attribute +``` + +```release-note:enhancement +resource/aws_timestreaminfluxdb_db_cluster: Add validation to ensure InfluxDB V2 clusters have required fields and InfluxDB V3 clusters (when using V3 parameter groups) do not have forbidden V2 fields. This functionality requires the `timestream-influxdb:GetDbParameterGroup` IAM permission +``` \ No newline at end of file diff --git a/.changelog/44934.txt b/.changelog/44934.txt new file mode 100644 index 000000000000..b9c8d4de9f1a --- /dev/null +++ b/.changelog/44934.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_connect_routing_profile: Add `media_concurrencies.cross_channel_behavior` argument +``` + +```release-note:enhancement +data-source/aws_connect_routing_profile: Add `media_concurrencies.cross_channel_behavior` attribute +``` diff --git a/.changelog/44944.txt b/.changelog/44944.txt index 181feede9934..036174e3caca 100644 --- a/.changelog/44944.txt +++ b/.changelog/44944.txt @@ -1,3 +1,3 @@ -```release-note:bug +```release-note:enhancement provider: Support `us-isob-west-1` as a valid AWS Region ``` \ No newline at end of file diff --git a/.changelog/44949.txt b/.changelog/44949.txt new file mode 100644 index 000000000000..3c36052b5cef --- /dev/null +++ b/.changelog/44949.txt @@ -0,0 +1,3 @@ +```release-note:new-ephemeral +aws_ecr_authorization_token +``` \ No newline at end of file diff --git a/.changelog/44952.txt b/.changelog/44952.txt new file mode 100644 index 000000000000..cf8538e2f03d --- /dev/null +++ b/.changelog/44952.txt @@ -0,0 +1,43 @@ +```release-note:bug +resource/aws_redshift_cluster: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_cluster_snapshot: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_event_subscription: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_hsm_client_certificate: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_hsm_configuration: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_integration: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_parameter_group: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_snapshot_copy_grant: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_snapshot_schedule: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_subnet_group: Prevents errors with empty tag values. +``` + +```release-note:bug +resource/aws_redshift_usage_limit: Prevents errors with empty tag values. +``` diff --git a/.changelog/44972.txt b/.changelog/44972.txt new file mode 100644 index 000000000000..291be131adfa --- /dev/null +++ b/.changelog/44972.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_cloudfront_continuous_deployment_policy: Fix `Source type "...cloudfront.stagingDistributionDNSNamesModel" does not implement attr.Value` error. This fixes a regression introduced in [v6.17.0](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md#6170-october-16-2025) +``` \ No newline at end of file diff --git a/.changelog/44977.txt b/.changelog/44977.txt new file mode 100644 index 000000000000..ea9666c22842 --- /dev/null +++ b/.changelog/44977.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_sagemaker_endpoint_configuration: Add `execution_role_arn` argument and make `model_name` optional in `production_variants` and `shadow_production_variants` blocks to support Inference Components +``` diff --git a/.changelog/44982.txt b/.changelog/44982.txt new file mode 100644 index 000000000000..693e5cedce52 --- /dev/null +++ b/.changelog/44982.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_opensearch_authorize_vpc_endpoint_access: Fix reading the resource when more than one principal is authorized. The [import ID](https://developer.hashicorp.com/terraform/language/block/import#id) has changed from `domain_name` to `domain_name` and `account` separated by a comma +``` \ No newline at end of file diff --git a/.changelog/44987.txt b/.changelog/44987.txt new file mode 100644 index 000000000000..fb44d802b409 --- /dev/null +++ b/.changelog/44987.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_wafv2_web_acl_logging_configuration: Fix the validation for `redacted_fields.single_header.name` +``` diff --git a/.changelog/44991.txt b/.changelog/44991.txt new file mode 100644 index 000000000000..845aa811c77c --- /dev/null +++ b/.changelog/44991.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_bedrockagentcore_gateway_target: Add `target_configuration.mcp.mcp_server` block +``` + +```release-note:enhancement +resource/aws_bedrockagentcore_gateway_target: Make `credential_provider_configuration` block optional +``` diff --git a/.changelog/44995.txt b/.changelog/44995.txt new file mode 100644 index 000000000000..53b1ad879135 --- /dev/null +++ b/.changelog/44995.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_cloudwatch_log_delivery_destination: Make `delivery_destination_type` and `delivery_destination_configuration` optional to support AWS X-Ray as a destination +``` diff --git a/.changelog/44996.txt b/.changelog/44996.txt new file mode 100644 index 000000000000..e210158c5299 --- /dev/null +++ b/.changelog/44996.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_s3tables_table_bucket: Add tagging support +``` + +```release-note:enhancement +resource/aws_s3tables_table: Add tagging support +``` \ No newline at end of file diff --git a/.changelog/45001.txt b/.changelog/45001.txt new file mode 100644 index 000000000000..0134cbe9bf90 --- /dev/null +++ b/.changelog/45001.txt @@ -0,0 +1,3 @@ +```release-note:new-action +aws_dynamodb_create_backup +``` diff --git a/.changelog/45003.txt b/.changelog/45003.txt new file mode 100644 index 000000000000..59e6e36a6443 --- /dev/null +++ b/.changelog/45003.txt @@ -0,0 +1,6 @@ +```release-note:bug +resource/aws_odb_cloud_vm_cluster: support for hyphen in odb cloud vm cluster hostname prefix. +``` +```release-note:enhancement +resource/aws_odb_cloud_vm_cluster: vm cluster creation using odb network ARN and exadata infrastructure ARN for resource sharing model. +``` \ No newline at end of file diff --git a/.changelog/45018.txt b/.changelog/45018.txt new file mode 100644 index 000000000000..92f20c3f35ff --- /dev/null +++ b/.changelog/45018.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_sns_topic: Fix `AuthorizationError ... is not authorized to perform: iam:PassRole on resource ...` IAM eventual consistency errors on Create and Update +``` \ No newline at end of file diff --git a/.changelog/45020.txt b/.changelog/45020.txt new file mode 100644 index 000000000000..d0e1a4ede2f1 --- /dev/null +++ b/.changelog/45020.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_backup_logically_air_gapped_vault: Add `encryption_key_arn` argument +``` diff --git a/.changelog/45022.txt b/.changelog/45022.txt new file mode 100644 index 000000000000..1f902e8b9b03 --- /dev/null +++ b/.changelog/45022.txt @@ -0,0 +1,3 @@ +```release-note:bug +provider: Fix situation where refreshes of removed infrastructure appear as errors rather than warnings +``` \ No newline at end of file diff --git a/.changelog/45023.txt b/.changelog/45023.txt new file mode 100644 index 000000000000..6983a1bba8fc --- /dev/null +++ b/.changelog/45023.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_ec2_image_block_public_access: Add `region` argument +``` \ No newline at end of file diff --git a/.changelog/45024.txt b/.changelog/45024.txt new file mode 100644 index 000000000000..d426c7d1a725 --- /dev/null +++ b/.changelog/45024.txt @@ -0,0 +1,23 @@ +```release-note:enhancement +resource/aws_lambda_function: Add support for `java25` `runtime` value +``` + +```release-note:enhancement +resource/aws_lambda_function: Add support for `nodejs24.x` `runtime` value +``` + +```release-note:enhancement +resource/aws_lambda_function: Add support for `python3.14` `runtime` value +``` + +```release-note:enhancement +resource/aws_lambda_layer_version: Add support for `java25` `compatible_runtimes` value +``` + +```release-note:enhancement +resource/aws_lambda_layer_version: Add support for `nodejs24.x` `compatible_runtimes` value +``` + +```release-note:enhancement +resource/aws_lambda_layer_version: Add support for `python3.14` `compatible_runtimes` value +``` diff --git a/.changelog/45029.txt b/.changelog/45029.txt new file mode 100644 index 000000000000..1856c1730c0a --- /dev/null +++ b/.changelog/45029.txt @@ -0,0 +1,11 @@ +```release-note:bug +resource/aws_emrcontainers_job_template: Fix `setting job_template_data: job_template_data.0.configuration_overrides.0.application_configuration.0: '' expected a map, got 'slice'` error +``` + +```release-note:bug +resource/aws_emrcontainers_job_template: Fix `ValidationException: Value null at 'jobTemplateData.configurationOverrides.monitoringConfiguration.cloudWatchMonitoringConfiguration.logGroupName' failed to satisfy constraint: Member must not be null` error +``` + +```release-note:bug +resource/aws_emrcontainers_job_template: Mark `job_template_data.job_driver.configuration_overrides.monitoring_configuration.persistent_app_ui` argument as computed +``` diff --git a/.changelog/45030.txt b/.changelog/45030.txt new file mode 100644 index 000000000000..b9ddcb847983 --- /dev/null +++ b/.changelog/45030.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_invoicing_invoice_unit: Fix `Provider returned invalid result object after apply` error occurred when updating the resource +``` diff --git a/.changelog/45050.txt b/.changelog/45050.txt new file mode 100644 index 000000000000..174ac47859b0 --- /dev/null +++ b/.changelog/45050.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_apprunner_service: Prevents error when upgrading from provider pre-v6.0 without refreshing +``` diff --git a/.changelog/45051.txt b/.changelog/45051.txt new file mode 100644 index 000000000000..174ac47859b0 --- /dev/null +++ b/.changelog/45051.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_apprunner_service: Prevents error when upgrading from provider pre-v6.0 without refreshing +``` diff --git a/.changelog/45064.txt b/.changelog/45064.txt new file mode 100644 index 000000000000..07474158130b --- /dev/null +++ b/.changelog/45064.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_ec2_serial_console_access: Add `region` argument +``` \ No newline at end of file diff --git a/.changelog/45070.txt b/.changelog/45070.txt new file mode 100644 index 000000000000..aff527708bd4 --- /dev/null +++ b/.changelog/45070.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_vpn_connection: Add `tunnel_bandwidth` argument to support higher bandwidth tunnels +``` \ No newline at end of file diff --git a/.changelog/45075.txt b/.changelog/45075.txt new file mode 100644 index 000000000000..fcdb27125b94 --- /dev/null +++ b/.changelog/45075.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Add `storage_configuration.rds_configuration.field_mapping.custom_metadata_field` argument +``` \ No newline at end of file diff --git a/.changelog/45077.txt b/.changelog/45077.txt new file mode 100644 index 000000000000..b792181981aa --- /dev/null +++ b/.changelog/45077.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_elastic_beanstalk_configuration_template: Fix updates not applying by including `ResourceName` for option settings and preventing duplicate add/remove operations +``` \ No newline at end of file diff --git a/.changelog/45083.txt b/.changelog/45083.txt new file mode 100644 index 000000000000..4fcd36a01b8f --- /dev/null +++ b/.changelog/45083.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_quicksight_account_settings: Add `region` argument +``` \ No newline at end of file diff --git a/.changelog/45085.txt b/.changelog/45085.txt new file mode 100644 index 000000000000..8144b1a25a90 --- /dev/null +++ b/.changelog/45085.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_vpclattice_resource_configuration: Add `custom_domain_name` and `domain_verification_id` arguments and `domain_verification_arn` and `domain_verification_status` attributes to support custom domain names for resource configurations +``` + +```release-note:new-resource +aws_vpclattice_domain_verification +``` diff --git a/.changelog/45086.txt b/.changelog/45086.txt new file mode 100644 index 000000000000..ea1b5736a7c1 --- /dev/null +++ b/.changelog/45086.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_s3_directory_bucket: Fix plan-time `AWS resource not found during refresh` warnings causing resource replacement when `ReadOnly` `s3express:SessionMode` is enforced +``` \ No newline at end of file diff --git a/.changelog/45089.txt b/.changelog/45089.txt new file mode 100644 index 000000000000..4099985d6592 --- /dev/null +++ b/.changelog/45089.txt @@ -0,0 +1,15 @@ +```release-note:enhancement +resource/aws_lb_listener: Support `jwt-validation` as a valid `default_action.type` and add `default_action.jwt_validation` configuration block +``` + +```release-note:enhancement +resource/aws_lb_listener_rule: Support `jwt-validation` as a valid `action.type` and add `action.jwt_validation` configuration block +``` + +```release-note:enhancement +data-source/aws_lb_listener: Add `default_action.jwt_validation` attribute +``` + +```release-note:enhancement +data-source/aws_lb_listener_rule: Add `action.jwt_validation` attribute +``` diff --git a/.changelog/45091.txt b/.changelog/45091.txt new file mode 100644 index 000000000000..517c27c1a0db --- /dev/null +++ b/.changelog/45091.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_bedrockagentcore_agent_runtime: Add `agent_runtime_artifact.code_configuration` block +``` + +```release-note:enhancement +resource/aws_bedrockagentcore_agent_runtime: Make `agent_runtime_artifact.container_configuration` block optional +``` diff --git a/.changelog/45092.txt b/.changelog/45092.txt new file mode 100644 index 000000000000..e4d1c271a7de --- /dev/null +++ b/.changelog/45092.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_ssoadmin_account_assignment: Correct `target_type` argument to required +``` diff --git a/.changelog/45105.txt b/.changelog/45105.txt new file mode 100644 index 000000000000..f5094d30aeab --- /dev/null +++ b/.changelog/45105.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_s3_bucket_server_side_encryption_configuration: Add `rule.blocked_encryption_types` argument +``` + +```release-note:note +resource/aws_s3_bucket_server_side_encryption_configuration: Starting in March 2026, Amazon S3 will introduce a new default bucket security setting by automatically disabling server-side encryption with customer-provided keys (SSE-C) for all new buckets. Use the `blocked_encryption_types` argument to manage this behavior for specific buckets. +``` diff --git a/.changelog/45132.txt b/.changelog/45132.txt new file mode 100644 index 000000000000..b749229c2b10 --- /dev/null +++ b/.changelog/45132.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_emr_managed_scaling_policy: Add `scaling_strategy` and `utilization_performance_index` arguments +``` diff --git a/.changelog/45135.txt b/.changelog/45135.txt new file mode 100644 index 000000000000..046fa1bb7f6a --- /dev/null +++ b/.changelog/45135.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_organizations_organization: Add `SECURITYHUB_POLICY` as a valid value for `enabled_policy_types` argument +``` diff --git a/.ci/.golangci3.yml b/.ci/.golangci3.yml index 442643a012c2..c9089ab868de 100644 --- a/.ci/.golangci3.yml +++ b/.ci/.golangci3.yml @@ -5,6 +5,7 @@ linters: - goconst - gocritic - govet + - importas - ineffassign - makezero - misspell @@ -25,6 +26,11 @@ linters: - opinionated - performance - style + importas: + no-unaliased: true + alias: + - pkg: github.com/hashicorp/terraform-provider-aws/internal/types + alias: inttypes mnd: checks: - argument diff --git a/.ci/.golangci4.yml b/.ci/.golangci4.yml index b0d9c1641efa..093a7b87ddf1 100644 --- a/.ci/.golangci4.yml +++ b/.ci/.golangci4.yml @@ -79,6 +79,9 @@ linters: - linters: - paralleltest text: Function TestAcc + - linters: + - perfsprint + path: _test\.go - linters: - staticcheck text: 'SA1019: \w+.GetOkExists is deprecated: usage is discouraged due to undefined behaviors and may be removed in a future version of the SDK' @@ -161,6 +164,10 @@ linters: - staticcheck path: internal/service/qldb/ text: 'SA1019: \w+.(\w+) is deprecated:' + - linters: + - staticcheck + path: internal/service/quicksight/ + text: 'SA1019: \w+.(\w+) is deprecated:' - linters: - staticcheck path: internal/service/s3/ diff --git a/.ci/providerlint/go.mod b/.ci/providerlint/go.mod index a8e4966297a1..134d539eb632 100644 --- a/.ci/providerlint/go.mod +++ b/.ci/providerlint/go.mod @@ -1,12 +1,12 @@ module github.com/hashicorp/terraform-provider-aws/ci/providerlint -go 1.24.8 +go 1.24.10 require ( github.com/bflad/tfproviderlint v0.31.0 github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.68 github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 - golang.org/x/tools v0.38.0 + golang.org/x/tools v0.39.0 ) require ( @@ -53,12 +53,12 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.17.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect - golang.org/x/crypto v0.43.0 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.46.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/text v0.30.0 // indirect + golang.org/x/crypto v0.44.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/grpc v1.75.1 // indirect diff --git a/.ci/providerlint/go.sum b/.ci/providerlint/go.sum index fffe296cf0e7..130c5a681158 100644 --- a/.ci/providerlint/go.sum +++ b/.ci/providerlint/go.sum @@ -178,23 +178,23 @@ go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42s golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -207,22 +207,22 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200214201135-548b770e2dfa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/.ci/providerlint/passes/AWSAT001/testdata/go.mod b/.ci/providerlint/passes/AWSAT001/testdata/go.mod index 88975b766cc4..87d96bece862 100644 --- a/.ci/providerlint/passes/AWSAT001/testdata/go.mod +++ b/.ci/providerlint/passes/AWSAT001/testdata/go.mod @@ -1,6 +1,6 @@ module testdata -go 1.24.8 +go 1.24.10 require ( github.com/YakDriver/regexache v0.24.0 diff --git a/.ci/providerlint/passes/AWSAT002/testdata/go.mod b/.ci/providerlint/passes/AWSAT002/testdata/go.mod index 6e52bd367daf..00c155cbf6a1 100644 --- a/.ci/providerlint/passes/AWSAT002/testdata/go.mod +++ b/.ci/providerlint/passes/AWSAT002/testdata/go.mod @@ -1,3 +1,3 @@ module testdata -go 1.24.8 +go 1.24.10 diff --git a/.ci/providerlint/passes/AWSAT003/testdata/go.mod b/.ci/providerlint/passes/AWSAT003/testdata/go.mod index 6e52bd367daf..00c155cbf6a1 100644 --- a/.ci/providerlint/passes/AWSAT003/testdata/go.mod +++ b/.ci/providerlint/passes/AWSAT003/testdata/go.mod @@ -1,3 +1,3 @@ module testdata -go 1.24.8 +go 1.24.10 diff --git a/.ci/providerlint/passes/AWSAT004/testdata/go.mod b/.ci/providerlint/passes/AWSAT004/testdata/go.mod index 9c2d75617a1f..703cc1fde19d 100644 --- a/.ci/providerlint/passes/AWSAT004/testdata/go.mod +++ b/.ci/providerlint/passes/AWSAT004/testdata/go.mod @@ -1,6 +1,6 @@ module testdata -go 1.24.8 +go 1.24.10 require github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 diff --git a/.ci/providerlint/passes/AWSAT005/testdata/go.mod b/.ci/providerlint/passes/AWSAT005/testdata/go.mod index 6e52bd367daf..00c155cbf6a1 100644 --- a/.ci/providerlint/passes/AWSAT005/testdata/go.mod +++ b/.ci/providerlint/passes/AWSAT005/testdata/go.mod @@ -1,3 +1,3 @@ module testdata -go 1.24.8 +go 1.24.10 diff --git a/.ci/providerlint/passes/AWSAT006/testdata/go.mod b/.ci/providerlint/passes/AWSAT006/testdata/go.mod index 6e52bd367daf..00c155cbf6a1 100644 --- a/.ci/providerlint/passes/AWSAT006/testdata/go.mod +++ b/.ci/providerlint/passes/AWSAT006/testdata/go.mod @@ -1,3 +1,3 @@ module testdata -go 1.24.8 +go 1.24.10 diff --git a/.ci/providerlint/passes/AWSR001/testdata/go.mod b/.ci/providerlint/passes/AWSR001/testdata/go.mod index 6e52bd367daf..00c155cbf6a1 100644 --- a/.ci/providerlint/passes/AWSR001/testdata/go.mod +++ b/.ci/providerlint/passes/AWSR001/testdata/go.mod @@ -1,3 +1,3 @@ module testdata -go 1.24.8 +go 1.24.10 diff --git a/.ci/providerlint/passes/AWSV001/testdata/go.mod b/.ci/providerlint/passes/AWSV001/testdata/go.mod index 2a9f362fee27..ef2ad2a90065 100644 --- a/.ci/providerlint/passes/AWSV001/testdata/go.mod +++ b/.ci/providerlint/passes/AWSV001/testdata/go.mod @@ -1,6 +1,6 @@ module testdata -go 1.24.8 +go 1.24.10 require github.com/hashicorp/terraform-plugin-sdk/v2 v2.36.1 diff --git a/.ci/tools/go.mod b/.ci/tools/go.mod index e1d3e171ef34..8298a5b0c094 100644 --- a/.ci/tools/go.mod +++ b/.ci/tools/go.mod @@ -1,18 +1,18 @@ module github.com/hashicorp/terraform-provider-aws/tools -go 1.24.8 +go 1.24.10 require ( github.com/YakDriver/tfproviderdocs v0.23.3 github.com/client9/misspell v0.3.4 - github.com/golangci/golangci-lint/v2 v2.5.0 + github.com/golangci/golangci-lint/v2 v2.6.2 github.com/hashicorp/copywrite v0.22.0 github.com/hashicorp/go-changelog v0.0.0-20250127101332-effe3832fb0b github.com/katbyte/terrafmt v0.5.5 github.com/pavius/impi v0.0.3 github.com/rhysd/actionlint v1.7.8 github.com/terraform-linters/tflint v0.58.1 - golang.org/x/tools v0.38.0 + golang.org/x/tools v0.39.0 mvdan.cc/gofumpt v0.9.2 ) @@ -21,9 +21,9 @@ require ( 4d63.com/gochecknoglobals v0.2.2 // indirect cel.dev/expr v0.24.0 // indirect cloud.google.com/go v0.121.2 // indirect - cloud.google.com/go/auth v0.16.3 // indirect + cloud.google.com/go/auth v0.16.5 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.7.0 // indirect + cloud.google.com/go/compute/metadata v0.8.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect cloud.google.com/go/storage v1.53.0 // indirect @@ -32,7 +32,7 @@ require ( dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect dev.gaijin.team/go/golib v0.6.0 // indirect github.com/4meepo/tagalign v1.4.3 // indirect - github.com/Abirdcfly/dupword v0.1.6 // indirect + github.com/Abirdcfly/dupword v0.1.7 // indirect github.com/AdminBenni/iota-mixing v1.0.0 // indirect github.com/AlecAivazis/survey/v2 v2.3.7 // indirect github.com/AlwxSin/noinlineerr v1.0.5 // indirect @@ -41,7 +41,7 @@ require ( github.com/Antonboom/testifylint v1.6.4 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect @@ -63,8 +63,8 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/ashanbrown/forbidigo/v2 v2.1.0 // indirect - github.com/ashanbrown/makezero/v2 v2.0.1 // indirect + github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect + github.com/ashanbrown/makezero/v2 v2.1.0 // indirect github.com/aws/aws-sdk-go v1.55.6 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -76,17 +76,17 @@ require ( github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect - github.com/bombsimon/wsl/v5 v5.2.0 // indirect + github.com/bombsimon/wsl/v5 v5.3.0 // indirect github.com/bradleyfalzon/ghinstallation/v2 v2.5.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect github.com/butuzov/ireturn v0.4.0 // indirect github.com/butuzov/mirror v1.3.0 // indirect - github.com/catenacyber/perfsprint v0.9.1 // indirect + github.com/catenacyber/perfsprint v0.10.0 // indirect github.com/ccojocar/zxcvbn-go v1.0.4 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/charithe/durationcheck v0.0.10 // indirect + github.com/charithe/durationcheck v0.0.11 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/lipgloss v1.1.1-0.20250319133953-166f707985bc // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect @@ -117,13 +117,13 @@ require ( github.com/firefart/nonamedreturns v1.0.6 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/ghostiam/protogetter v0.3.16 // indirect + github.com/ghostiam/protogetter v0.3.17 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect - github.com/go-critic/go-critic v0.13.0 // indirect + github.com/go-critic/go-critic v0.14.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.0 // indirect github.com/go-git/go-git/v5 v5.13.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.5 // indirect + github.com/go-jose/go-jose/v4 v4.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect @@ -146,8 +146,8 @@ require ( github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/godoc-lint/godoc-lint v0.10.0 // indirect - github.com/gofrs/flock v0.12.1 // indirect + github.com/godoc-lint/godoc-lint v0.10.1 // indirect + github.com/gofrs/flock v0.13.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -157,7 +157,6 @@ require ( github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 // indirect github.com/golangci/misspell v0.7.0 // indirect - github.com/golangci/nilerr v0.0.0-20250918000102-015671e622fe // indirect github.com/golangci/plugin-module-register v0.1.2 // indirect github.com/golangci/revgrep v0.8.0 // indirect github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect @@ -173,11 +172,12 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect - github.com/gookit/color v1.5.4 // indirect + github.com/gookit/color v1.6.0 // indirect github.com/gordonklaus/ineffassign v0.2.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.5.0 // indirect github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect + github.com/gostaticanalysis/nilerr v0.1.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.7.9 // indirect @@ -216,7 +216,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/jstemmer/go-junit-report v1.0.0 // indirect github.com/julz/importas v0.2.0 // indirect - github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect + github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect github.com/katbyte/andreyvit-diff v0.0.2 // indirect github.com/katbyte/sergi-go-diff v1.2.2 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect @@ -227,10 +227,10 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/knadh/koanf v1.5.0 // indirect github.com/kulti/thelper v0.7.1 // indirect - github.com/kunwardeep/paralleltest v1.0.14 // indirect + github.com/kunwardeep/paralleltest v1.0.15 // indirect github.com/lasiar/canonicalheader v1.1.2 // indirect - github.com/ldez/exptostd v0.4.4 // indirect - github.com/ldez/gomoddirectives v0.7.0 // indirect + github.com/ldez/exptostd v0.4.5 // indirect + github.com/ldez/gomoddirectives v0.7.1 // indirect github.com/ldez/grignotin v0.10.1 // indirect github.com/ldez/tagliatelle v0.7.2 // indirect github.com/ldez/usetesting v0.5.0 // indirect @@ -241,8 +241,8 @@ require ( github.com/mailru/easyjson v0.9.0 // indirect github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect github.com/manuelarte/funcorder v0.5.0 // indirect - github.com/maratori/testableexamples v1.0.0 // indirect - github.com/maratori/testpackage v1.1.1 // indirect + github.com/maratori/testableexamples v1.0.1 // indirect + github.com/maratori/testpackage v1.1.2 // indirect github.com/matoous/godox v1.1.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -263,7 +263,7 @@ require ( github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.21.0 // indirect + github.com/nunnatsa/ginkgolinter v0.21.2 // indirect github.com/oklog/run v1.0.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -280,8 +280,8 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/quasilyte/go-ruleguard v0.4.4 // indirect - github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect + github.com/quasilyte/go-ruleguard v0.4.5 // indirect + github.com/quasilyte/go-ruleguard/dsl v0.3.23 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect @@ -299,7 +299,7 @@ require ( github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect github.com/sassoftware/relic v7.2.1+incompatible // indirect github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect - github.com/securego/gosec/v2 v2.22.8 // indirect + github.com/securego/gosec/v2 v2.22.10 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect @@ -360,45 +360,45 @@ require ( gitlab.com/bosi/decorder v0.4.2 // indirect go-simpler.org/musttag v0.14.0 // indirect go-simpler.org/sloglint v0.11.1 // indirect - go.augendre.info/arangolint v0.2.0 // indirect - go.augendre.info/fatcontext v0.8.1 // indirect + go.augendre.info/arangolint v0.3.1 // indirect + go.augendre.info/fatcontext v0.9.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel v1.36.0 // indirect - go.opentelemetry.io/otel/metric v1.36.0 // indirect - go.opentelemetry.io/otel/sdk v1.36.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.36.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.37.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.2 // indirect - golang.org/x/crypto v0.43.0 // indirect + golang.org/x/crypto v0.44.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect - golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.46.0 // indirect + golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.36.0 // indirect - golang.org/x/text v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/api v0.246.0 // indirect google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 // indirect - google.golang.org/grpc v1.74.2 // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/grpc v1.75.0 // indirect + google.golang.org/protobuf v1.36.8 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.6.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect - mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect + mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect ) replace github.com/hashicorp/go-changelog => github.com/breathingdust/go-changelog v0.0.0-20210127001721-f985d5709c15 diff --git a/.ci/tools/go.sum b/.ci/tools/go.sum index d6f4bd03dade..63bc05181fc6 100644 --- a/.ci/tools/go.sum +++ b/.ci/tools/go.sum @@ -105,8 +105,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= -cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= +cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI= +cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -188,8 +188,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= +cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA= +cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -635,8 +635,8 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= -github.com/Abirdcfly/dupword v0.1.6 h1:qeL6u0442RPRe3mcaLcbaCi2/Y/hOcdtw6DE9odjz9c= -github.com/Abirdcfly/dupword v0.1.6/go.mod h1:s+BFMuL/I4YSiFv29snqyjwzDp4b65W2Kvy+PKzZ6cw= +github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= +github.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= github.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= @@ -669,8 +669,8 @@ github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk= @@ -761,10 +761,10 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/ashanbrown/forbidigo/v2 v2.1.0 h1:NAxZrWqNUQiDz19FKScQ/xvwzmij6BiOw3S0+QUQ+Hs= -github.com/ashanbrown/forbidigo/v2 v2.1.0/go.mod h1:0zZfdNAuZIL7rSComLGthgc/9/n2FqspBOH90xlCHdA= -github.com/ashanbrown/makezero/v2 v2.0.1 h1:r8GtKetWOgoJ4sLyUx97UTwyt2dO7WkGFHizn/Lo8TY= -github.com/ashanbrown/makezero/v2 v2.0.1/go.mod h1:kKU4IMxmYW1M4fiEHMb2vc5SFoPzXvgbMR9gIp5pjSw= +github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo= +github.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c= +github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE= +github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk= github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= @@ -829,8 +829,8 @@ github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/ github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.2.0 h1:PyCCwd3Q7abGs3e34IW4jLYlBS+FbsU6iK+Tb3NnDp4= -github.com/bombsimon/wsl/v5 v5.2.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= +github.com/bombsimon/wsl/v5 v5.3.0 h1:nZWREJFL6U3vgW/B1lfDOigl+tEF6qgs6dGGbFeR0UM= +github.com/bombsimon/wsl/v5 v5.3.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradleyfalzon/ghinstallation/v2 v2.5.0 h1:yaYcGQ7yEIGbsJfW/9z7v1sLiZg/5rSNNXwmMct5XaE= @@ -849,8 +849,8 @@ github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/catenacyber/perfsprint v0.9.1 h1:5LlTp4RwTooQjJCvGEFV6XksZvWE7wCOUvjD2z0vls0= -github.com/catenacyber/perfsprint v0.9.1/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM= +github.com/catenacyber/perfsprint v0.10.0 h1:AZj1mYyxbxLRqmnYOeguZXEQwWOgQGm2wzLI5d7Hl/0= +github.com/catenacyber/perfsprint v0.10.0/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc= github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -865,8 +865,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= -github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk= +github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= github.com/charmbracelet/lipgloss v1.1.1-0.20250319133953-166f707985bc h1:nFRtCfZu/zkltd2lsLUPlVNv3ej/Atod9hcdbRZtlys= @@ -998,15 +998,15 @@ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8 github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghostiam/protogetter v0.3.16 h1:UkrisuJBYLnZW6FcYUNBDJOqY3X22RtoYMlCsiNlFFA= -github.com/ghostiam/protogetter v0.3.16/go.mod h1:4SRRIv6PcjkIMpUkRUsP4TsUTqO/N3Fmvwivuc/sCHA= +github.com/ghostiam/protogetter v0.3.17 h1:sjGPErP9o7i2Ym+z3LsQzBdLCNaqbYy2iJQPxGXg04Q= +github.com/ghostiam/protogetter v0.3.17/go.mod h1:AivIX1eKA/TcUmzZdzbl+Tb8tjIe8FcyG6JFyemQAH4= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-critic/go-critic v0.13.0 h1:kJzM7wzltQasSUXtYyTl6UaPVySO6GkaR1thFnJ6afY= -github.com/go-critic/go-critic v0.13.0/go.mod h1:M/YeuJ3vOCQDnP2SU+ZhjgRzwzcBW87JqLpMJLrZDLI= +github.com/go-critic/go-critic v0.14.2 h1:PMvP5f+LdR8p6B29npvChUXbD1vrNlKDf60NJtgMBOo= +github.com/go-critic/go-critic v0.14.2/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= @@ -1031,8 +1031,8 @@ github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkv github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= +github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -1108,10 +1108,10 @@ github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godoc-lint/godoc-lint v0.10.0 h1:OcyrziBi18sQSEpib6NesVHEJ/Xcng97NunePBA48g4= -github.com/godoc-lint/godoc-lint v0.10.0/go.mod h1:KleLcHu/CGSvkjUH2RvZyoK1MBC7pDQg4NxMYLcBBsw= -github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= -github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/godoc-lint/godoc-lint v0.10.1 h1:ZPUVzlDtJfA+P688JfPJPkI/SuzcBr/753yGIk5bOPA= +github.com/godoc-lint/godoc-lint v0.10.1/go.mod h1:KleLcHu/CGSvkjUH2RvZyoK1MBC7pDQg4NxMYLcBBsw= +github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= +github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= @@ -1168,14 +1168,12 @@ github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarog github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint/v2 v2.5.0 h1:BDRg4ASm4J1y/DSRY6zwJ5tr5Yy8ZqbZ79XrCeFxaQo= -github.com/golangci/golangci-lint/v2 v2.5.0/go.mod h1:IJtWJBZkLbx7AVrIUzLd8Oi3ADtwaNpWbR3wthVWHcc= +github.com/golangci/golangci-lint/v2 v2.6.2 h1:jkMSVv36JmyTENcEertckvimvjPcD5qxNM7W7qhECvI= +github.com/golangci/golangci-lint/v2 v2.6.2/go.mod h1:fSIMDiBt9kzdpnvvV7GO6iWzyv5uaeZ+iPor+2uRczE= github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 h1:AkK+w9FZBXlU/xUmBtSJN1+tAI4FIvy5WtnUnY8e4p8= github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95/go.mod h1:k9mmcyWKSTMcPPvQUCfRWWQ9VHJ1U9Dc0R7kaXAgtnQ= github.com/golangci/misspell v0.7.0 h1:4GOHr/T1lTW0hhR4tgaaV1WS/lJ+ncvYCoFKmqJsj0c= github.com/golangci/misspell v0.7.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= -github.com/golangci/nilerr v0.0.0-20250918000102-015671e622fe h1:F1pK9tBy41i7eesBFkSNMldwtiAaWiU+3fT/24sTnNI= -github.com/golangci/nilerr v0.0.0-20250918000102-015671e622fe/go.mod h1:CtTxAluxD2ng9aIT9bPrVoMuISFWCD+SaxtvYtdWA2k= github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= @@ -1245,8 +1243,8 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18= -github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= @@ -1279,13 +1277,15 @@ github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81 github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= -github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0= +github.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E= +github.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA= +github.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs= github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= @@ -1293,6 +1293,8 @@ github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytm github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk= github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= +github.com/gostaticanalysis/nilerr v0.1.2 h1:S6nk8a9N8g062nsx63kUkF6AzbHGw7zzyHMcpu52xQU= +github.com/gostaticanalysis/nilerr v0.1.2/go.mod h1:A19UHhoY3y8ahoL7YKz6sdjDtduwTSI4CsymaC2htPA= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8= github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= @@ -1468,8 +1470,8 @@ github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/karamaru-alpha/copyloopvar v1.2.1 h1:wmZaZYIjnJ0b5UoKDjUHrikcV0zuPyyxI4SVplLd2CI= -github.com/karamaru-alpha/copyloopvar v1.2.1/go.mod h1:nFmMlFNlClC2BPvNaHMdkirmTJxVCY0lhxBtlfOypMM= +github.com/karamaru-alpha/copyloopvar v1.2.2 h1:yfNQvP9YaGQR7VaWLYcfZUlRP2eo2vhExWKxD/fP6q0= +github.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRkmUvH0x35ykgaKgsgJY= github.com/katbyte/andreyvit-diff v0.0.2 h1:uQGxP2z57bTUGn3SCFzYKgtIKLeuYE+k9dxq1u9Js7U= github.com/katbyte/andreyvit-diff v0.0.2/go.mod h1:TdKKfasbASLXZHMVyCoXJw999kjRmOIeHSdG1Pm/x1Y= github.com/katbyte/sergi-go-diff v1.2.2 h1:QfvxByYpWiTcWXVDAxuAx+SY7vY2WEsboJKBDR54Egs= @@ -1513,16 +1515,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98= github.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs= -github.com/kunwardeep/paralleltest v1.0.14 h1:wAkMoMeGX/kGfhQBPODT/BL8XhK23ol/nuQ3SwFaUw8= -github.com/kunwardeep/paralleltest v1.0.14/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= +github.com/kunwardeep/paralleltest v1.0.15 h1:ZMk4Qt306tHIgKISHWFJAO1IDQJLc6uDyJMLyncOb6w= +github.com/kunwardeep/paralleltest v1.0.15/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= -github.com/ldez/exptostd v0.4.4 h1:58AtQjnLcT/tI5W/1KU7xE/O7zW9RAWB6c/ScQAnfus= -github.com/ldez/exptostd v0.4.4/go.mod h1:QfdzPw6oHjFVdNV7ILoPu5sw3OZ3OG1JS0I5JN3J4Js= -github.com/ldez/gomoddirectives v0.7.0 h1:EOx8Dd56BZYSez11LVgdj025lKwlP0/E5OLSl9HDwsY= -github.com/ldez/gomoddirectives v0.7.0/go.mod h1:wR4v8MN9J8kcwvrkzrx6sC9xe9Cp68gWYCsda5xvyGc= +github.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ= +github.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM= +github.com/ldez/gomoddirectives v0.7.1 h1:FaULkvUIG36hj6chpwa+FdCNGZBsD7/fO+p7CCsM6pE= +github.com/ldez/gomoddirectives v0.7.1/go.mod h1:auDNtakWJR1rC+YX7ar+HmveqXATBAyEK1KYpsIRW/8= github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= github.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk= @@ -1546,10 +1548,10 @@ github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLt github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM= github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= -github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= -github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= -github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= -github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8= +github.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ= +github.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs= +github.com/maratori/testpackage v1.1.2/go.mod h1:8F24GdVDFW5Ew43Et02jamrVMNXLUNaOynhDssITGfc= github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4= github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= @@ -1632,16 +1634,16 @@ github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7e github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= -github.com/nunnatsa/ginkgolinter v0.21.0 h1:IYwuX+ajy3G1MezlMLB1BENRtFj16+Evyi4uki1NOOQ= -github.com/nunnatsa/ginkgolinter v0.21.0/go.mod h1:QlzY9UP9zaqu58FjYxhp9bnjuwXwG1bfW5rid9ChNMw= +github.com/nunnatsa/ginkgolinter v0.21.2 h1:khzWfm2/Br8ZemX8QM1pl72LwM+rMeW6VUbQ4rzh0Po= +github.com/nunnatsa/ginkgolinter v0.21.2/go.mod h1:GItSI5fw7mCGLPmkvGYrr1kEetZe7B593jcyOpyabsY= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= -github.com/onsi/gomega v1.38.0 h1:c/WX+w8SLAinvuKKQFh77WEucCnPk4j2OTUr7lt7BeY= -github.com/onsi/gomega v1.38.0/go.mod h1:OcXcwId0b9QsE7Y49u+BTrL4IdKOBOKnD6VQNTJEB6o= +github.com/onsi/ginkgo/v2 v2.26.0 h1:1J4Wut1IlYZNEAWIV3ALrT9NfiaGW2cDCJQSFQMs/gE= +github.com/onsi/ginkgo/v2 v2.26.0/go.mod h1:qhEywmzWTBUY88kfO0BRvX4py7scov9yR+Az2oavUzw= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= @@ -1718,10 +1720,10 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/quasilyte/go-ruleguard v0.4.4 h1:53DncefIeLX3qEpjzlS1lyUmQoUEeOWPFWqaTJq9eAQ= -github.com/quasilyte/go-ruleguard v0.4.4/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= -github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= -github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA= +github.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= +github.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY= +github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= @@ -1775,8 +1777,8 @@ github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PK github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc= github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw= -github.com/securego/gosec/v2 v2.22.8 h1:3NMpmfXO8wAVFZPNsd3EscOTa32Jyo6FLLlW53bexMI= -github.com/securego/gosec/v2 v2.22.8/go.mod h1:ZAw8K2ikuH9qDlfdV87JmNghnVfKB1XC7+TVzk6Utto= +github.com/securego/gosec/v2 v2.22.10 h1:ntbBqdWXnu46DUOXn+R2SvPo3PiJCDugTCgTW2g4tQg= +github.com/securego/gosec/v2 v2.22.10/go.mod h1:9UNjK3tLpv/w2b0+7r82byV43wCJDNtEDQMeS+H/g2w= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= @@ -1978,10 +1980,10 @@ go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= -go.augendre.info/arangolint v0.2.0 h1:2NP/XudpPmfBhQKX4rMk+zDYIj//qbt4hfZmSSTcpj8= -go.augendre.info/arangolint v0.2.0/go.mod h1:Vx4KSJwu48tkE+8uxuf0cbBnAPgnt8O1KWiT7bljq7w= -go.augendre.info/fatcontext v0.8.1 h1:/T4+cCjpL9g71gJpcFAgVo/K5VFpqlN+NPU7QXxD5+A= -go.augendre.info/fatcontext v0.8.1/go.mod h1:r3Qz4ZOzex66wfyyj5VZ1xUcl81vzvHQ6/GWzzlMEwA= +go.augendre.info/arangolint v0.3.1 h1:n2E6p8f+zfXSFLa2e2WqFPp4bfvcuRdd50y6cT65pSo= +go.augendre.info/arangolint v0.3.1/go.mod h1:6ZKzEzIZuBQwoSvlKT+qpUfIbBfFCE5gbAoTg0/117g= +go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= +go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= @@ -2003,18 +2005,18 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY= -go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= -go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= -go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -2031,6 +2033,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s= go.yaml.in/yaml/v4 v4.0.0-rc.2/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -2058,8 +2062,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2079,8 +2083,8 @@ golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWB golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621 h1:Yl4H5w2RV7L/dvSHp2GerziT5K2CORgFINPaMFxWGWw= -golang.org/x/exp/typeparams v0.0.0-20250911091902-df9299821621/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= +golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546 h1:HDjDiATsGqvuqvkDvgJjD1IgPrVekcSXVVE21JwvzGE= +golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -2128,8 +2132,8 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2199,8 +2203,8 @@ golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2254,8 +2258,8 @@ golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2367,8 +2371,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2384,8 +2388,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2407,8 +2411,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2489,8 +2493,8 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -2507,6 +2511,8 @@ gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJ gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= @@ -2712,10 +2718,10 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= -google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0 h1:MAKi5q709QWfnkkpNQ0M12hYJ1+e8qYVDyowc4U1XZM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 h1:FiusG7LWj+4byqhbvmB+Q93B/mOxJLN2DTozDuZm4EU= +google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2759,8 +2765,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= -google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= +google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2780,8 +2786,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2856,8 +2862,8 @@ modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= -mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8= -mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5ginj6dA2oLE7YNlta9qhBNNdCaLE= +mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI= +mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/.github/labeler-issue-triage.yml b/.github/labeler-issue-triage.yml index 6a99713f2025..de4fbdb0e1d1 100644 --- a/.github/labeler-issue-triage.yml +++ b/.github/labeler-issue-triage.yml @@ -246,7 +246,7 @@ service/dynamodbstreams: service/ebs: - '((\*|-)\s*`?|(data|resource)\s+"?)aws_ebs_' service/ec2: - - '((\*|-)\s*`?|(data|resource)\s+"?)aws_(ami|availability_zone|ec2_(availability|capacity|default_credit_specification|fleet|host|instance|public_ipv4_pool|serial|spot|tag)|eip|instance|key_pair|launch_template|placement_group|spot)' + - '((\*|-)\s*`?|(data|resource)\s+"?)aws_(ami|availability_zone|ec2_(allowed_images_settings|availability|capacity|default_credit_specification|fleet|host|instance|public_ipv4_pool|serial|spot|tag)|eip|instance|key_pair|launch_template|placement_group|spot)' service/ec2ebs: - '((\*|-)\s*`?|(data|resource)\s+"?)aws_(ebs_|volume_attach|snapshot_create)' service/ec2instanceconnect: diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index bcd156ad977b..5ee1b6d5f3d2 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -791,6 +791,7 @@ service/ec2: - 'internal/service/ec2/**/ec2_*' - 'website/**/ami*' - 'website/**/availability_zone*' + - 'website/**/ec2_allowed_images_settings*' - 'website/**/ec2_availability_*' - 'website/**/ec2_capacity_*' - 'website/**/ec2_default_credit_specification*' diff --git a/.github/workflows/acctest-terraform-embedded-lint.yml b/.github/workflows/acctest-terraform-embedded-lint.yml index 9a901e64ae81..03a75ff555c6 100644 --- a/.github/workflows/acctest-terraform-embedded-lint.yml +++ b/.github/workflows/acctest-terraform-embedded-lint.yml @@ -23,7 +23,7 @@ jobs: terrafmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -51,7 +51,7 @@ jobs: TEST_FILES_PARTITION: '\./internal/service/${{ matrix.path }}.*/.*_test\.go' steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/acctest-terraform-lint.yml b/.github/workflows/acctest-terraform-lint.yml index 27562381ec86..5b8377575feb 100644 --- a/.github/workflows/acctest-terraform-lint.yml +++ b/.github/workflows/acctest-terraform-lint.yml @@ -22,7 +22,7 @@ jobs: terrafmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -41,7 +41,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5c45f97f02ca..3d32b97b64f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: 'go.mod' @@ -52,7 +52,7 @@ jobs: product-prerelease-version: ${{ steps.set-product-version.outputs.prerelease-product-version }} product-minor-version: ${{ steps.set-product-version.outputs.minor-product-version }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Set variables id: set-product-version uses: hashicorp/actions-set-product-version@v2 @@ -67,7 +67,7 @@ jobs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: "Checkout directory" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Generate metadata file id: generate-metadata-file uses: hashicorp/actions-generate-metadata@v1 @@ -85,7 +85,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout directory" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: path: ${{ env.PKG_NAME }} - name: "Copy manifest from checkout directory to a file with the desired name" @@ -137,7 +137,7 @@ jobs: name: Go ${{ needs.get-go-version.outputs.go-version }} ${{ matrix.goos }} ${{ matrix.goarch }} build steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: hashicorp/actions-go-build@v1 env: CGO_ENABLED: 0 diff --git a/.github/workflows/changelog_misspell.yml b/.github/workflows/changelog_misspell.yml index 6f2ef972bbb7..ef983981a41d 100644 --- a/.github/workflows/changelog_misspell.yml +++ b/.github/workflows/changelog_misspell.yml @@ -20,7 +20,7 @@ jobs: misspell: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/closed_items.yml b/.github/workflows/closed_items.yml index 63d0e49879a3..7ea88d641da6 100644 --- a/.github/workflows/closed_items.yml +++ b/.github/workflows/closed_items.yml @@ -42,7 +42,7 @@ jobs: > > Ongoing conversations amongst community members are welcome, however, the issue will be locked after 30 days. Moving conversations to another venue, such as the [AWS Provider forum](https://discuss.hashicorp.com/c/terraform-providers/tf-aws/33), is recommended. If you have additional concerns, please open a new issue, referencing this one where needed." - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 id: checkout if: github.event.pull_request.merged with: diff --git a/.github/workflows/comments.yml b/.github/workflows/comments.yml index ac4cdc01045c..3178e0aaa15e 100644 --- a/.github/workflows/comments.yml +++ b/.github/workflows/comments.yml @@ -13,7 +13,7 @@ jobs: comment: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: sparse-checkout: .github/actions/community_check diff --git a/.github/workflows/copyright.yml b/.github/workflows/copyright.yml index 66811cdfa38a..450823f65b64 100644 --- a/.github/workflows/copyright.yml +++ b/.github/workflows/copyright.yml @@ -24,7 +24,7 @@ jobs: name: add headers check runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 0f3fec27bdf5..aec60ee9c2c0 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -37,7 +37,7 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - name: Setup Go diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 3a957c580103..b89e0229e652 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -23,7 +23,7 @@ jobs: env: UV_THREADPOOL_SIZE: 128 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: YakDriver/md-check-links@0a295ce2e08c544aae01cccc9b4c6801a8398942 # v2.2.0 with: quiet: 'yes' @@ -36,14 +36,14 @@ jobs: markdown-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: avto-dev/markdown-lint@04d43ee9191307b50935a753da3b775ab695eceb # v1.5.0 with: args: 'docs' misspell: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 913f8237e98e..f7d43b9bbf2f 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -24,7 +24,7 @@ jobs: tflint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 @@ -61,7 +61,7 @@ jobs: env: TF_IN_AUTOMATION: "1" steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 diff --git a/.github/workflows/gen-teamcity.yml b/.github/workflows/gen-teamcity.yml index 436f8185b0ea..643e592bbf0e 100644 --- a/.github/workflows/gen-teamcity.yml +++ b/.github/workflows/gen-teamcity.yml @@ -13,7 +13,7 @@ jobs: name: Validate TeamCity Configuration runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0 with: distribution: adopt diff --git a/.github/workflows/generate_changelog.yml b/.github/workflows/generate_changelog.yml index 60a83b7d6dcb..672e867474bc 100644 --- a/.github/workflows/generate_changelog.yml +++ b/.github/workflows/generate_changelog.yml @@ -13,7 +13,7 @@ jobs: with: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PEM }} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 5bde7fe2e537..a821ff103c44 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -27,7 +27,7 @@ jobs: name: 1 of 5 runs-on: custom-ubuntu-22.04-large steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -41,7 +41,7 @@ jobs: awk '{print $2}' )" >> $GITHUB_OUTPUT - name: golangci-lint - uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 + uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47 # v9.0.0 with: version: "${{ steps.golangci-lint-version.outputs.version }}" args: --config .ci/.golangci.yml @@ -50,7 +50,7 @@ jobs: needs: [golangci-linta] runs-on: custom-ubuntu-22.04-xl steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -64,7 +64,7 @@ jobs: awk '{print $2}' )" >> $GITHUB_OUTPUT - name: golangci-lint - uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 + uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47 # v9.0.0 with: version: "${{ steps.golangci-lint-version.outputs.version }}" args: --config .ci/.golangci2.yml @@ -78,7 +78,7 @@ jobs: needs: [golangci-linta] runs-on: custom-ubuntu-22.04-xl steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -92,7 +92,7 @@ jobs: awk '{print $2}' )" >> $GITHUB_OUTPUT - name: golangci-lint - uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 + uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47 # v9.0.0 with: version: "${{ steps.golangci-lint-version.outputs.version }}" args: --config .ci/.golangci3.yml @@ -106,7 +106,7 @@ jobs: needs: [golangci-linta] runs-on: custom-ubuntu-22.04-xl steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -120,7 +120,7 @@ jobs: awk '{print $2}' )" >> $GITHUB_OUTPUT - name: golangci-lint - uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 + uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47 # v9.0.0 with: version: "${{ steps.golangci-lint-version.outputs.version }}" args: --config .ci/.golangci4.yml @@ -134,7 +134,7 @@ jobs: needs: [golangci-linta] runs-on: custom-ubuntu-22.04-xl steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -148,7 +148,7 @@ jobs: awk '{print $2}' )" >> $GITHUB_OUTPUT - name: golangci-lint - uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 + uses: golangci/golangci-lint-action@0a35821d5c230e903fcfe077583637dea1b27b47 # v9.0.0 with: version: "${{ steps.golangci-lint-version.outputs.version }}" args: --config .ci/.golangci5.yml diff --git a/.github/workflows/maintainer_helpers.yml b/.github/workflows/maintainer_helpers.yml index 68d1f227d44e..f6d9de2cb46e 100644 --- a/.github/workflows/maintainer_helpers.yml +++ b/.github/workflows/maintainer_helpers.yml @@ -45,7 +45,7 @@ jobs: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PEM }} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: sparse-checkout: .github/actions/ @@ -104,7 +104,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: sparse-checkout: .github/actions/ diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml index ba98dc0e44d8..d387d15c5683 100644 --- a/.github/workflows/milestone.yml +++ b/.github/workflows/milestone.yml @@ -27,7 +27,7 @@ jobs: MILESTONE: ${{ github.event.milestone.number }} steps: - name: 'Checkout Repo' - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: 'Remove Prioritized Label' env: diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml index df12f1014210..c3cacdc5811d 100644 --- a/.github/workflows/mkdocs.yml +++ b/.github/workflows/mkdocs.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout main - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Deploy docs uses: mhausenblas/mkdocs-deploy-gh-pages@d77dd03172e96abbcdb081d8c948224762033653 # 1.26 diff --git a/.github/workflows/modern_go.yml b/.github/workflows/modern_go.yml index 650150d9d276..90d1d48e7617 100644 --- a/.github/workflows/modern_go.yml +++ b/.github/workflows/modern_go.yml @@ -21,7 +21,7 @@ jobs: name: Check for modern Go code runs-on: custom-ubuntu-22.04-medium steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/provider.yml b/.github/workflows/provider.yml index 3099b51321df..92ac4109f36f 100644 --- a/.github/workflows/provider.yml +++ b/.github/workflows/provider.yml @@ -37,7 +37,7 @@ jobs: name: go mod download runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -56,7 +56,7 @@ jobs: needs: [go_mod_download] runs-on: custom-ubuntu-22.04-medium steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 continue-on-error: true id: cache-terraform-plugin-dir @@ -92,7 +92,7 @@ jobs: needs: [go_build] runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -125,7 +125,7 @@ jobs: needs: [go_build] runs-on: custom-ubuntu-22.04-xl steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 @@ -154,7 +154,7 @@ jobs: needs: [go_build] runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -185,7 +185,7 @@ jobs: needs: [go_build] runs-on: custom-ubuntu-22.04-medium steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 @@ -243,7 +243,7 @@ jobs: needs: [go_build] runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 continue-on-error: true id: cache-terraform-providers-schema @@ -278,7 +278,7 @@ jobs: needs: [terraform_providers_schema] runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod @@ -306,7 +306,7 @@ jobs: markdown-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: avto-dev/markdown-lint@04d43ee9191307b50935a753da3b775ab695eceb # v1.5.0 with: args: "." @@ -315,7 +315,7 @@ jobs: misspell: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/providerlint.yml b/.github/workflows/providerlint.yml index 686c9582be95..55eb2275c60a 100644 --- a/.github/workflows/providerlint.yml +++ b/.github/workflows/providerlint.yml @@ -23,7 +23,7 @@ jobs: providerlint: runs-on: custom-ubuntu-22.04-medium steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/pull_request_review.yml b/.github/workflows/pull_request_review.yml index 203d6f597f64..db8373bffbbc 100644 --- a/.github/workflows/pull_request_review.yml +++ b/.github/workflows/pull_request_review.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Community Check - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: sparse-checkout: .github/actions/community_check diff --git a/.github/workflows/pull_request_target.yml b/.github/workflows/pull_request_target.yml index 725bbaa39c37..4fe096c62b6b 100644 --- a/.github/workflows/pull_request_target.yml +++ b/.github/workflows/pull_request_target.yml @@ -29,7 +29,7 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - name: Setup Go diff --git a/.github/workflows/readiness_comment.yml b/.github/workflows/readiness_comment.yml index a1d4145c1b7c..9e98d395986f 100644 --- a/.github/workflows/readiness_comment.yml +++ b/.github/workflows/readiness_comment.yml @@ -49,7 +49,7 @@ jobs: has: - '.changelog/**' - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 id: checkout if: | steps.filter.outputs.changelog == 'true' diff --git a/.github/workflows/resource-counts.yml b/.github/workflows/resource-counts.yml index 4be90153b0c3..fc76715a5104 100644 --- a/.github/workflows/resource-counts.yml +++ b/.github/workflows/resource-counts.yml @@ -18,7 +18,7 @@ jobs: installation_retrieval_mode: id installation_retrieval_payload: ${{ secrets.INSTALLATION_ID }} private_key: ${{secrets.APP_PEM }} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd with: terraform_version: ${{ env.TERRAFORM_VERSION }} diff --git a/.github/workflows/semgrep-ci.yml b/.github/workflows/semgrep-ci.yml index 0319cb8684ad..7c984469e6b1 100644 --- a/.github/workflows/semgrep-ci.yml +++ b/.github/workflows/semgrep-ci.yml @@ -30,7 +30,7 @@ jobs: container: image: "semgrep/semgrep:1.110.0" steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: | semgrep --validate \ --config .ci/.semgrep.yml \ @@ -45,7 +45,7 @@ jobs: container: image: "semgrep/semgrep:1.110.0" steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: | semgrep --quiet --test .ci/semgrep/ @@ -56,7 +56,7 @@ jobs: container: image: "semgrep/semgrep:1.110.0" steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: | semgrep $SEMGREP_ARGS \ --config .ci/.semgrep.yml \ @@ -77,7 +77,7 @@ jobs: image: "semgrep/semgrep:1.110.0" if: (github.action != 'dependabot[bot]') steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: semgrep --validate --config .ci/.semgrep-caps-aws-ec2.yml - run: semgrep $SEMGREP_ARGS --config .ci/.semgrep-caps-aws-ec2.yml @@ -88,7 +88,7 @@ jobs: image: "semgrep/semgrep:1.110.0" if: (github.action != 'dependabot[bot]') steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: semgrep --validate --config .ci/.semgrep-configs.yml - run: semgrep $SEMGREP_ARGS --config .ci/.semgrep-configs.yml @@ -99,7 +99,7 @@ jobs: image: "semgrep/semgrep:1.110.0" if: (github.action != 'dependabot[bot]') steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: semgrep --validate --config .ci/.semgrep-service-name0.yml - run: semgrep $SEMGREP_ARGS --config .ci/.semgrep-service-name0.yml @@ -110,7 +110,7 @@ jobs: image: "semgrep/semgrep:1.110.0" if: (github.action != 'dependabot[bot]') steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: semgrep --validate --config .ci/.semgrep-service-name1.yml - run: semgrep $SEMGREP_ARGS --config .ci/.semgrep-service-name1.yml @@ -121,7 +121,7 @@ jobs: image: "semgrep/semgrep:1.110.0" if: (github.action != 'dependabot[bot]') steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: semgrep --validate --config .ci/.semgrep-service-name2.yml - run: semgrep $SEMGREP_ARGS --config .ci/.semgrep-service-name2.yml @@ -132,6 +132,6 @@ jobs: image: "semgrep/semgrep:1.110.0" if: (github.action != 'dependabot[bot]') steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - run: semgrep --validate --config .ci/.semgrep-service-name3.yml - run: semgrep $SEMGREP_ARGS --config .ci/.semgrep-service-name3.yml diff --git a/.github/workflows/skaff.yml b/.github/workflows/skaff.yml index aeb4e3f45ab5..a53c1bff6204 100644 --- a/.github/workflows/skaff.yml +++ b/.github/workflows/skaff.yml @@ -21,7 +21,7 @@ jobs: name: Compile skaff runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 diff --git a/.github/workflows/smarterr.yml b/.github/workflows/smarterr.yml index e7e89025b86a..827ceab80877 100644 --- a/.github/workflows/smarterr.yml +++ b/.github/workflows/smarterr.yml @@ -21,7 +21,7 @@ jobs: name: Check smarterr config runs-on: custom-ubuntu-22.04-medium steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: go.mod diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml index 718ef501d529..6ee2d97e77c4 100644 --- a/.github/workflows/triage.yml +++ b/.github/workflows/triage.yml @@ -25,7 +25,7 @@ jobs: name: Labelers runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: sparse-checkout: .github diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index f25f935065f3..ab81a3ee2530 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: token: ${{ secrets.GITHUB_TOKEN }} fetch-depth: 0 diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 840d08a0c433..d79ed34975c9 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -26,7 +26,7 @@ jobs: markdown-link-check-a-h-markdown: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: YakDriver/md-check-links@0a295ce2e08c544aae01cccc9b4c6801a8398942 # v2.2.0 name: markdown-link-check website/docs/**/[a-h].markdown with: @@ -42,7 +42,7 @@ jobs: markdown-link-check-i-z-markdown: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: YakDriver/md-check-links@0a295ce2e08c544aae01cccc9b4c6801a8398942 # v2.2.0 name: markdown-link-check website/docs/**/[i-z].markdown with: @@ -58,7 +58,7 @@ jobs: markdown-link-check-md: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: YakDriver/md-check-links@0a295ce2e08c544aae01cccc9b4c6801a8398942 # v2.2.0 name: markdown-link-check website/docs/**/*.md with: @@ -76,7 +76,7 @@ jobs: markdown-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: avto-dev/markdown-lint@04d43ee9191307b50935a753da3b775ab695eceb # v1.5.0 with: args: "website/docs" @@ -86,7 +86,7 @@ jobs: misspell: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: .ci/tools/go.mod @@ -102,7 +102,7 @@ jobs: terrafmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: .ci/tools/go.mod @@ -118,7 +118,7 @@ jobs: tflint: runs-on: custom-ubuntu-22.04-xl steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 diff --git a/.github/workflows/workflow-lint.yml b/.github/workflows/workflow-lint.yml index 0e2da7e9cad8..e4ac6590abc1 100644 --- a/.github/workflows/workflow-lint.yml +++ b/.github/workflows/workflow-lint.yml @@ -19,7 +19,7 @@ jobs: actionlint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version-file: .ci/tools/go.mod diff --git a/.github/workflows/yamllint.yml b/.github/workflows/yamllint.yml index 3f444a6e21fb..a7ff7d5fee54 100644 --- a/.github/workflows/yamllint.yml +++ b/.github/workflows/yamllint.yml @@ -20,7 +20,7 @@ jobs: yamllint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Run yamllint uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1 with: diff --git a/.gitignore b/.gitignore index 4d17eaa2a430..97b9c6e6c787 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ *.prof *.test *~ +/.kiro /pkg/ aws/testdata/service/cloudformation/examplecompany-exampleservice-exampleresource/bin/handler bin/ diff --git a/.go-version b/.go-version index f666fce1a2bb..c4bdc90e96da 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.24.8 +1.24.10 diff --git a/CHANGELOG.md b/CHANGELOG.md index a47c7bdb8311..1ef19eedb880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,139 @@ -## 6.20.0 (Unreleased) +## 6.22.0 (Unreleased) + +NOTES: + +* resource/aws_s3_bucket_server_side_encryption_configuration: Starting in March 2026, Amazon S3 will introduce a new default bucket security setting by automatically disabling server-side encryption with customer-provided keys (SSE-C) for all new buckets. Use the `blocked_encryption_types` argument to manage this behavior for specific buckets. ([#45105](https://github.com/hashicorp/terraform-provider-aws/issues/45105)) FEATURES: +* **New Ephemeral Resource:** `aws_ecr_authorization_token` ([#44949](https://github.com/hashicorp/terraform-provider-aws/issues/44949)) +* **New Resource:** `aws_vpclattice_domain_verification` ([#45085](https://github.com/hashicorp/terraform-provider-aws/issues/45085)) + +ENHANCEMENTS: + +* data-source/aws_lb_listener: Add `default_action.jwt_validation` attribute ([#45089](https://github.com/hashicorp/terraform-provider-aws/issues/45089)) +* data-source/aws_lb_listener_rule: Add `action.jwt_validation` attribute ([#45089](https://github.com/hashicorp/terraform-provider-aws/issues/45089)) +* data-source/aws_route53_zone: Support filtering by `tags` only or by `vpc_id` only ([#39671](https://github.com/hashicorp/terraform-provider-aws/issues/39671)) +* resource/aws_backup_logically_air_gapped_vault: Add `encryption_key_arn` argument ([#45020](https://github.com/hashicorp/terraform-provider-aws/issues/45020)) +* resource/aws_bedrockagent_knowledge_base: Add `storage_configuration.rds_configuration.field_mapping.custom_metadata_field` argument ([#45075](https://github.com/hashicorp/terraform-provider-aws/issues/45075)) +* resource/aws_bedrockagentcore_agent_runtime: Add `agent_runtime_artifact.code_configuration` block ([#45091](https://github.com/hashicorp/terraform-provider-aws/issues/45091)) +* resource/aws_bedrockagentcore_agent_runtime: Make `agent_runtime_artifact.container_configuration` block optional ([#45091](https://github.com/hashicorp/terraform-provider-aws/issues/45091)) +* resource/aws_dynamodb_table: Add `global_table_witness` argument ([#43908](https://github.com/hashicorp/terraform-provider-aws/issues/43908)) +* resource/aws_emr_managed_scaling_policy: Add `scaling_strategy` and `utilization_performance_index` arguments ([#45132](https://github.com/hashicorp/terraform-provider-aws/issues/45132)) +* resource/aws_fis_experiment_template: Add plan-time validation of `log_configuration.cloudwatch_logs_configuration.log_group_arn` ([#35941](https://github.com/hashicorp/terraform-provider-aws/issues/35941)) +* resource/aws_fis_experiment_template: Add support for `Functions` to `action.*.target` ([#41209](https://github.com/hashicorp/terraform-provider-aws/issues/41209)) +* resource/aws_lambda_invocation: Add import support ([#41240](https://github.com/hashicorp/terraform-provider-aws/issues/41240)) +* resource/aws_lb_listener: Support `jwt-validation` as a valid `default_action.type` and add `default_action.jwt_validation` configuration block ([#45089](https://github.com/hashicorp/terraform-provider-aws/issues/45089)) +* resource/aws_lb_listener_rule: Support `jwt-validation` as a valid `action.type` and add `action.jwt_validation` configuration block ([#45089](https://github.com/hashicorp/terraform-provider-aws/issues/45089)) +* resource/aws_odb_cloud_vm_cluster: vm cluster creation using odb network ARN and exadata infrastructure ARN for resource sharing model. ([#45003](https://github.com/hashicorp/terraform-provider-aws/issues/45003)) +* resource/aws_organizations_organization: Add `SECURITYHUB_POLICY` as a valid value for `enabled_policy_types` argument ([#45135](https://github.com/hashicorp/terraform-provider-aws/issues/45135)) +* resource/aws_prometheus_query_logging_configuration: Add plan-time validation of `destination.cloudwatch_logs.log_group_arn` ([#35941](https://github.com/hashicorp/terraform-provider-aws/issues/35941)) +* resource/aws_prometheus_workspace: Add plan-time validation of `logging_configuration.log_group_arn` ([#35941](https://github.com/hashicorp/terraform-provider-aws/issues/35941)) +* resource/aws_s3_bucket_server_side_encryption_configuration: Add `rule.blocked_encryption_types` argument ([#45105](https://github.com/hashicorp/terraform-provider-aws/issues/45105)) +* resource/aws_sagemaker_model: Add `container.additional_model_data_source` and `primary_container.additional_model_data_source` arguments ([#44407](https://github.com/hashicorp/terraform-provider-aws/issues/44407)) +* resource/aws_sfn_state_machine: Add plan-time validation of `logging_configuration.log_destination` ([#35941](https://github.com/hashicorp/terraform-provider-aws/issues/35941)) +* resource/aws_timestreaminfluxdb_db_cluster: Add `engine_type` attribute ([#44899](https://github.com/hashicorp/terraform-provider-aws/issues/44899)) +* resource/aws_timestreaminfluxdb_db_cluster: Add validation to ensure InfluxDB V2 clusters have required fields and InfluxDB V3 clusters (when using V3 parameter groups) do not have forbidden V2 fields. This functionality requires the `timestream-influxdb:GetDbParameterGroup` IAM permission ([#44899](https://github.com/hashicorp/terraform-provider-aws/issues/44899)) +* resource/aws_vpclattice_resource_configuration: Add `custom_domain_name` and `domain_verification_id` arguments and `domain_verification_arn` and `domain_verification_status` attributes to support custom domain names for resource configurations ([#45085](https://github.com/hashicorp/terraform-provider-aws/issues/45085)) +* resource/aws_vpn_connection: Add `tunnel_bandwidth` argument to support higher bandwidth tunnels ([#45070](https://github.com/hashicorp/terraform-provider-aws/issues/45070)) + +BUG FIXES: + +* resource/aws_db_instance: Fix blue/green deployments failing with "not in available state" by improving stability and handling `storage-config-upgrade` and `storage-initialization` statuses ([#41275](https://github.com/hashicorp/terraform-provider-aws/issues/41275)) +* resource/aws_elastic_beanstalk_configuration_template: Fix updates not applying by including `ResourceName` for option settings and preventing duplicate add/remove operations ([#45077](https://github.com/hashicorp/terraform-provider-aws/issues/45077)) +* resource/aws_odb_cloud_vm_cluster: support for hyphen in odb cloud vm cluster hostname prefix. ([#45003](https://github.com/hashicorp/terraform-provider-aws/issues/45003)) +* resource/aws_quicksight_account_settings: Add `region` argument ([#45083](https://github.com/hashicorp/terraform-provider-aws/issues/45083)) +* resource/aws_s3_directory_bucket: Fix plan-time `AWS resource not found during refresh` warnings causing resource replacement when `ReadOnly` `s3express:SessionMode` is enforced ([#45086](https://github.com/hashicorp/terraform-provider-aws/issues/45086)) +* resource/aws_ssoadmin_account_assignment: Correct `target_type` argument to required ([#45092](https://github.com/hashicorp/terraform-provider-aws/issues/45092)) +* resource/aws_timestreaminfluxdb_db_cluster: Make `allocated_storage`, `bucket`, `organization`, `username`, and `password` optional to support InfluxDB V3 clusters ([#44899](https://github.com/hashicorp/terraform-provider-aws/issues/44899)) + +## 6.21.0 (November 13, 2025) + +BREAKING CHANGES: + +* resource/aws_bedrockagentcore_browser: Rename `network_configuration.network_mode_config` to `network_configuration.vpc_config` ([#44828](https://github.com/hashicorp/terraform-provider-aws/issues/44828)) + +FEATURES: + +* **New Action:** `aws_dynamodb_create_backup` ([#45001](https://github.com/hashicorp/terraform-provider-aws/issues/45001)) +* **New Resource:** `aws_networkflowmonitor_monitor` ([#44782](https://github.com/hashicorp/terraform-provider-aws/issues/44782)) +* **New Resource:** `aws_networkflowmonitor_scope` ([#44782](https://github.com/hashicorp/terraform-provider-aws/issues/44782)) +* **New Resource:** `aws_observabilityadmin_centralization_rule_for_organization` ([#44806](https://github.com/hashicorp/terraform-provider-aws/issues/44806)) + +ENHANCEMENTS: + +* data-source/aws_ecs_service: Add `capacity_provider_strategy`, `created_at`, `created_by`, `deployment_configuration`, `deployment_controller`, `deployments`, `enable_ecs_managed_tags`, `enable_execute_command`, `events`, `health_check_grace_period_seconds`, `iam_role`, `network_configuration`, `ordered_placement_strategy`, `pending_count`, `placement_constraints`, `platform_family`, `platform_version`, `propagate_tags`, `running_count`, `service_connect_configuration`, `service_registries`, `status`, and `task_sets` attributes ([#44842](https://github.com/hashicorp/terraform-provider-aws/issues/44842)) +* resource/aws_bedrockagentcore_gateway_target: Add `target_configuration.mcp.mcp_server` block ([#44991](https://github.com/hashicorp/terraform-provider-aws/issues/44991)) +* resource/aws_bedrockagentcore_gateway_target: Make `credential_provider_configuration` block optional ([#44991](https://github.com/hashicorp/terraform-provider-aws/issues/44991)) +* resource/aws_cloudwatch_log_delivery_destination: Make `delivery_destination_type` and `delivery_destination_configuration` optional to support AWS X-Ray as a destination ([#44995](https://github.com/hashicorp/terraform-provider-aws/issues/44995)) +* resource/aws_ecs_service: Add support for `LINEAR` and `CANARY` deployment strategies with `deployment_configuration.linear_configuration` and `deployment_configuration.canary_configuration` blocks ([#44842](https://github.com/hashicorp/terraform-provider-aws/issues/44842)) +* resource/aws_lambda_function: Add support for `java25` `runtime` value ([#45024](https://github.com/hashicorp/terraform-provider-aws/issues/45024)) +* resource/aws_lambda_function: Add support for `nodejs24.x` `runtime` value ([#45024](https://github.com/hashicorp/terraform-provider-aws/issues/45024)) +* resource/aws_lambda_function: Add support for `python3.14` `runtime` value ([#45024](https://github.com/hashicorp/terraform-provider-aws/issues/45024)) +* resource/aws_lambda_layer_version: Add support for `java25` `compatible_runtimes` value ([#45024](https://github.com/hashicorp/terraform-provider-aws/issues/45024)) +* resource/aws_lambda_layer_version: Add support for `nodejs24.x` `compatible_runtimes` value ([#45024](https://github.com/hashicorp/terraform-provider-aws/issues/45024)) +* resource/aws_lambda_layer_version: Add support for `python3.14` `compatible_runtimes` value ([#45024](https://github.com/hashicorp/terraform-provider-aws/issues/45024)) +* resource/aws_s3tables_table: Add tagging support ([#44996](https://github.com/hashicorp/terraform-provider-aws/issues/44996)) +* resource/aws_s3tables_table_bucket: Add tagging support ([#44996](https://github.com/hashicorp/terraform-provider-aws/issues/44996)) +* resource/aws_sagemaker_endpoint_configuration: Add `execution_role_arn` argument and make `model_name` optional in `production_variants` and `shadow_production_variants` blocks to support Inference Components ([#44977](https://github.com/hashicorp/terraform-provider-aws/issues/44977)) +* resource/aws_sns_topic: Fix `AuthorizationError ... is not authorized to perform: iam:PassRole on resource ...` IAM eventual consistency errors on Create and Update ([#45018](https://github.com/hashicorp/terraform-provider-aws/issues/45018)) + +BUG FIXES: + +* provider: Fix situation where refreshes of removed infrastructure appear as errors rather than warnings ([#45022](https://github.com/hashicorp/terraform-provider-aws/issues/45022)) +* resource/aws_acmpca_certificate_authority: Prevents error when upgrading from provider pre-v6.0 without refreshing ([#45050](https://github.com/hashicorp/terraform-provider-aws/issues/45050)) +* resource/aws_apprunner_service: Prevents error when upgrading from provider pre-v6.0 without refreshing ([#45051](https://github.com/hashicorp/terraform-provider-aws/issues/45051)) +* resource/aws_ec2_image_block_public_access: Add `region` argument ([#45023](https://github.com/hashicorp/terraform-provider-aws/issues/45023)) +* resource/aws_ec2_serial_console_access: Add `region` argument ([#45064](https://github.com/hashicorp/terraform-provider-aws/issues/45064)) +* resource/aws_emrcontainers_job_template: Fix `ValidationException: Value null at 'jobTemplateData.configurationOverrides.monitoringConfiguration.cloudWatchMonitoringConfiguration.logGroupName' failed to satisfy constraint: Member must not be null` error ([#45029](https://github.com/hashicorp/terraform-provider-aws/issues/45029)) +* resource/aws_emrcontainers_job_template: Fix `setting job_template_data: job_template_data.0.configuration_overrides.0.application_configuration.0: '' expected a map, got 'slice'` error ([#45029](https://github.com/hashicorp/terraform-provider-aws/issues/45029)) +* resource/aws_emrcontainers_job_template: Mark `job_template_data.job_driver.configuration_overrides.monitoring_configuration.persistent_app_ui` argument as computed ([#45029](https://github.com/hashicorp/terraform-provider-aws/issues/45029)) +* resource/aws_invoicing_invoice_unit: Fix `Provider returned invalid result object after apply` error occurred when updating the resource ([#45030](https://github.com/hashicorp/terraform-provider-aws/issues/45030)) +* resource/aws_opensearch_authorize_vpc_endpoint_access: Fix reading the resource when more than one principal is authorized. The [import ID](https://developer.hashicorp.com/terraform/language/block/import#id) has changed from `domain_name` to `domain_name` and `account` separated by a comma ([#44982](https://github.com/hashicorp/terraform-provider-aws/issues/44982)) +* resource/aws_redshift_cluster: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_cluster_snapshot: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_event_subscription: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_hsm_client_certificate: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_hsm_configuration: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_integration: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_parameter_group: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_snapshot_copy_grant: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_snapshot_schedule: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_subnet_group: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_usage_limit: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_sagemaker_endpoint: Fix bug where `endpoint_config_name` was not correctly updated, causing the endpoint to retain the old configuration ([#42843](https://github.com/hashicorp/terraform-provider-aws/issues/42843)) +* resource/aws_wafv2_web_acl_logging_configuration: Fix the validation for `redacted_fields.single_header.name` ([#44987](https://github.com/hashicorp/terraform-provider-aws/issues/44987)) + +## 6.20.0 (November 6, 2025) + +FEATURES: + +* **New Resource:** `aws_ec2_allowed_images_settings` ([#44800](https://github.com/hashicorp/terraform-provider-aws/issues/44800)) * **New Resource:** `aws_fis_target_account_configuration` ([#44875](https://github.com/hashicorp/terraform-provider-aws/issues/44875)) * **New Resource:** `aws_invoicing_invoice_unit` ([#44892](https://github.com/hashicorp/terraform-provider-aws/issues/44892)) ENHANCEMENTS: +* data-source/aws_connect_routing_profile: Add `media_concurrencies.cross_channel_behavior` attribute ([#44934](https://github.com/hashicorp/terraform-provider-aws/issues/44934)) * data-source/aws_elasticache_replication_group: Add `node_group_configuration` attribute to expose node group details including availability zones, replica counts, and slot ranges ([#44879](https://github.com/hashicorp/terraform-provider-aws/issues/44879)) * data-source/aws_kinesis_stream: Add `max_record_size_in_kib` attribute ([#44915](https://github.com/hashicorp/terraform-provider-aws/issues/44915)) +* data-source/aws_opensearch_domain: Add `identity_center_options` attribute ([#44626](https://github.com/hashicorp/terraform-provider-aws/issues/44626)) +* provider: Support `us-isob-west-1` as a valid AWS Region ([#44944](https://github.com/hashicorp/terraform-provider-aws/issues/44944)) * resource/aws_cloudfront_distribution: Add `logging_v1_enabled` attribute ([#44838](https://github.com/hashicorp/terraform-provider-aws/issues/44838)) +* resource/aws_connect_routing_profile: Add `media_concurrencies.cross_channel_behavior` argument ([#44934](https://github.com/hashicorp/terraform-provider-aws/issues/44934)) * resource/aws_ec2_client_vpn_route: Allow IPv6 address ranges for `destination_cidr_block` ([#44926](https://github.com/hashicorp/terraform-provider-aws/issues/44926)) * resource/aws_ec2_instance_connect_endpoint: Add `ip_address_type` argument ([#44616](https://github.com/hashicorp/terraform-provider-aws/issues/44616)) * resource/aws_eks_node_group: Add `max_parallel_nodes_repaired_count`, `max_parallel_nodes_repaired_percentage`, `max_unhealthy_node_threshold_count`, `max_unhealthy_node_threshold_percentage`, and `node_repair_config_overrides` to the `node_repair_config` schema ([#44894](https://github.com/hashicorp/terraform-provider-aws/issues/44894)) * resource/aws_elasticache_replication_group: Add `node_group_configuration` block to support availability zone specification and snapshot restoration for cluster mode enabled replication groups ([#44879](https://github.com/hashicorp/terraform-provider-aws/issues/44879)) * resource/aws_glue_job: Ensure that `timeout` is unconfigured for Ray jobs ([#35012](https://github.com/hashicorp/terraform-provider-aws/issues/35012)) * resource/aws_kinesis_stream: Add `max_record_size_in_kib` argument to support for Kinesis 10MiB payloads. This functionality requires the `kinesis:UpdateMaxRecordSize` IAM permission ([#44915](https://github.com/hashicorp/terraform-provider-aws/issues/44915)) +* resource/aws_opensearch_domain: Add `identity_center_options` configuration block ([#44626](https://github.com/hashicorp/terraform-provider-aws/issues/44626)) * resource/aws_transfer_server: Add support for `TransferSecurityPolicy-AS2Restricted-2025-07` `security_policy_name` value ([#44865](https://github.com/hashicorp/terraform-provider-aws/issues/44865)) * resource/aws_transfer_server: Support `TransferSecurityPolicy-AS2Restricted-2025-07` as a valid value for `security_policy_name` ([#44652](https://github.com/hashicorp/terraform-provider-aws/issues/44652)) BUG FIXES: -* provider: Support `us-isob-west-1` as a valid AWS Region ([#44944](https://github.com/hashicorp/terraform-provider-aws/issues/44944)) +* resource/aws_cloudfront_continuous_deployment_policy: Fix `Source type "...cloudfront.stagingDistributionDNSNamesModel" does not implement attr.Value` error. This fixes a regression introduced in [v6.17.0](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md#6170-october-16-2025) ([#44972](https://github.com/hashicorp/terraform-provider-aws/issues/44972)) * resource/aws_cloudfront_distribution: Change `logging_config.bucket` argument from `Required` to `Optional` ([#44838](https://github.com/hashicorp/terraform-provider-aws/issues/44838)) * resource/aws_cloudfront_distribution: Fix inability to configure `logging_config.include_cookies` argument while keeping V1 logging disabled ([#44838](https://github.com/hashicorp/terraform-provider-aws/issues/44838)) * resource/aws_cloudfront_vpc_origin: Fix `Source type "...cloudfront.originSSLProtocolsModel" does not implement attr.Value` and `missing required field, CreateVpcOriginInput.VpcOriginEndpointConfig` errors. This fixes a regression introduced in [v6.17.0](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md#6170-october-16-2025) ([#44861](https://github.com/hashicorp/terraform-provider-aws/issues/44861)) @@ -29,6 +141,17 @@ BUG FIXES: * resource/aws_glue_job: Allow a zero (`0`) value for `timeout` for Apache Spark streaming ETL jobs. This allows the job to be configured with no timeout ([#44920](https://github.com/hashicorp/terraform-provider-aws/issues/44920)) * resource/aws_lakeformation_lf_tags: Remove incorrect validation from `catalog_id`, `database.catalog_id`, `table.catalog_id`, and `table_with_columns.catalog_id` arguments ([#44890](https://github.com/hashicorp/terraform-provider-aws/issues/44890)) * resource/aws_launch_template: Allow an empty (`""`) value for `block_device_mappings.ebs.kms_key_id`. This fixes a regression introduced in [v6.16.0](https://github.com/hashicorp/terraform-provider-aws/blob/main/CHANGELOG.md#6160-october-9-2025) ([#44708](https://github.com/hashicorp/terraform-provider-aws/issues/44708)) +* resource/aws_redshift_cluster: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_cluster_snapshot: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_event_subscription: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_hsm_client_certificate: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_hsm_configuration: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_integration: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_parameter_group: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_snapshot_copy_grant: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_snapshot_schedule: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_subnet_group: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) +* resource/aws_redshift_usage_limit: Prevents errors with empty tag values. ([#44952](https://github.com/hashicorp/terraform-provider-aws/issues/44952)) ## 6.19.0 (October 30, 2025) diff --git a/docs/acc-test-environment-variables.md b/docs/acc-test-environment-variables.md index 11447361df9b..093f27dbb070 100644 --- a/docs/acc-test-environment-variables.md +++ b/docs/acc-test-environment-variables.md @@ -46,6 +46,10 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `AWS_API_GATEWAY_DOMAIN_NAME_REGIONAL_CERTIFICATE_NAME_ENABLED` | Flag to enable API Gateway Domain Name regional certificate upload testing. | | `AWS_BEDROCK_AGENTCORE_RUNTIME_IMAGE_V1_URI` | ECR repository image URI (tagged as `v1`) for Bedrock AgentCore Agent Runtime acceptance tests. | | `AWS_BEDROCK_AGENTCORE_RUNTIME_IMAGE_V2_URI` | ECR repository image URI (tagged as `v2`) for Bedrock AgentCore Agent Runtime acceptance | +| `AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V1_S3_BUCKET` | S3 bucket that contains the object holding the ZIP file of the agent runtime source code (version `v1`) for Bedrock AgentCore Agent Runtime code acceptance tests. | +| `AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V1_S3_KEY` | S3 key of the object that contains the ZIP file of the agent runtime source code (version `v1`) for Bedrock AgentCore Agent Runtime acceptance tests. | +| `AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V2_S3_BUCKET` | S3 bucket that contains the object holding the ZIP file of the agent runtime source code (version `v2`) for Bedrock AgentCore Agent Runtime code acceptance tests. | +| `AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V2_S3_KEY` | S3 key of the object that contains the ZIP file of the agent runtime source code (version `v2`) for Bedrock AgentCore Agent Runtime acceptance tests. | | `AWS_CODEBUILD_BITBUCKET_SOURCE_LOCATION` | BitBucket source URL for CodeBuild testing. CodeBuild must have access to this repository via OAuth or Source Credentials. Defaults to `https://terraform@bitbucket.org/terraform/aws-test.git`. | | `AWS_CODEBUILD_GITHUB_SOURCE_LOCATION` | GitHub source URL for CodeBuild testing. CodeBuild must have access to this repository via OAuth or Source Credentials. Defaults to `https://github.com/hashibot-test/aws-test.git`. | | `AWS_DEFAULT_REGION` | Primary AWS region for tests. Defaults to `us-west-2`. | diff --git a/go.mod b/go.mod index 199f985cf798..47fd7521dbcc 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/terraform-provider-aws -go 1.24.8 +go 1.24.10 // Disable post-quantum X25519MLKEM768 key exchange mechanism // This causes errors with AWS Network Firewall @@ -9,273 +9,273 @@ godebug tlsmlkem=0 require ( github.com/ProtonMail/go-crypto v1.3.0 github.com/YakDriver/go-version v0.1.0 - github.com/YakDriver/regexache v0.24.0 - github.com/YakDriver/smarterr v0.7.0 + github.com/YakDriver/regexache v0.25.0 + github.com/YakDriver/smarterr v0.8.0 github.com/aws/aws-sdk-go-v2 v1.39.6 - github.com/aws/aws-sdk-go-v2/config v1.31.17 - github.com/aws/aws-sdk-go-v2/credentials v1.18.21 + github.com/aws/aws-sdk-go-v2/config v1.31.21 + github.com/aws/aws-sdk-go-v2/credentials v1.18.25 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 - github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.44.10 - github.com/aws/aws-sdk-go-v2/service/account v1.29.2 - github.com/aws/aws-sdk-go-v2/service/acm v1.37.11 - github.com/aws/aws-sdk-go-v2/service/acmpca v1.45.3 - github.com/aws/aws-sdk-go-v2/service/amp v1.41.1 - github.com/aws/aws-sdk-go-v2/service/amplify v1.38.3 - github.com/aws/aws-sdk-go-v2/service/apigateway v1.36.1 - github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.32.11 - github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.1 - github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.10 - github.com/aws/aws-sdk-go-v2/service/appflow v1.51.1 - github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.10 - github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.2 - github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.9 - github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.2 - github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.1 - github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.3 - github.com/aws/aws-sdk-go-v2/service/appstream v1.50.4 - github.com/aws/aws-sdk-go-v2/service/appsync v1.52.1 - github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.12 - github.com/aws/aws-sdk-go-v2/service/athena v1.55.10 - github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.1 - github.com/aws/aws-sdk-go-v2/service/autoscaling v1.60.3 - github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.3 - github.com/aws/aws-sdk-go-v2/service/backup v1.49.4 - github.com/aws/aws-sdk-go-v2/service/batch v1.58.4 - github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.3 - github.com/aws/aws-sdk-go-v2/service/bedrock v1.48.4 - github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.1 - github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.1 - github.com/aws/aws-sdk-go-v2/service/billing v1.8.4 - github.com/aws/aws-sdk-go-v2/service/budgets v1.41.1 - github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.10 - github.com/aws/aws-sdk-go-v2/service/chime v1.41.1 - github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.10 - github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.2 - github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.1 - github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.9 - github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.1 - github.com/aws/aws-sdk-go-v2/service/cloudformation v1.68.3 - github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.4 - github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.12 - github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.9 - github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.1 - github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.53.11 - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.1 - github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.7 - github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.10 - github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.2 - github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.1 - github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.1 - github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.9 - github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.1 - github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.9 - github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.9 - github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.10 - github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.2 - github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.10 - github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.10 - github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.11 - github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.10 - github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.1 - github.com/aws/aws-sdk-go-v2/service/configservice v1.59.2 - github.com/aws/aws-sdk-go-v2/service/connect v1.143.3 - github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.1 - github.com/aws/aws-sdk-go-v2/service/controltower v1.26.10 - github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.2 - github.com/aws/aws-sdk-go-v2/service/costexplorer v1.59.2 - github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.20.10 - github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.3 - github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.58.2 - github.com/aws/aws-sdk-go-v2/service/databrew v1.39.3 - github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.3 - github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.9 - github.com/aws/aws-sdk-go-v2/service/datasync v1.55.4 - github.com/aws/aws-sdk-go-v2/service/datazone v1.44.2 - github.com/aws/aws-sdk-go-v2/service/dax v1.29.5 - github.com/aws/aws-sdk-go-v2/service/detective v1.38.2 - github.com/aws/aws-sdk-go-v2/service/devicefarm v1.36.3 - github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.1 - github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.3 - github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.4 - github.com/aws/aws-sdk-go-v2/service/dlm v1.35.4 - github.com/aws/aws-sdk-go-v2/service/docdb v1.48.1 - github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.2 - github.com/aws/aws-sdk-go-v2/service/drs v1.36.2 - github.com/aws/aws-sdk-go-v2/service/dsql v1.10.2 - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.52.4 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.261.1 - github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2 - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2 - github.com/aws/aws-sdk-go-v2/service/ecs v1.67.2 - github.com/aws/aws-sdk-go-v2/service/efs v1.41.2 - github.com/aws/aws-sdk-go-v2/service/eks v1.74.7 - github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.1 - github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.11 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.11 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.51.5 - github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.11 - github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.10 - github.com/aws/aws-sdk-go-v2/service/emr v1.55.4 - github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.6 - github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.1 - github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.10 - github.com/aws/aws-sdk-go-v2/service/evidently v1.28.9 - github.com/aws/aws-sdk-go-v2/service/evs v1.5.6 - github.com/aws/aws-sdk-go-v2/service/finspace v1.33.10 - github.com/aws/aws-sdk-go-v2/service/firehose v1.42.1 - github.com/aws/aws-sdk-go-v2/service/fis v1.37.9 - github.com/aws/aws-sdk-go-v2/service/fms v1.44.10 - github.com/aws/aws-sdk-go-v2/service/fsx v1.62.4 - github.com/aws/aws-sdk-go-v2/service/gamelift v1.47.3 - github.com/aws/aws-sdk-go-v2/service/glacier v1.31.10 - github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.3 - github.com/aws/aws-sdk-go-v2/service/glue v1.132.1 - github.com/aws/aws-sdk-go-v2/service/grafana v1.32.3 - github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.10 - github.com/aws/aws-sdk-go-v2/service/groundstation v1.38.2 - github.com/aws/aws-sdk-go-v2/service/guardduty v1.65.4 - github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.2 - github.com/aws/aws-sdk-go-v2/service/iam v1.49.2 - github.com/aws/aws-sdk-go-v2/service/identitystore v1.33.3 - github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.48.4 - github.com/aws/aws-sdk-go-v2/service/inspector v1.30.9 - github.com/aws/aws-sdk-go-v2/service/inspector2 v1.44.10 - github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.2 - github.com/aws/aws-sdk-go-v2/service/invoicing v1.6.12 - github.com/aws/aws-sdk-go-v2/service/iot v1.69.9 - github.com/aws/aws-sdk-go-v2/service/ivs v1.48.3 - github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.9 - github.com/aws/aws-sdk-go-v2/service/kafka v1.44.3 - github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.10 - github.com/aws/aws-sdk-go-v2/service/kendra v1.60.10 - github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.3 - github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.1 - github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.10 - github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.11 - github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.9 - github.com/aws/aws-sdk-go-v2/service/kms v1.47.1 - github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.9 - github.com/aws/aws-sdk-go-v2/service/lambda v1.81.1 - github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.10 - github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.3 - github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.56.10 - github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.10 - github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.4 - github.com/aws/aws-sdk-go-v2/service/location v1.50.2 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.8 + github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.45.2 + github.com/aws/aws-sdk-go-v2/service/account v1.29.4 + github.com/aws/aws-sdk-go-v2/service/acm v1.37.13 + github.com/aws/aws-sdk-go-v2/service/acmpca v1.46.2 + github.com/aws/aws-sdk-go-v2/service/amp v1.42.0 + github.com/aws/aws-sdk-go-v2/service/amplify v1.38.5 + github.com/aws/aws-sdk-go-v2/service/apigateway v1.37.0 + github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.0 + github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.3 + github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.12 + github.com/aws/aws-sdk-go-v2/service/appflow v1.51.3 + github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.12 + github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.4 + github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.11 + github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.4 + github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.3 + github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.5 + github.com/aws/aws-sdk-go-v2/service/appstream v1.52.1 + github.com/aws/aws-sdk-go-v2/service/appsync v1.52.3 + github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.14 + github.com/aws/aws-sdk-go-v2/service/athena v1.55.12 + github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.3 + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.61.0 + github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.5 + github.com/aws/aws-sdk-go-v2/service/backup v1.54.0 + github.com/aws/aws-sdk-go-v2/service/batch v1.58.6 + github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.5 + github.com/aws/aws-sdk-go-v2/service/bedrock v1.49.1 + github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.3 + github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.3 + github.com/aws/aws-sdk-go-v2/service/billing v1.9.0 + github.com/aws/aws-sdk-go-v2/service/budgets v1.41.3 + github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.12 + github.com/aws/aws-sdk-go-v2/service/chime v1.41.3 + github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.12 + github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.4 + github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.3 + github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.11 + github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.3 + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.70.0 + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.56.2 + github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.14 + github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.11 + github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.3 + github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.54.0 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.3 + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.60.0 + github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.12 + github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.4 + github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.3 + github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.3 + github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.11 + github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.3 + github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.11 + github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.11 + github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.12 + github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.4 + github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.12 + github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.12 + github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.13 + github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.12 + github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.3 + github.com/aws/aws-sdk-go-v2/service/configservice v1.59.4 + github.com/aws/aws-sdk-go-v2/service/connect v1.146.0 + github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.3 + github.com/aws/aws-sdk-go-v2/service/controltower v1.27.2 + github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.4 + github.com/aws/aws-sdk-go-v2/service/costexplorer v1.60.0 + github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.21.0 + github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.5 + github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.60.0 + github.com/aws/aws-sdk-go-v2/service/databrew v1.39.5 + github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.5 + github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.11 + github.com/aws/aws-sdk-go-v2/service/datasync v1.55.6 + github.com/aws/aws-sdk-go-v2/service/datazone v1.48.0 + github.com/aws/aws-sdk-go-v2/service/dax v1.29.7 + github.com/aws/aws-sdk-go-v2/service/detective v1.38.4 + github.com/aws/aws-sdk-go-v2/service/devicefarm v1.37.0 + github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.3 + github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.5 + github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.6 + github.com/aws/aws-sdk-go-v2/service/dlm v1.35.6 + github.com/aws/aws-sdk-go-v2/service/docdb v1.48.3 + github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.4 + github.com/aws/aws-sdk-go-v2/service/drs v1.36.4 + github.com/aws/aws-sdk-go-v2/service/dsql v1.11.2 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.0 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.272.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.53.0 + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.4 + github.com/aws/aws-sdk-go-v2/service/ecs v1.68.0 + github.com/aws/aws-sdk-go-v2/service/efs v1.41.4 + github.com/aws/aws-sdk-go-v2/service/eks v1.74.9 + github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.3 + github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.13 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.13 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.53.0 + github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.13 + github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.12 + github.com/aws/aws-sdk-go-v2/service/emr v1.56.0 + github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.8 + github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.3 + github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.12 + github.com/aws/aws-sdk-go-v2/service/evidently v1.28.11 + github.com/aws/aws-sdk-go-v2/service/evs v1.5.8 + github.com/aws/aws-sdk-go-v2/service/finspace v1.33.12 + github.com/aws/aws-sdk-go-v2/service/firehose v1.42.3 + github.com/aws/aws-sdk-go-v2/service/fis v1.37.11 + github.com/aws/aws-sdk-go-v2/service/fms v1.44.12 + github.com/aws/aws-sdk-go-v2/service/fsx v1.64.0 + github.com/aws/aws-sdk-go-v2/service/gamelift v1.48.2 + github.com/aws/aws-sdk-go-v2/service/glacier v1.31.12 + github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.5 + github.com/aws/aws-sdk-go-v2/service/glue v1.133.0 + github.com/aws/aws-sdk-go-v2/service/grafana v1.32.5 + github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.12 + github.com/aws/aws-sdk-go-v2/service/groundstation v1.39.2 + github.com/aws/aws-sdk-go-v2/service/guardduty v1.68.0 + github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.4 + github.com/aws/aws-sdk-go-v2/service/iam v1.52.0 + github.com/aws/aws-sdk-go-v2/service/identitystore v1.34.2 + github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.49.0 + github.com/aws/aws-sdk-go-v2/service/inspector v1.30.11 + github.com/aws/aws-sdk-go-v2/service/inspector2 v1.45.0 + github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.4 + github.com/aws/aws-sdk-go-v2/service/invoicing v1.8.0 + github.com/aws/aws-sdk-go-v2/service/iot v1.69.11 + github.com/aws/aws-sdk-go-v2/service/ivs v1.48.5 + github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.11 + github.com/aws/aws-sdk-go-v2/service/kafka v1.46.0 + github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.12 + github.com/aws/aws-sdk-go-v2/service/kendra v1.60.12 + github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.5 + github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.3 + github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.12 + github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.13 + github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.11 + github.com/aws/aws-sdk-go-v2/service/kms v1.48.2 + github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.11 + github.com/aws/aws-sdk-go-v2/service/lambda v1.82.0 + github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.12 + github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.5 + github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.57.0 + github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.12 + github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.6 + github.com/aws/aws-sdk-go-v2/service/location v1.50.4 github.com/aws/aws-sdk-go-v2/service/lookoutmetrics v1.37.2 - github.com/aws/aws-sdk-go-v2/service/m2 v1.26.3 - github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.2 - github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.45.4 - github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.84.1 - github.com/aws/aws-sdk-go-v2/service/medialive v1.85.3 - github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.10 - github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.32.3 - github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.10 - github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.10 - github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.3 - github.com/aws/aws-sdk-go-v2/service/mgn v1.38.2 - github.com/aws/aws-sdk-go-v2/service/mq v1.34.8 - github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.10 - github.com/aws/aws-sdk-go-v2/service/neptune v1.43.1 - github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.9 - github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.57.5 - github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.10.3 - github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.3 - github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.2 - github.com/aws/aws-sdk-go-v2/service/notifications v1.7.8 - github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.12 - github.com/aws/aws-sdk-go-v2/service/oam v1.23.3 - github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.4 - github.com/aws/aws-sdk-go-v2/service/odb v1.5.4 - github.com/aws/aws-sdk-go-v2/service/opensearch v1.52.10 - github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.2 - github.com/aws/aws-sdk-go-v2/service/organizations v1.46.2 - github.com/aws/aws-sdk-go-v2/service/osis v1.21.3 - github.com/aws/aws-sdk-go-v2/service/outposts v1.57.4 - github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.1 - github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.10 - github.com/aws/aws-sdk-go-v2/service/pcs v1.14.4 - github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.10 - github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.0 - github.com/aws/aws-sdk-go-v2/service/pipes v1.23.9 - github.com/aws/aws-sdk-go-v2/service/polly v1.54.3 - github.com/aws/aws-sdk-go-v2/service/pricing v1.40.3 - github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.10 + github.com/aws/aws-sdk-go-v2/service/m2 v1.26.5 + github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.4 + github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.46.0 + github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.85.0 + github.com/aws/aws-sdk-go-v2/service/medialive v1.87.0 + github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.12 + github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.33.0 + github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.12 + github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.12 + github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.5 + github.com/aws/aws-sdk-go-v2/service/mgn v1.38.4 + github.com/aws/aws-sdk-go-v2/service/mq v1.34.10 + github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.12 + github.com/aws/aws-sdk-go-v2/service/neptune v1.43.3 + github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.11 + github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.58.0 + github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.11.0 + github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.5 + github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.4 + github.com/aws/aws-sdk-go-v2/service/notifications v1.7.10 + github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.14 + github.com/aws/aws-sdk-go-v2/service/oam v1.23.5 + github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.6 + github.com/aws/aws-sdk-go-v2/service/odb v1.5.6 + github.com/aws/aws-sdk-go-v2/service/opensearch v1.54.0 + github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.4 + github.com/aws/aws-sdk-go-v2/service/organizations v1.46.4 + github.com/aws/aws-sdk-go-v2/service/osis v1.21.5 + github.com/aws/aws-sdk-go-v2/service/outposts v1.57.6 + github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.3 + github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.12 + github.com/aws/aws-sdk-go-v2/service/pcs v1.15.0 + github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.12 + github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.2 + github.com/aws/aws-sdk-go-v2/service/pipes v1.23.11 + github.com/aws/aws-sdk-go-v2/service/polly v1.54.5 + github.com/aws/aws-sdk-go-v2/service/pricing v1.40.5 + github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.12 github.com/aws/aws-sdk-go-v2/service/qldb v1.32.2 - github.com/aws/aws-sdk-go-v2/service/quicksight v1.95.4 - github.com/aws/aws-sdk-go-v2/service/ram v1.34.11 - github.com/aws/aws-sdk-go-v2/service/rbin v1.26.11 - github.com/aws/aws-sdk-go-v2/service/rds v1.108.7 - github.com/aws/aws-sdk-go-v2/service/redshift v1.59.5 - github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.10 - github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.13 - github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.9 - github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.2 - github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.4 - github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.12 - github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.30.11 - github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.10 - github.com/aws/aws-sdk-go-v2/service/route53 v1.59.3 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.8 - github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.10 - github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.3 - github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.10 - github.com/aws/aws-sdk-go-v2/service/route53resolver v1.40.10 - github.com/aws/aws-sdk-go-v2/service/rum v1.29.2 - github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2 - github.com/aws/aws-sdk-go-v2/service/s3control v1.66.7 - github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.1 - github.com/aws/aws-sdk-go-v2/service/s3tables v1.10.9 - github.com/aws/aws-sdk-go-v2/service/s3vectors v1.4.12 - github.com/aws/aws-sdk-go-v2/service/sagemaker v1.219.1 - github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.9 - github.com/aws/aws-sdk-go-v2/service/schemas v1.34.1 - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.11 - github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.2 - github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.2 - github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.1 - github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.1 - github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.10 - github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.14 - github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.5 - github.com/aws/aws-sdk-go-v2/service/ses v1.34.9 - github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.2 - github.com/aws/aws-sdk-go-v2/service/sfn v1.39.11 - github.com/aws/aws-sdk-go-v2/service/shield v1.34.10 - github.com/aws/aws-sdk-go-v2/service/signer v1.31.10 - github.com/aws/aws-sdk-go-v2/service/sns v1.39.3 - github.com/aws/aws-sdk-go-v2/service/sqs v1.42.13 - github.com/aws/aws-sdk-go-v2/service/ssm v1.66.4 - github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.3 - github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.9 - github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.10 - github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.9 - github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 - github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.6 - github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.2 - github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 - github.com/aws/aws-sdk-go-v2/service/swf v1.33.4 - github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.2 - github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.10 - github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.4 - github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.3 - github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.9 - github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.4 - github.com/aws/aws-sdk-go-v2/service/transfer v1.67.4 - github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.29.9 - github.com/aws/aws-sdk-go-v2/service/vpclattice v1.19.4 - github.com/aws/aws-sdk-go-v2/service/waf v1.30.9 - github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.10 - github.com/aws/aws-sdk-go-v2/service/wafv2 v1.68.4 - github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.10 - github.com/aws/aws-sdk-go-v2/service/workmail v1.36.8 - github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.2 - github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.33.3 - github.com/aws/aws-sdk-go-v2/service/xray v1.36.9 + github.com/aws/aws-sdk-go-v2/service/quicksight v1.96.2 + github.com/aws/aws-sdk-go-v2/service/ram v1.34.13 + github.com/aws/aws-sdk-go-v2/service/rbin v1.26.13 + github.com/aws/aws-sdk-go-v2/service/rds v1.109.0 + github.com/aws/aws-sdk-go-v2/service/redshift v1.60.0 + github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.12 + github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.15 + github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.11 + github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.4 + github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.6 + github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.14 + github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.0 + github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.12 + github.com/aws/aws-sdk-go-v2/service/route53 v1.60.0 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.10 + github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.12 + github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.5 + github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.12 + github.com/aws/aws-sdk-go-v2/service/route53resolver v1.41.0 + github.com/aws/aws-sdk-go-v2/service/rum v1.30.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.91.0 + github.com/aws/aws-sdk-go-v2/service/s3control v1.66.9 + github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.3 + github.com/aws/aws-sdk-go-v2/service/s3tables v1.12.0 + github.com/aws/aws-sdk-go-v2/service/s3vectors v1.5.2 + github.com/aws/aws-sdk-go-v2/service/sagemaker v1.224.0 + github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.12 + github.com/aws/aws-sdk-go-v2/service/schemas v1.34.3 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.0 + github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.4 + github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.4 + github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.3 + github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.3 + github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.12 + github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.16 + github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.7 + github.com/aws/aws-sdk-go-v2/service/ses v1.34.11 + github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.4 + github.com/aws/aws-sdk-go-v2/service/sfn v1.40.0 + github.com/aws/aws-sdk-go-v2/service/shield v1.34.12 + github.com/aws/aws-sdk-go-v2/service/signer v1.31.12 + github.com/aws/aws-sdk-go-v2/service/sns v1.39.5 + github.com/aws/aws-sdk-go-v2/service/sqs v1.42.15 + github.com/aws/aws-sdk-go-v2/service/ssm v1.67.2 + github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.5 + github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.11 + github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.12 + github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.11 + github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 + github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.8 + github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.4 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.0 + github.com/aws/aws-sdk-go-v2/service/swf v1.33.6 + github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.4 + github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.12 + github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.6 + github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.5 + github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.11 + github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.6 + github.com/aws/aws-sdk-go-v2/service/transfer v1.67.6 + github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.30.2 + github.com/aws/aws-sdk-go-v2/service/vpclattice v1.20.2 + github.com/aws/aws-sdk-go-v2/service/waf v1.30.11 + github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.12 + github.com/aws/aws-sdk-go-v2/service/wafv2 v1.70.0 + github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.12 + github.com/aws/aws-sdk-go-v2/service/workmail v1.36.10 + github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.4 + github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.34.0 + github.com/aws/aws-sdk-go-v2/service/xray v1.36.11 github.com/aws/smithy-go v1.23.2 github.com/beevik/etree v1.6.0 - github.com/cedar-policy/cedar-go v1.2.9 + github.com/cedar-policy/cedar-go v1.3.0 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/dlclark/regexp2 v1.11.5 github.com/gertd/go-pluralize v0.2.1 @@ -289,6 +289,7 @@ require ( github.com/hashicorp/go-cty v1.5.0 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-multierror v1.1.1 + github.com/hashicorp/go-set/v3 v3.0.1 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/hcl/v2 v2.24.0 @@ -303,7 +304,7 @@ require ( github.com/hashicorp/terraform-plugin-mux v0.21.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 github.com/hashicorp/terraform-plugin-testing v1.14.0-beta.1.0.20251013071646-7ed2ee242705 - github.com/jaswdr/faker/v2 v2.8.1 + github.com/jaswdr/faker/v2 v2.9.0 github.com/jmespath/go-jmespath v0.4.0 github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 github.com/mitchellh/copystructure v1.2.0 @@ -314,9 +315,9 @@ require ( github.com/shopspring/decimal v1.4.0 go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws v0.63.0 go.opentelemetry.io/otel v1.38.0 - golang.org/x/crypto v0.43.0 - golang.org/x/text v0.30.0 - golang.org/x/tools v0.38.0 + golang.org/x/crypto v0.44.0 + golang.org/x/text v0.31.0 + golang.org/x/tools v0.39.0 gopkg.in/dnaeon/go-vcr.v4 v4.0.5 ) @@ -337,7 +338,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cloudflare/circl v1.6.1 // indirect @@ -377,10 +378,10 @@ require ( go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect golang.org/x/exp v0.0.0-20220921023135-46d9e7742f1e // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.46.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/grpc v1.75.1 // indirect diff --git a/go.sum b/go.sum index dc8777b1cb7f..62dada21806f 100644 --- a/go.sum +++ b/go.sum @@ -12,10 +12,10 @@ github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBi github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/YakDriver/go-version v0.1.0 h1:/x+Xg2+l89Mjtxl0VRf2+ue8cnHkw6jfYv49j6f7gZw= github.com/YakDriver/go-version v0.1.0/go.mod h1:LXwFAp1E3KBhS7FHO/FE8r3XCmvKizs/VXXXFWfoSYY= -github.com/YakDriver/regexache v0.24.0 h1:zUKaixelkswzdqsqPc2sveiV//Mi/msJn0teG8zBDiA= -github.com/YakDriver/regexache v0.24.0/go.mod h1:awcd8uBj614F3ScW06JqlfSGqq2/7vdJHy+RiKzVC+g= -github.com/YakDriver/smarterr v0.7.0 h1:LHL/ke6J4NdjsiHASLzn3V1Bt4Ra+t8t+c22WBiOiQo= -github.com/YakDriver/smarterr v0.7.0/go.mod h1:tF8iZvoX2SHQIEk5Ttj+jnLe3jb2JGQ4ag8JkuYZE7Y= +github.com/YakDriver/regexache v0.25.0 h1:uggvmj09EhXQgaXYmdGsKuDARbmdOIqICiO+PIwhlTA= +github.com/YakDriver/regexache v0.25.0/go.mod h1:4xOFrfggN3UAGlhcvNpM/kuedpJL+48DrUs0CcCxPv8= +github.com/YakDriver/smarterr v0.8.0 h1:U4GZytxw/js/2hzoyg94S341sC8PuD0CV5dEBRurZPs= +github.com/YakDriver/smarterr v0.8.0/go.mod h1:tF8iZvoX2SHQIEk5Ttj+jnLe3jb2JGQ4ag8JkuYZE7Y= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= @@ -27,14 +27,14 @@ github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+X github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y= -github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y= -github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c= -github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA= -github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA= +github.com/aws/aws-sdk-go-v2/config v1.31.21 h1:gH/y+NphLGIVuNHXNkTQir3PmL44Efe8OpPAsbDms0o= +github.com/aws/aws-sdk-go-v2/config v1.31.21/go.mod h1:P6I8guuLej6F2++fKUlo9OIhI59LuEsyEZZMMmgqh/4= +github.com/aws/aws-sdk-go-v2/credentials v1.18.25 h1:MvtSN3ECsQbgEHcux1pZQhuMjZnShlsqcS0Pqlan4Vw= +github.com/aws/aws-sdk-go-v2/credentials v1.18.25/go.mod h1:YATyDPzlHucr1cxEE9rsZl7ZG3gQsxpjD6o5of/8qXE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 h1:4GNV1lhyELGjMz5ILMRxDvxvOaeo3Ux9Z69S1EgVMMQ= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3/go.mod h1:br7KA6edAAqDGUYJ+zVVPAyMrPhnN+zdt17yTUT6FPw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.8 h1:R1Ws+p6Gyk0mdVvMI8zruUFnqaFouKKKDOdadtKbHbI= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.8/go.mod h1:VPrEBa+zT9J2x+HHdeq5SwTMd7tbhcBQH3sYPiKORfY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY= @@ -43,256 +43,256 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEG github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k= -github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.44.10 h1:e9IzNA2eWkeSsVWP+PqSPIit+YUyd7dE0FNmWcbDWSg= -github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.44.10/go.mod h1:iATSoxt/SEINLDvYHe5N9/UDnc45vngRxRJYr2MqGO0= -github.com/aws/aws-sdk-go-v2/service/account v1.29.2 h1:u+Sq9gnWQmTug7OOnr/kGR4g0V7RAIn/YAX66vYPjp0= -github.com/aws/aws-sdk-go-v2/service/account v1.29.2/go.mod h1:3LbGl+sLnaiyCVp2LJXj0gEoeV2Uw0QOsDpP1gDMBVA= -github.com/aws/aws-sdk-go-v2/service/acm v1.37.11 h1:oQgvxk0+83+EVZYsea3QysBDcrXffPG4UcnBfI2XD7M= -github.com/aws/aws-sdk-go-v2/service/acm v1.37.11/go.mod h1:v8E4cAu0qIxpS7IokQilQb60A8IODPxo82VxVtJ+Dgo= -github.com/aws/aws-sdk-go-v2/service/acmpca v1.45.3 h1:+9/8gDU+vK4MDNYL4bDYEkqdoKqAthD7GifEroL2GtU= -github.com/aws/aws-sdk-go-v2/service/acmpca v1.45.3/go.mod h1:rpBWGq3UUlrgtAwNMy+I9ZoGgbiCoy30QetJZtI6+1A= -github.com/aws/aws-sdk-go-v2/service/amp v1.41.1 h1:Mkao9rWXSWKXnPswpRQrOQl9LlW+zLQcelJkSMPv0jI= -github.com/aws/aws-sdk-go-v2/service/amp v1.41.1/go.mod h1:uwNPmGivmh+4kJecS8OuYtMQTeZCGoBxdLLAGv+13r0= -github.com/aws/aws-sdk-go-v2/service/amplify v1.38.3 h1:gzDbuRQ+3TgZDtqU6YkdumaGIco5X/v0SEST4FNe2hU= -github.com/aws/aws-sdk-go-v2/service/amplify v1.38.3/go.mod h1:ieZIB8x+q5G3azy9SUtyGzGxXGHCVsTK4YvnADiCBZQ= -github.com/aws/aws-sdk-go-v2/service/apigateway v1.36.1 h1:IdikGPwXSRpybGY5QFf3VBJe7qjojVGwEhs6T1U7YCI= -github.com/aws/aws-sdk-go-v2/service/apigateway v1.36.1/go.mod h1:9tT261wkl3uME2BWp/a3nzGNe9BM7jLWZdrXW1eX3BA= -github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.32.11 h1:FGTcpVtiTMti0vWIptgncvP4gCDKfj7MIfdlbq0UCxQ= -github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.32.11/go.mod h1:vr6hE/YGoQQa8PPwsB1uKt9wHjNZZcbXN+ww6lBXVhY= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.1 h1:gSrJ9yZe7oRHSGWKn+68//iQ1DS/RhNVqGcAVhC6VH8= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.1/go.mod h1:rvGHrN6a1lCypZrV0gDsJNPP5w51XIzr6manLptGnZg= -github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.10 h1:8BzTiju+0ULXjDwnLgC+aVG1ka7s7vyvnZLFjoSQ0FM= -github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.10/go.mod h1:EFrW9OOrllIDc/Rg/aUpaWnK81C2VVxhtFt9XUmM4kQ= -github.com/aws/aws-sdk-go-v2/service/appflow v1.51.1 h1:xsMtmgeovHNBxoIsPy9FHWNbYz+6OitWpn/iocBu5gc= -github.com/aws/aws-sdk-go-v2/service/appflow v1.51.1/go.mod h1:bjux2H0bZSqK50RnMXHMr1eBi6Uw6gJmTeDOvFk7w14= -github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.10 h1:kI2+k9m0GMNAjKLpmnvyEDjglzVFayw/cJOEBA1ptKc= -github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.10/go.mod h1:FrNhRSko1IPmuXPB8ldLs3nRkjjONG3E7ZE5nnV0snE= -github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.2 h1:zZ6TJ93crR09QVPxqoFJnlioltKejaPLxY1dCcBjU20= -github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.2/go.mod h1:BDzrZs53Hsb5MyAICN2dmtFWaeLONzMaseXyF9Bagt0= -github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.9 h1:siRXiihD1QrredolQOogo3LIUT2IxG7VGaf96MS1XjQ= -github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.9/go.mod h1:2Sln2mubGkQTNc86N2eobz6KhGrHatsr4lVoIkUwrhQ= -github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.2 h1:YYAuZMyQyL7AgqqIltetNMMFrk3eITn9tk7wOzopPYI= -github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.2/go.mod h1:5Il7eB5oblkNf9V8ugOpPwA6ZARgTzld7otDTumO2w4= -github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.1 h1:jh5RzCpaQUpcUkxM+SYgacL+idKvMXYQTHmcQDYwZGg= -github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.1/go.mod h1:xcEbbUjLqajeslIydrSJhESXNlGMtfXmu7MLY6ONlzY= -github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.3 h1:MY0ipQXQ3c++MZtnY7pF1uHu2vByFEoCUun/5zIjPmk= -github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.3/go.mod h1:rI1byQGgb9tUXBvo3uLFrRXRzaCJayw+CiqAnDgYSKw= -github.com/aws/aws-sdk-go-v2/service/appstream v1.50.4 h1:cq3Q4bOTAgzMjfj8iWP0A4/abnykkXbuK0yk8US254I= -github.com/aws/aws-sdk-go-v2/service/appstream v1.50.4/go.mod h1:flCm0TnAjuMbHs8YaGjVjQjUUsa5EP5O6nC4Zpt080E= -github.com/aws/aws-sdk-go-v2/service/appsync v1.52.1 h1:Vj314J7fmfo5XY1dI19d/4qo4r8cpyf565b7hFLYUBU= -github.com/aws/aws-sdk-go-v2/service/appsync v1.52.1/go.mod h1:uCcHMGXa27Gp8b/hlAI0JbqmXeZp16E2FDWNz5nX0cQ= -github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.12 h1:dVoHETeQsZucFnY+jaTctpzLZsLc9wHolJNCEQRCaJw= -github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.12/go.mod h1:PyPhpvZGkGYZTeuYRlPwZTgBx93EUYtHdpPbiIlY7Q8= -github.com/aws/aws-sdk-go-v2/service/athena v1.55.10 h1:lhHg2H2XeRix8Zk2UKxsJXKk93066CAZCw0x5pMRvDw= -github.com/aws/aws-sdk-go-v2/service/athena v1.55.10/go.mod h1:1bY3ff3w7nTDnyGgOAOEZpO7e7bUiG2iDM2tXbCzxjg= -github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.1 h1:wF8gPnNk6r2PHV7lX/Bc0PLksQ7ehy8xnECyBhxsoBo= -github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.1/go.mod h1:6U6XFWocDXxVtEZsjDajhNtAxNJzZRs9k7CJHuTMJCY= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.60.3 h1:63i7taIpNPPncOc1tXoArX6KkFFXiHNZugaPuFPrbMw= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.60.3/go.mod h1:6E1AiecbY52kVBl8lKkdaO759rbGK3TBBBNnfxJezTM= -github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.3 h1:Pubm5Z15HT7TxjIlCe0Wi1yez4GC2TVD8IkfHHdoA0M= -github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.3/go.mod h1:NkStIqURmzgUVyoB3YkmU1HUtIPECrExIastd5QbXIk= -github.com/aws/aws-sdk-go-v2/service/backup v1.49.4 h1:v30l5443w7l8CGmKNeoeIZE1dBvO5psDUuoC6RqGElM= -github.com/aws/aws-sdk-go-v2/service/backup v1.49.4/go.mod h1:Sqiqu5Ws64P9IYY+0mQ4OafDKK1LK6sRWQqw89dZZYA= -github.com/aws/aws-sdk-go-v2/service/batch v1.58.4 h1:teElXpUfGCUfrGmHzA+BDmfq/bjD2c1MDG/Uq4P0dEQ= -github.com/aws/aws-sdk-go-v2/service/batch v1.58.4/go.mod h1:zaUBHLEVy5UjLlFt996XZMXLza3teA7f0IhAoV7+3mg= -github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.3 h1:7GGp+4HcHUEhJMc+Io7vUEQFIKvuYwcH0Y2nk3YQN/w= -github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.3/go.mod h1:PJ5iWye10CA9cYAeVL4RUSkZvAwVK/WrOnTSHLztNAI= -github.com/aws/aws-sdk-go-v2/service/bedrock v1.48.4 h1:ZxjMilNfgm+do1eXsU13DE34OIS/IRFudJrZBkKzNdo= -github.com/aws/aws-sdk-go-v2/service/bedrock v1.48.4/go.mod h1:xJ84P+JCcEkzkMjqBKmImWl/zlwEwBmbjc9QR+tcACQ= -github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.1 h1:qgWo/BbdHN80+PUEWxv3D+ppvEfkx5gqSiKKnGriodM= -github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.1/go.mod h1:R5jkUdemrZt6+90gq4JFyxHKldEMH88F6wdxquDLa4Q= -github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.1 h1:g/lzCCkLOkmcJLsAC/a6jvQ+26rKB5e5nj/TGJRbHag= -github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.1/go.mod h1:MvhjtEWL5RO1w6AMrt4d9k//kZxZUsLrTSipRM9Q0/8= -github.com/aws/aws-sdk-go-v2/service/billing v1.8.4 h1:Y/f33Wdef0k3l+tTrKigBAGSGS8w7U10MQHxTQ6d7jM= -github.com/aws/aws-sdk-go-v2/service/billing v1.8.4/go.mod h1:7WI9oHeKA76HgGtTaUeKToGO/rRH9/fx7WLCw1QLJt4= -github.com/aws/aws-sdk-go-v2/service/budgets v1.41.1 h1:Xvc3wK1+jcLmXWLeKbluJJvtQA/Ql8Bt5VzdjcEVAM0= -github.com/aws/aws-sdk-go-v2/service/budgets v1.41.1/go.mod h1:wjQL1whunmAT3ZhqQGZq0lPGNmU27Uu8RjGmT12wLNg= -github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.10 h1:M1TeQUGe3K6yRVrWjbzQWtPZzL0YCjXE67ZuXHq9As0= -github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.10/go.mod h1:H9eUeKMZNHJnd/zKD3Ga0xyk6da+LDSFMZfOw2Wz45E= -github.com/aws/aws-sdk-go-v2/service/chime v1.41.1 h1:44oVq8c++c/LV12VId21rnnp8VOsYeUHIDzcFbAJqiU= -github.com/aws/aws-sdk-go-v2/service/chime v1.41.1/go.mod h1:NL5o86salGH/wxYiFkrzG6K8/GGPGdUNYXS00LCoNr4= -github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.10 h1:hsizZupHqOY/a4kXJqo/kgkjPwHxptt4ethWPxIVk58= -github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.10/go.mod h1:ykYGKe/rWysRsTmMJcq5VvqFzViL4XqsHke2UMh4ok0= -github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.2 h1:duYgiNtiFVrcq1TAo4LhaMeALa1+7uy7rqCgm94nS7w= -github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.2/go.mod h1:xjd2Oeftl4VNXrNTaEBSpwu4cKUDo82FQL9eHunFDqU= -github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.1 h1:9Up9lk52f4JwQTTneROfVm9cm4T4ZMiI4P6l9Racla4= -github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.1/go.mod h1:q9yJkMo4u5vpFAExN0Vtw+ChYDwq0hsSrD9DDE5Sd8w= -github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.9 h1:m5cYYOu2qNdLlejq9xAzJYnqEiUdCt34AXUl0C9Lt30= -github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.9/go.mod h1:kyuiuFhvDWwqLGNWmwbIr/amPIFQWrA7KkbxRQvP0JU= -github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.1 h1:JdROcIIy8NsG5yoAZgr8zya8khelwZEkiQhC+2qwnLM= -github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.1/go.mod h1:6kx+wmHMUP1fQBUpXN2N9xRt2sQUlloxwyF5cMIvDOc= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.68.3 h1:H4jVDatTYCt6WSG7oC0dlZl8kfKHT2anADHQiQI1HVo= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.68.3/go.mod h1:llucikq1Q6I1Ps8rNV3St0bOY5RQMxYh1lpCaskyhPw= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.4 h1:jjgrc81F2h7KlpeN/g/B8QzQDIbaVIuh3u+Ibl/UZY8= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.4/go.mod h1:UtP1sSXq2FHHO7Lvn4mNplFS4x7oP4+uMIJIQ8+3JyY= -github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.12 h1:sL/TJmTThdewOJDczZuuosnifzbbzmgYeCWCrVXLI4Q= -github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.12/go.mod h1:yFxrWxlbxnTilFCsiViY+x3qnKqi1CGdSPfEWYnwh6Q= -github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.9 h1:iJ6l2NdE1LElrAgnGbmh1Uw9H/sh+s5b/IgP6Vg5080= -github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.9/go.mod h1:w13K+4E6mjE6m5w3tDBZCs+S0zUiAse7M3qZg5ugecw= -github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.1 h1:rREW79PiTjRnFfB+x6ReyYYfb2eplnYbuEQZDhgudS0= -github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.1/go.mod h1:6hxErkN8bbEtojNMVdGQPpL7j9+A/QKL+eDljfRIKMM= -github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.53.11 h1:GqRfk8acdUn5kBmq6RlN98PIUAhe1uiKVEFQ8Wqg+tg= -github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.53.11/go.mod h1:yPef5Em35Sb/89IIHAOarpsld8EuxyxuDVDlHj32LVA= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.1 h1:mgk+V5mDNGDTpawxzS0GyjTDbcmD2Db/IpIxVuIJaTM= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.1/go.mod h1:KSWhI1V5x80r8NUqs8QDkOazDolFqFUAjsyE5nYjKro= -github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.7 h1:Yj4NvoEEdSxA90x/uCBskzeF3OxZr72Yaf64n0fIVR4= -github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.7/go.mod h1:9/Q0/HtqBTLMksFse42wZjUq0jJrUuo4XlnXy/uSoeg= -github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.10 h1:iHbgvCKy+QOWwxoi27E0cvScKANkdJ4QVUvtPKPX9b8= -github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.10/go.mod h1:9R9pEHnoKOjLs5dDREGyV1Ui2kWZgPPKz0VZd3juZhY= -github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.2 h1:6YCT7dAWUWd9uNWnXatVCNDYMCKOilv//1ZbH42MtbE= -github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.2/go.mod h1:LAT1SFMRPN1z4wewG4PHazKs2xL+J59saaAJQfZj8rc= -github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.1 h1:Cx+3UeTRF9nUgqmK73ee+pfqC/xU62WlMEp4u9sKkoo= -github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.1/go.mod h1:160q+ylvlYKq6c8wufCHYeX4Qei0IC509n4hxlh8oVA= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.1 h1:HKp8jj94R8WmgseHjmKH8weZKHiI2pgfZ+7yh0z9BRs= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.1/go.mod h1:jZuIO2m8qmy6VFTQgB/8bTb72o+X4zLRfnu1PubtriM= -github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.9 h1:eDbt/ZpY/TD/SZwREHwIOUVCtxOIDtP0D9r+RiG6QDw= -github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.9/go.mod h1:MMDcKcUGX6vTU6iI4+JFF486CGygY/COEldYNSdQDFQ= -github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.1 h1:XXE1+yxobGTQ8u6kOfIzKkjlY9GKZO9ym/qB4HSwof8= -github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.1/go.mod h1:t9VTnwqOH9QaIWz+NXLMpV68Q983qdWH+ol+4pXATI8= -github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.9 h1:JurZxcGvXRgMUcXQX/64fQ6gbX4Fs5EuFtdKoxqZxtg= -github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.9/go.mod h1:TTz1x8GSLqG2xw5I6ZPs0nm9Ro8W/D44MyeffDYxXnE= -github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.9 h1:F57knV0os9MQqwt7AesU/SG9VDKcgKgTEfIz9S+Q7fI= -github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.9/go.mod h1:KysZ41BGS0TjTmMIu6v0jIOKSlmhACK+7NnZOytrqC4= -github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.10 h1:Bjyew34SxxjAQnijpd14fGGO+2KnILO/AQzVJblX4B4= -github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.10/go.mod h1:COTp2TtxyTD6Pm7H6mKieN+Q0TmccQhJnfxD6//JPtg= -github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.2 h1:dnPgXfBdVf0Mz/tqnmLTihGUbpttUnfcWDy074QiaOo= -github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.2/go.mod h1:QOzDyBkE0ODl/dOuwpcSdMDz/8mz2i+KbwE8hSTUxKo= -github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.10 h1:12f0ZP5XkV4O7RIYz/wpuhaxLP6s7+J75OpqB83eous= -github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.10/go.mod h1:9+D52LzbRUGdyzwB/AMLPi4ydjtSeFkCSloB6Tw7bq0= -github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.10 h1:Lx1tOt8Zo9onYJQ2vhwnXjgIESysOiJ65bx9PaYPCcc= -github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.10/go.mod h1:ahZYJFutez0db6zWQyLWNddBtDDGovvOShiUTnOYPPw= -github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.11 h1:zuNz0zPOh6yOwwuh7tO9dvfcy/fTVkvLL0S99c2XbYo= -github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.11/go.mod h1:NLRVISwN4NcFEWz8WN5kySbgN1g8hjYPR2cZD9Of3Rg= -github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.10 h1:Ky+u5qntJYl4vzaYAgut7Ww55fKUmO3hI1Bu7FUze7M= -github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.10/go.mod h1:QY56Tp8KUNsipLdUdWGTwNg76WXpos4Q4Bbw51i2KS0= -github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.1 h1:jwDn2p79HGHHZhn6PXU5Ur0zXTB2LTtH3EnmpujoTmU= -github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.1/go.mod h1:PzK50LObvBt9Mb2YxwsocMuck07wSMSR+eVU9CiV05M= -github.com/aws/aws-sdk-go-v2/service/configservice v1.59.2 h1:wLYrBB2bdNXCBHq2C4wSTUAOsbwpiOVYyK5gyPDwsbc= -github.com/aws/aws-sdk-go-v2/service/configservice v1.59.2/go.mod h1:8pBCQK4k6Qpff8QKM6gcCt2ZsluQFsNtNaa8ouEZLFc= -github.com/aws/aws-sdk-go-v2/service/connect v1.143.3 h1:lSoAUDJAEnZAJSlsB3htA89N04NKXp/aVzZjqHXbapg= -github.com/aws/aws-sdk-go-v2/service/connect v1.143.3/go.mod h1:4S/3f30iB9LArrLNHVRw/IWyGEGturV5Z5DF1rp3NsE= -github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.1 h1:QOS9GlCgEsug3XViTkdqJoP+aViiZO3jbqDogK9gYhs= -github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.1/go.mod h1:g0V7qnDiTliogqzfAiJrhrOAEKnY+XY3u7/FJ8sZEYU= -github.com/aws/aws-sdk-go-v2/service/controltower v1.26.10 h1:TIwjU2ujMh/xeGPhcdgkbSgD86rmX3/GOP99eNofkgU= -github.com/aws/aws-sdk-go-v2/service/controltower v1.26.10/go.mod h1:ZQuFo9/qnryEiHaDdXGo0pgsC+uHYHheHzGq+Vem8xM= -github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.2 h1:VivnMRlCTwLehgTM35HkCvDMtazOjR5qOBk5p2WIfA8= -github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.2/go.mod h1:z4Y8J/t7ktcqMxLtf4korP74Tg42Ov97FjuTDyFfJKw= -github.com/aws/aws-sdk-go-v2/service/costexplorer v1.59.2 h1:3gpBCMGemT7ICVav0yQfdPILVB5MDRL7D2C4XmD/QV0= -github.com/aws/aws-sdk-go-v2/service/costexplorer v1.59.2/go.mod h1:sP89eC3imDzTgMk/N+gDwDqjeQgLLEt0PuU5NMBHBCo= -github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.20.10 h1:pNn0agq67d7sF4zJ/bYHZkjK63W6UD4L85TCw55crxc= -github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.20.10/go.mod h1:Ouo0lXAlK9jTlJeMt6LTL+G6kKOfoK7xks0TT5AwdlQ= -github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.3 h1:eGd3TjGC98p5rxEVxmm9eKZyGX7o9xbGrMxUvwu7oEk= -github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.3/go.mod h1:86sgcd46latOOSvQKbctenNsiEHnow3vip0OnwSqC54= -github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.58.2 h1:bND6tXqyuCENQ4BgPnbZ/5uk52O8yVQ9VA5YiGpMUFM= -github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.58.2/go.mod h1:Sc22CT1GPF61n0yJdqquFNvqoyfnQCZ+WS7Uz8daW8c= -github.com/aws/aws-sdk-go-v2/service/databrew v1.39.3 h1:ysxZXq5UtMgacfeGErqwFZs4drcWfaRMfwTUi0TfaOk= -github.com/aws/aws-sdk-go-v2/service/databrew v1.39.3/go.mod h1:hu5s2BoJ9fqmyMoVVvYbAtTFOFg8lsr4TzgJnK58n2Q= -github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.3 h1:x3vzuW2JGtQWQocjYze9CScsxRQNs2eVlwhs4BDlYPQ= -github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.3/go.mod h1:rwA2QoV4mz3TSrr4QirNyAndfs3EmwbVrGx5nMtTdz0= -github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.9 h1:P3xC2HzI0AnETmQsyrWhgAVXKEHTRP9TwOz46/yOOl4= -github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.9/go.mod h1:WZjvFO/jWbSRaxdkTmbL5GZu1HmPV2+DrDFmUCH0BKk= -github.com/aws/aws-sdk-go-v2/service/datasync v1.55.4 h1:eV3CXCf6TDigPN8CpRt7p7i7h1EY4Er27yhN+vGvbvQ= -github.com/aws/aws-sdk-go-v2/service/datasync v1.55.4/go.mod h1:35IO7OkYfIGQJeJ8IOFN7dPrregYgMMxBlSGpR0dEj8= -github.com/aws/aws-sdk-go-v2/service/datazone v1.44.2 h1:GJKRpQurAmu+9R+j5WcuI4DAxLVkH4rFUQWLPUKrS2k= -github.com/aws/aws-sdk-go-v2/service/datazone v1.44.2/go.mod h1:ELpY+QIvAO5sH048NMmxDNMDuAKWbRmHCl0rrNR4V5s= -github.com/aws/aws-sdk-go-v2/service/dax v1.29.5 h1:UD59qdhdH1RTlRLID1KSJJGkP+X1Sji54rzP3k2A4EY= -github.com/aws/aws-sdk-go-v2/service/dax v1.29.5/go.mod h1:LqCHisA88LmdWAT7R/FsvLksZZs7ghdIUwZsZSu0xKs= -github.com/aws/aws-sdk-go-v2/service/detective v1.38.2 h1:artDNBhcGdZ0/GWj0EdpRKOXA3eKsHY9PqNmxwOd1Ts= -github.com/aws/aws-sdk-go-v2/service/detective v1.38.2/go.mod h1:cOhEIcmxoL4V4Uavp0LRUV30gYNTGiTd2G0/ECJlIls= -github.com/aws/aws-sdk-go-v2/service/devicefarm v1.36.3 h1:OOp6MY+hT8jc0vRKkK2xzI14dwoXenBPXYwy/nej+yI= -github.com/aws/aws-sdk-go-v2/service/devicefarm v1.36.3/go.mod h1:DOlSchQTITKhdLgShZBymT+x+kX6jSJx8ArGf2jvFVs= -github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.1 h1:mO8u1KoFx9MVe4Rp85NzUU6TZEAf4atrFrW86HOAjso= -github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.1/go.mod h1:pOx5GDFaf6hXYuvqq18r+Op5BCfuMuZKX2ZJgacqWNk= -github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.3 h1:884G69tdukkk8RYH73soxXPRzvjpSnzdoTPCVhYQ1v0= -github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.3/go.mod h1:ozhPmvMQlk6trPDKahoaHUUEzmgiRxuHjXMWqdBy/Is= -github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.4 h1:EgIG6rQdKZ3X/1c9H/1H1RKWVxFtY11b8C6MI72iVp4= -github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.4/go.mod h1:yv/LQu/I+t1HsDl5wBlBxhnFDmLe8sk+6EkFW1WTb10= -github.com/aws/aws-sdk-go-v2/service/dlm v1.35.4 h1:E6WM979VZjTY9Sxp24HXXKcPlulwXaBuWWoXrJN+6K0= -github.com/aws/aws-sdk-go-v2/service/dlm v1.35.4/go.mod h1:rP4rq5uek/rreEV2CzUzGPNcD36+ZLDeh9HzyxePFnE= -github.com/aws/aws-sdk-go-v2/service/docdb v1.48.1 h1:MBuwuulakbiHZ9SNHqdjfd95B3ie5yBVtPDLfQPajCo= -github.com/aws/aws-sdk-go-v2/service/docdb v1.48.1/go.mod h1:13D9OjKPmSXbWE+20zVYaesIuFSUtx1pEouI2hu8yp0= -github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.2 h1:S5Ym+nCmNuX+Mxlu1C57hpM2kRa/KMFhfJyI/ms+/fA= -github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.2/go.mod h1:GXVZTuVYCRQvfLiT+fKmnXLYap5xGTfz+UD47bxJEKE= -github.com/aws/aws-sdk-go-v2/service/drs v1.36.2 h1:HVo+k9ttPnGpjZS/4nGhifrltoGF8ytKBTUF+XPBt4M= -github.com/aws/aws-sdk-go-v2/service/drs v1.36.2/go.mod h1:qO9+wcb7meZj7R8VQd8QnHb+ZPRWdODsexKGr3ru7cA= -github.com/aws/aws-sdk-go-v2/service/dsql v1.10.2 h1:YhtJu0sZ3gFAix8M25aUS5tEVuoeN0Kp8qWQ0aURK0A= -github.com/aws/aws-sdk-go-v2/service/dsql v1.10.2/go.mod h1:qAIMlh9aATA3n6dbs3aHQD7MOCAN8km548KABpaxqUs= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.52.4 h1:5nhomXR6eve564BfKNb/2wvBJGicjXHOFW9++Y6jwRg= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.52.4/go.mod h1:6eUUnWOJ8sucL5Uk8rPkFo8FYioM0CTNGHga8hwzXVc= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.261.1 h1:1U9Is5mKIIgi8xlIZi5Apuq/SHnQrKUBmmRm4tmgLYM= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.261.1/go.mod h1:NDdDLLW5PtLLXN661gKcvJvqAH5OBXsfhMlmKVu1/pY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2 h1:aq2N/9UkbEyljIQ7OFcudEgUsJzO8MYucmfsM/k/dmc= -github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2/go.mod h1:1NVD1KuMjH2GqnPwMotPndQaT/MreKkWpjkF12d6oKU= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2 h1:9fe6w8bydUwNAhFVmjo+SRqAJjbBMOyILL/6hTTVkyA= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2/go.mod h1:x7gU4CAyAz4BsM9hlRkhHiYw2GIr1QCmN45uwQw9l/E= -github.com/aws/aws-sdk-go-v2/service/ecs v1.67.2 h1:oeICOX/+D0XXV1aMYJPXVe3CO37zYr7fB6HFgxchleU= -github.com/aws/aws-sdk-go-v2/service/ecs v1.67.2/go.mod h1:rrhqfkXfa2DSNq0RyFhnnFEAyI+yJB4+2QlZKeJvMjs= -github.com/aws/aws-sdk-go-v2/service/efs v1.41.2 h1:WlttNCWA42RoH3U2QASpq+5JkVZTnjAHt8Hpu4I/kQs= -github.com/aws/aws-sdk-go-v2/service/efs v1.41.2/go.mod h1:ddWcpZJhvKugMHfwzBsq3dtaBLH7PsTgtAyiL3BEdxo= -github.com/aws/aws-sdk-go-v2/service/eks v1.74.7 h1:dqNrMBr+8NrKNXUN3h88HLwJWDGSV3h7HgCFqItJ+MM= -github.com/aws/aws-sdk-go-v2/service/eks v1.74.7/go.mod h1:xHVz3A2oEVl3UzjCOSEz/fBeBoFrS6FJ3cc/jo0WLyM= -github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.1 h1:qlldII+DFEDZKZtFj9laRO4YBkgiTaSuOmccIoExeD8= -github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.1/go.mod h1:m21nBoJHIHVbICAgJgvaZuO2AEfamKO53hl05xQ1ZUQ= -github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.11 h1:cGWsx/MXgjg84MJnyNQ7Ety6KpLkGe200DvhXyUtm5Q= -github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.11/go.mod h1:V3Yl2vXro/+nzAmexAXOc1GdkTmEE+UHp0YMuTn5G5k= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.11 h1:99Ju2tMSx8pkNvGVSXLyL6yy7juXfCxcl8vL5gAtvZQ= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.11/go.mod h1:ImGbJ8W4fb8KZekLSWCnuuabYN5WusCD7cnW4Nz7i14= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.51.5 h1:g8zncADOBZ34APoawN/iZcYAZ0/mVtGGeaDPz5URqDU= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.51.5/go.mod h1:Uyo8wjqYyZaHVqoe+APHe4+THRGv4pctJzItYYnRe5Q= -github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.11 h1:i+GKaGY+1ci+/bm9jptCBtg27JUbHlPMbf/xaku5Cs0= -github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.11/go.mod h1:GXyWYhCWYQQhGzxzNDU6CRL++zIsBgguWJFTa/iTOqI= -github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.10 h1:4SaTltdS17HyE0Q48Dcki6iHc30hgDuC5qdMPbeXlrw= -github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.10/go.mod h1:hV8KFAz+flqQ0eHBEJYGU4NWzTqQBtrRyqVwfm3Gi2Q= -github.com/aws/aws-sdk-go-v2/service/emr v1.55.4 h1:D5+t3h3vXOnX2FAJUe1p1L0fu300ITpME6u0rvmJF7k= -github.com/aws/aws-sdk-go-v2/service/emr v1.55.4/go.mod h1:NZatCe1XK65DogTuEG2emmEN3NIZtwLsXtJzWpkqSx0= -github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.6 h1:RAXe6pdT2rI1CWsgMCt2gYmioPL+slLtk81hQXkRwuk= -github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.6/go.mod h1:ncWhqV69Tim5BrNp98qdJfLvlD/WwCs5X3lBPgV62rs= -github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.1 h1:KgTxH206wAPdbi7IhYWKI1KEeUehUHqXtM1FfBxi7nI= -github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.1/go.mod h1:osVEDevOxiptmGI1/Q3CCm0FFIRf0MhwnWoL8Br0Pso= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.10 h1:BI56PI2i1CE0czMJZ6OFk8jde6nPmFWktkDDna5yXvE= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.10/go.mod h1:WVMQLFJTxCpu7h7eKnItFtVWitmVRJLsHTbZFYOmkTs= -github.com/aws/aws-sdk-go-v2/service/evidently v1.28.9 h1:sHHMo7xRH9RC95aKrZyT//yV074EdDN2LVMQx2grt88= -github.com/aws/aws-sdk-go-v2/service/evidently v1.28.9/go.mod h1:3Dt+ChkPyMq1eJTpXmBu4AUtsXN0oqfYph09KNICC6Q= -github.com/aws/aws-sdk-go-v2/service/evs v1.5.6 h1:02QX83EWnWb+Zeil0XFWMXQQTsjHOjEPBReHSpnkhlw= -github.com/aws/aws-sdk-go-v2/service/evs v1.5.6/go.mod h1:/IUqdRVJhNRM7OjN7cdlxnM2j+nuf8b1C6j20YzKTeg= -github.com/aws/aws-sdk-go-v2/service/finspace v1.33.10 h1:d/06SukYzwzgYuN077Qc10hD9MpY89yjSB4WotY2wmo= -github.com/aws/aws-sdk-go-v2/service/finspace v1.33.10/go.mod h1:L9hrtvHZKfvGwvP3rZcNgaZhhH0QWarqvcuw66JUqR8= -github.com/aws/aws-sdk-go-v2/service/firehose v1.42.1 h1:SxuqmmRvQ0+vB5MjEB73Jo5PvRFMoHU3Zfv+80IhOkI= -github.com/aws/aws-sdk-go-v2/service/firehose v1.42.1/go.mod h1:tHbE62j5gxIYxqmus+zqDQEZama0aWmglUnAk5+lAUs= -github.com/aws/aws-sdk-go-v2/service/fis v1.37.9 h1:CKtEPx1xCQrRUHDLpkaX43ga3PhYNYNHmCPPph4IRt0= -github.com/aws/aws-sdk-go-v2/service/fis v1.37.9/go.mod h1:Ja2eowkEbK8dfjWqxg96k4lkVjnf7YTUpEtQKHflynQ= -github.com/aws/aws-sdk-go-v2/service/fms v1.44.10 h1:XiI/s24q/w2CI+NP9LtGKv5vmdAII8N9O8GhJaLOa/4= -github.com/aws/aws-sdk-go-v2/service/fms v1.44.10/go.mod h1:qKGD0P+Hxcbq4w6Q6PUrDDLd0C2PcgwLtIS2BT6+2yo= -github.com/aws/aws-sdk-go-v2/service/fsx v1.62.4 h1:urTv0bEKWU6bDfz9jF/yTq7CaCyBox6Xjmz/F20itbk= -github.com/aws/aws-sdk-go-v2/service/fsx v1.62.4/go.mod h1:MCyHv+eBeciHOldY/pOKwp7j02Jo2HS1cpvThq2hSqs= -github.com/aws/aws-sdk-go-v2/service/gamelift v1.47.3 h1:AFP5CCk1aJNd463CIx25u4NsBxScLlS3vUkG28ptDWQ= -github.com/aws/aws-sdk-go-v2/service/gamelift v1.47.3/go.mod h1:dcVPaAeS/WE1PQeOldz0EuPud1gttdoQXajAKhNf0rE= -github.com/aws/aws-sdk-go-v2/service/glacier v1.31.10 h1:x7Qw8EiMW/0TSujhbsy4txAu3GbuiAJvq50cuog2FGI= -github.com/aws/aws-sdk-go-v2/service/glacier v1.31.10/go.mod h1:qkG1pn5qsa79Ovau5ZJ3DpYa9Ar534RyQU8PjjMalCM= -github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.3 h1:JjzgrGBK+CXE2zQVlyjld1h3qc5VXlLxQmDTHfHGu4I= -github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.3/go.mod h1:La9wJnRUasTkBLOLqH2JVrApk1WG0vui4MVyr+rGS8Y= -github.com/aws/aws-sdk-go-v2/service/glue v1.132.1 h1:GgPCZotTW5wWrro7+hotCARLuI9UP1Gyjcf2s9W3evM= -github.com/aws/aws-sdk-go-v2/service/glue v1.132.1/go.mod h1:KBo/tKQu4KUTMQ88jWZR79PNgEeDCD8QrO8oMmAq8ng= -github.com/aws/aws-sdk-go-v2/service/grafana v1.32.3 h1:Wn3sl9tIorquSK0fPeMFXnNCJ1pB4zwuxpKzMTlNA9c= -github.com/aws/aws-sdk-go-v2/service/grafana v1.32.3/go.mod h1:6tjVI48fzvjSAKY486cvKQPNeuIcV5YULNlFyAPZ+UU= -github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.10 h1:gLoXDwLQNoj9h71oUE0SYrXWqfpyznjD3fqD6OYSsqA= -github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.10/go.mod h1:wXnnE8KHU07d8VHPGTibk+Kx2TXFaCsL92wJoPPvCvM= -github.com/aws/aws-sdk-go-v2/service/groundstation v1.38.2 h1:NATc0n6+15TgtrhO/xopKCELOiukzX5dRbJV809b6BI= -github.com/aws/aws-sdk-go-v2/service/groundstation v1.38.2/go.mod h1:mg5Mut9Q671xNH+VvfaPBVvS4U9vLw1R5wz4bJvPjd4= -github.com/aws/aws-sdk-go-v2/service/guardduty v1.65.4 h1:a8ni6rPoSFzTITPXH3Uy1HAEKd78QHMNSjkp+P+5pXQ= -github.com/aws/aws-sdk-go-v2/service/guardduty v1.65.4/go.mod h1:U8kxZNr/dDtSqvr9L8e+fyqVmU/BNyI9fKWAatpu1CE= -github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.2 h1:4rQFhJ0j1ifbwFQKY/QDR4eNcQk3T1tDoN7M/mBApT0= -github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.2/go.mod h1:1GUJHZK3s9RIYhn/cLwh5/08/EfcnpCllSHWeJ23nVg= -github.com/aws/aws-sdk-go-v2/service/iam v1.49.2 h1:XeF6yEMX4/FxoSHCE1VNMOZ0t+mGnf/onqVe9dDVAlQ= -github.com/aws/aws-sdk-go-v2/service/iam v1.49.2/go.mod h1:cuEMbL1mNtO1sUyT+DYDNIA8Y7aJG1oIdgHqUk29Uzk= -github.com/aws/aws-sdk-go-v2/service/identitystore v1.33.3 h1:LeDRkqRXONJ1bxBAGuB0kRp1v2PrEIRYiXMqCKVmF5A= -github.com/aws/aws-sdk-go-v2/service/identitystore v1.33.3/go.mod h1:uuQmaV23i5w+5Jy2XFnquY0Z41iR6oDDdu+Sqz6bsNg= -github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.48.4 h1:J30DLdOosZDh9zwmWrFQffBVaHenpPy2oa/AqH5UmXE= -github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.48.4/go.mod h1:VD7bLCk88KQgyRB+yIQH9BNmtmSpwgRQ0Q7Wp1bsCuk= -github.com/aws/aws-sdk-go-v2/service/inspector v1.30.9 h1:e1WIoRDAyFSsxs4qGlDexK5MiPAWaBgn+7cobyLfnYk= -github.com/aws/aws-sdk-go-v2/service/inspector v1.30.9/go.mod h1:Ce8Iac726mzXgIOgFkMllAZsgb5XTOjzC5og1vPkHu0= -github.com/aws/aws-sdk-go-v2/service/inspector2 v1.44.10 h1:Ljs2y3qmx4eimm97ZtmJEBr4qDCbG7vhIcaCTdV7qZ8= -github.com/aws/aws-sdk-go-v2/service/inspector2 v1.44.10/go.mod h1:btzexzBLvYxamIptsxWMmHhXXx/FFmdKGgH96IM6HE8= +github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.45.2 h1:Ako32TEdYnL79+slzTDOFxdSKhltoWcjkNxPWz9X/M4= +github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.45.2/go.mod h1:iATSoxt/SEINLDvYHe5N9/UDnc45vngRxRJYr2MqGO0= +github.com/aws/aws-sdk-go-v2/service/account v1.29.4 h1:qrptW0Zqnc3O0fjjfmBDtJPRaNH+qY47txKwRhXQ67A= +github.com/aws/aws-sdk-go-v2/service/account v1.29.4/go.mod h1:3LbGl+sLnaiyCVp2LJXj0gEoeV2Uw0QOsDpP1gDMBVA= +github.com/aws/aws-sdk-go-v2/service/acm v1.37.13 h1:5AUX6KOEBF20wiIaiI4fKHvVkELEptyLtRTbWGpNQNY= +github.com/aws/aws-sdk-go-v2/service/acm v1.37.13/go.mod h1:v8E4cAu0qIxpS7IokQilQb60A8IODPxo82VxVtJ+Dgo= +github.com/aws/aws-sdk-go-v2/service/acmpca v1.46.2 h1:mBl0TQb13preknTDjHWbanhl1BveYfF1QES/YverKlQ= +github.com/aws/aws-sdk-go-v2/service/acmpca v1.46.2/go.mod h1:rpBWGq3UUlrgtAwNMy+I9ZoGgbiCoy30QetJZtI6+1A= +github.com/aws/aws-sdk-go-v2/service/amp v1.42.0 h1:eBxruXVqrfytiVJIqxGVW4kGlbxlsCasNa5GZgcTgZ4= +github.com/aws/aws-sdk-go-v2/service/amp v1.42.0/go.mod h1:uwNPmGivmh+4kJecS8OuYtMQTeZCGoBxdLLAGv+13r0= +github.com/aws/aws-sdk-go-v2/service/amplify v1.38.5 h1:uqG80MBs+aYwh6V2bpD3p4EAN3+23H9zDF+kyQNmbgo= +github.com/aws/aws-sdk-go-v2/service/amplify v1.38.5/go.mod h1:ieZIB8x+q5G3azy9SUtyGzGxXGHCVsTK4YvnADiCBZQ= +github.com/aws/aws-sdk-go-v2/service/apigateway v1.37.0 h1:yGW8ujCEpbex84kfx9KL6HkzfSC3pTiUOwNgrCB/Tek= +github.com/aws/aws-sdk-go-v2/service/apigateway v1.37.0/go.mod h1:9tT261wkl3uME2BWp/a3nzGNe9BM7jLWZdrXW1eX3BA= +github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.0 h1:jFWRglDVLlQcANMwsdFp/lJ6RAsc/mFLopFlTw9IeXs= +github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.0/go.mod h1:vr6hE/YGoQQa8PPwsB1uKt9wHjNZZcbXN+ww6lBXVhY= +github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.3 h1:CiSitRcp8P68+JoA9cNuBL6H2cdDtNr1w1pkHyRXFKE= +github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.3/go.mod h1:rvGHrN6a1lCypZrV0gDsJNPP5w51XIzr6manLptGnZg= +github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.12 h1:CKuViUgkrDY63niR+Jg2UBylJOSOrMx83NbOFKT0I7o= +github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.12/go.mod h1:EFrW9OOrllIDc/Rg/aUpaWnK81C2VVxhtFt9XUmM4kQ= +github.com/aws/aws-sdk-go-v2/service/appflow v1.51.3 h1:lmeUBk1pCMxqGNhlp1bpAMLzelZsqVh6YEQw5kJffMU= +github.com/aws/aws-sdk-go-v2/service/appflow v1.51.3/go.mod h1:bjux2H0bZSqK50RnMXHMr1eBi6Uw6gJmTeDOvFk7w14= +github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.12 h1:Mpl2kD1mBc6fegNiwcRzp8FjgDZ97fbaEafbDXF9xqk= +github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.12/go.mod h1:FrNhRSko1IPmuXPB8ldLs3nRkjjONG3E7ZE5nnV0snE= +github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.4 h1:YjpBB2PGZSl6WRhmgzLMMdvY5FIpWPQ/oVThQd6uX3M= +github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.4/go.mod h1:BDzrZs53Hsb5MyAICN2dmtFWaeLONzMaseXyF9Bagt0= +github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.11 h1:EcnZjQKet6JnsXwj2tw1gfvesNmnfGfvwuzWMZIxTfM= +github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.11/go.mod h1:2Sln2mubGkQTNc86N2eobz6KhGrHatsr4lVoIkUwrhQ= +github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.4 h1:t4DkpLlx64Dyv5ttJNfjuQCtXA4jwygnPic3u6SHeqg= +github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.4/go.mod h1:5Il7eB5oblkNf9V8ugOpPwA6ZARgTzld7otDTumO2w4= +github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.3 h1:IsdFy0YkFhSo1nPjw9WcPpm3joGCEH1pLnXuLkAV2X0= +github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.3/go.mod h1:xcEbbUjLqajeslIydrSJhESXNlGMtfXmu7MLY6ONlzY= +github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.5 h1:+fyOW8hT7uLzKQgkmKeqyq6Z8Y4+qiGsAOvbXYXmpdQ= +github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.5/go.mod h1:rI1byQGgb9tUXBvo3uLFrRXRzaCJayw+CiqAnDgYSKw= +github.com/aws/aws-sdk-go-v2/service/appstream v1.52.1 h1:wP/OGyNS8YMeNf1nqNMl3zPkyl3Vp2UJ171ykt2Vkvc= +github.com/aws/aws-sdk-go-v2/service/appstream v1.52.1/go.mod h1:flCm0TnAjuMbHs8YaGjVjQjUUsa5EP5O6nC4Zpt080E= +github.com/aws/aws-sdk-go-v2/service/appsync v1.52.3 h1:ANP9cl/DMLE1BewJU7eg25Ipq2gdrBtzd3k7nIcfq3A= +github.com/aws/aws-sdk-go-v2/service/appsync v1.52.3/go.mod h1:uCcHMGXa27Gp8b/hlAI0JbqmXeZp16E2FDWNz5nX0cQ= +github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.14 h1:wRm3ZJkjRHNiTRFGPLR9xTzXpAG8l1h5ywGY9b5tN5I= +github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.14/go.mod h1:PyPhpvZGkGYZTeuYRlPwZTgBx93EUYtHdpPbiIlY7Q8= +github.com/aws/aws-sdk-go-v2/service/athena v1.55.12 h1:upjiOGrCbvVk/kgSvE8oRE5SwzuaayRsBoMs2dnVlvY= +github.com/aws/aws-sdk-go-v2/service/athena v1.55.12/go.mod h1:1bY3ff3w7nTDnyGgOAOEZpO7e7bUiG2iDM2tXbCzxjg= +github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.3 h1:gus+gJbIngKvaL6Q3PH7e2tjO1Isx+kp+ldWIvysiY0= +github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.3/go.mod h1:6U6XFWocDXxVtEZsjDajhNtAxNJzZRs9k7CJHuTMJCY= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.61.0 h1:L4+Ts9JbR5Bb92eyQunFFAB6TfTobcfFne8+fNPGFX0= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.61.0/go.mod h1:6E1AiecbY52kVBl8lKkdaO759rbGK3TBBBNnfxJezTM= +github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.5 h1:/Gf9lbM1ce3h5SswLp0dCzWz3Lb8wHdlQvD9okQFnKs= +github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.5/go.mod h1:NkStIqURmzgUVyoB3YkmU1HUtIPECrExIastd5QbXIk= +github.com/aws/aws-sdk-go-v2/service/backup v1.54.0 h1:irUsF+2pK8u1YfiH1SC265XCRR81txSLGOca1s8Dh88= +github.com/aws/aws-sdk-go-v2/service/backup v1.54.0/go.mod h1:Sqiqu5Ws64P9IYY+0mQ4OafDKK1LK6sRWQqw89dZZYA= +github.com/aws/aws-sdk-go-v2/service/batch v1.58.6 h1:/SWr0iPuPFm90sbJwTowOCD63ZtbdFYmp67XlXygwxo= +github.com/aws/aws-sdk-go-v2/service/batch v1.58.6/go.mod h1:zaUBHLEVy5UjLlFt996XZMXLza3teA7f0IhAoV7+3mg= +github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.5 h1:otJvRakif5zPNVJ2sRcayQFqYh8QMj3ukVNred28uTw= +github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.5/go.mod h1:PJ5iWye10CA9cYAeVL4RUSkZvAwVK/WrOnTSHLztNAI= +github.com/aws/aws-sdk-go-v2/service/bedrock v1.49.1 h1:Da6sk9ZLlC2PXBWRPENz9msEkn5fYE6MOSWKPTjoMRg= +github.com/aws/aws-sdk-go-v2/service/bedrock v1.49.1/go.mod h1:xJ84P+JCcEkzkMjqBKmImWl/zlwEwBmbjc9QR+tcACQ= +github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.3 h1:UArcFWYHtdk5QWOTteqRZwF/tAoaYx+ArreUakHx8K0= +github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.3/go.mod h1:R5jkUdemrZt6+90gq4JFyxHKldEMH88F6wdxquDLa4Q= +github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.3 h1:lskoaAo1V+KpDYgS6lWMGvnxGhA0eX/bUQ6Xm7TEJM8= +github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.3/go.mod h1:MvhjtEWL5RO1w6AMrt4d9k//kZxZUsLrTSipRM9Q0/8= +github.com/aws/aws-sdk-go-v2/service/billing v1.9.0 h1:xbdlsW9TVa7AVpqB8CzaX6cM4qQQ/9RLrx6GGuBoSHE= +github.com/aws/aws-sdk-go-v2/service/billing v1.9.0/go.mod h1:7WI9oHeKA76HgGtTaUeKToGO/rRH9/fx7WLCw1QLJt4= +github.com/aws/aws-sdk-go-v2/service/budgets v1.41.3 h1:9cQXqYwHzp4fcKCHOAlHeMm/m/K+dcZS2D5SB+4ZA9s= +github.com/aws/aws-sdk-go-v2/service/budgets v1.41.3/go.mod h1:wjQL1whunmAT3ZhqQGZq0lPGNmU27Uu8RjGmT12wLNg= +github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.12 h1:WAVCaNagdhnjzFUUsrYADbR6NF1RVG9LAZj2+oY8gAg= +github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.12/go.mod h1:H9eUeKMZNHJnd/zKD3Ga0xyk6da+LDSFMZfOw2Wz45E= +github.com/aws/aws-sdk-go-v2/service/chime v1.41.3 h1:8Dt3NnfOF1ErL1xUxi6+fu5p/3Ezee6RZaCxH8YzL8g= +github.com/aws/aws-sdk-go-v2/service/chime v1.41.3/go.mod h1:NL5o86salGH/wxYiFkrzG6K8/GGPGdUNYXS00LCoNr4= +github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.12 h1:f6OT810gyz9/vYCGh99l8e2bSIqGO2B8HeSEsFwKy7w= +github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.12/go.mod h1:ykYGKe/rWysRsTmMJcq5VvqFzViL4XqsHke2UMh4ok0= +github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.4 h1:0W88faK7py65Xgpi/SPpK4HxF4nrHi0SG20ZTDdGQ1A= +github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.4/go.mod h1:xjd2Oeftl4VNXrNTaEBSpwu4cKUDo82FQL9eHunFDqU= +github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.3 h1:158UOfGTmbAijrcMpR72d7UWaA8VtpyRDSQtiGB2Gd8= +github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.3/go.mod h1:q9yJkMo4u5vpFAExN0Vtw+ChYDwq0hsSrD9DDE5Sd8w= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.11 h1:iR8n4gvDdN2hrUjXgETp76p/ILPbLFPuNbOi68B4CfE= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.11/go.mod h1:kyuiuFhvDWwqLGNWmwbIr/amPIFQWrA7KkbxRQvP0JU= +github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.3 h1:6ZTiyJCqVLE5CjuCZ6h9kKEbWOTbFxlBFXZ0fvTZK+s= +github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.3/go.mod h1:6kx+wmHMUP1fQBUpXN2N9xRt2sQUlloxwyF5cMIvDOc= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.70.0 h1:w9Yx0QWNhU2615kugQRIYSSR27GpZHkyRVdEHGi5PIY= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.70.0/go.mod h1:llucikq1Q6I1Ps8rNV3St0bOY5RQMxYh1lpCaskyhPw= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.56.2 h1:1Ipv5nooFuWg3iPGQPeh1WkUSJ96QFTqZQKMHPw9WHc= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.56.2/go.mod h1:UtP1sSXq2FHHO7Lvn4mNplFS4x7oP4+uMIJIQ8+3JyY= +github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.14 h1:AfC0uaSoMsz32lAOMkTjyfSX1PZRYniqzyt6pJmf+00= +github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.14/go.mod h1:yFxrWxlbxnTilFCsiViY+x3qnKqi1CGdSPfEWYnwh6Q= +github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.11 h1:w+afQ/tvYUVdTiX1LhIm/vSNvaNiOyy3QoYGz3GfhuI= +github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.11/go.mod h1:w13K+4E6mjE6m5w3tDBZCs+S0zUiAse7M3qZg5ugecw= +github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.3 h1:AUYRw6eRXp6MjvKpTGRbNBmlfVRY7kEuClnMGv/zQQI= +github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.3/go.mod h1:6hxErkN8bbEtojNMVdGQPpL7j9+A/QKL+eDljfRIKMM= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.54.0 h1:dbSrsAKSNOOwNd1rtaZwiRSzjc6U9yIRMfymrEeCM9g= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.54.0/go.mod h1:yPef5Em35Sb/89IIHAOarpsld8EuxyxuDVDlHj32LVA= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.3 h1:fD9/X9n4O6fauKLp9BE848I3JcXVEliwlgliernxUhs= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.3/go.mod h1:KSWhI1V5x80r8NUqs8QDkOazDolFqFUAjsyE5nYjKro= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.60.0 h1:jqF36cdImXcEo63d52Wpdi2qTXOLTZSJF/71h9MP5jo= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.60.0/go.mod h1:9/Q0/HtqBTLMksFse42wZjUq0jJrUuo4XlnXy/uSoeg= +github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.12 h1:j75xPdSialz4ipsvOpCtKl2VFb/ugc2PMgOfVvWjt6o= +github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.12/go.mod h1:9R9pEHnoKOjLs5dDREGyV1Ui2kWZgPPKz0VZd3juZhY= +github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.4 h1:rp7p7dTLS1qix2pVRT168GfZevumq0HoiytyrRG5e9o= +github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.4/go.mod h1:LAT1SFMRPN1z4wewG4PHazKs2xL+J59saaAJQfZj8rc= +github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.3 h1:jusavOo6R3Cx7dF90etnt4fSU1KWM1NSwENFsdPPqVQ= +github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.3/go.mod h1:160q+ylvlYKq6c8wufCHYeX4Qei0IC509n4hxlh8oVA= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.3 h1:D0CCIRXUefKZX30AyyG7QZby5+tVzP3Z+M66HoZVI4g= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.3/go.mod h1:jZuIO2m8qmy6VFTQgB/8bTb72o+X4zLRfnu1PubtriM= +github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.11 h1:UjRTTd2hwOv/bzqqaDlemhOqBK+J/tjTdv6PRJSvCxg= +github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.11/go.mod h1:MMDcKcUGX6vTU6iI4+JFF486CGygY/COEldYNSdQDFQ= +github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.3 h1:K6u1VZc2SmFqWaBELcIfowpH4livshEk3Iwg/Kuvd9g= +github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.3/go.mod h1:t9VTnwqOH9QaIWz+NXLMpV68Q983qdWH+ol+4pXATI8= +github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.11 h1:2+4r5Z7FE6bFMOfMt9b26xVwNwOn9DSS/gDTQSZVcuU= +github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.11/go.mod h1:TTz1x8GSLqG2xw5I6ZPs0nm9Ro8W/D44MyeffDYxXnE= +github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.11 h1:SEaA8Sl/YGV7nrjySKWTncQo4Zj0Xcbjr2+jb8LFrtU= +github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.11/go.mod h1:KysZ41BGS0TjTmMIu6v0jIOKSlmhACK+7NnZOytrqC4= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.12 h1:OhbU8xlrNQt2qNHX8kKB8/WaONKPadiaSRXpyPYkCFY= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.12/go.mod h1:COTp2TtxyTD6Pm7H6mKieN+Q0TmccQhJnfxD6//JPtg= +github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.4 h1:we8Y0b2KcnY65saLrF9YXtFfK9BrpMY/qlx7QysALqI= +github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.4/go.mod h1:QOzDyBkE0ODl/dOuwpcSdMDz/8mz2i+KbwE8hSTUxKo= +github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.12 h1:6YR4J0bwBwLRwZ7OFm8gpA8BBVoTsbjfMBWNOuRkOBE= +github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.12/go.mod h1:9+D52LzbRUGdyzwB/AMLPi4ydjtSeFkCSloB6Tw7bq0= +github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.12 h1:lS0WkuQQ13PmBN5Aab3GajJA15BeTGOeFCYQlAmROfw= +github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.12/go.mod h1:ahZYJFutez0db6zWQyLWNddBtDDGovvOShiUTnOYPPw= +github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.13 h1:gUchSsfXNg3xDlGKTCOx/ZvFk/CbsiQ6pHgSzAAvNUo= +github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.13/go.mod h1:NLRVISwN4NcFEWz8WN5kySbgN1g8hjYPR2cZD9Of3Rg= +github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.12 h1:OUq9z5ZMhZn87/QKG9xxWeyEmf8HKC4aiNnpLy36lc8= +github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.12/go.mod h1:QY56Tp8KUNsipLdUdWGTwNg76WXpos4Q4Bbw51i2KS0= +github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.3 h1:0oum8CeAFRcovMsI+a8R3op5Z1ngJVLgi9ffWYt3xkQ= +github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.3/go.mod h1:PzK50LObvBt9Mb2YxwsocMuck07wSMSR+eVU9CiV05M= +github.com/aws/aws-sdk-go-v2/service/configservice v1.59.4 h1:dY6ktQ8OfUkI6fTs0R9/3mAbYC6N1wEbjsGq2PLFms4= +github.com/aws/aws-sdk-go-v2/service/configservice v1.59.4/go.mod h1:8pBCQK4k6Qpff8QKM6gcCt2ZsluQFsNtNaa8ouEZLFc= +github.com/aws/aws-sdk-go-v2/service/connect v1.146.0 h1:fL4XXNHdfBmVWSGgsBzoezErUf7knnLK5cCUe1F3eoQ= +github.com/aws/aws-sdk-go-v2/service/connect v1.146.0/go.mod h1:4S/3f30iB9LArrLNHVRw/IWyGEGturV5Z5DF1rp3NsE= +github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.3 h1:ZcrD31NLG/brevUHw8XSn74VHShleHUm5xy8uJC/1ek= +github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.3/go.mod h1:g0V7qnDiTliogqzfAiJrhrOAEKnY+XY3u7/FJ8sZEYU= +github.com/aws/aws-sdk-go-v2/service/controltower v1.27.2 h1:D5zM7WP5IWp4DMbtY8NdTemanN/MxGyp2vm8Eis0gQE= +github.com/aws/aws-sdk-go-v2/service/controltower v1.27.2/go.mod h1:ZQuFo9/qnryEiHaDdXGo0pgsC+uHYHheHzGq+Vem8xM= +github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.4 h1:aCPRvahOg+fH79Sk9wOZslIrQVAAPgC1JpGzj1s5ZBo= +github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.4/go.mod h1:z4Y8J/t7ktcqMxLtf4korP74Tg42Ov97FjuTDyFfJKw= +github.com/aws/aws-sdk-go-v2/service/costexplorer v1.60.0 h1:nZrsl4tViAlW9+xkUpc4GXa9t0p3RIzGz9csmRrXR/s= +github.com/aws/aws-sdk-go-v2/service/costexplorer v1.60.0/go.mod h1:sP89eC3imDzTgMk/N+gDwDqjeQgLLEt0PuU5NMBHBCo= +github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.21.0 h1:8oTOAr895uaekGOozHzfH1zHGfBhSHZwpardvitnaCI= +github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.21.0/go.mod h1:Ouo0lXAlK9jTlJeMt6LTL+G6kKOfoK7xks0TT5AwdlQ= +github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.5 h1:XJUCroqsUAG80W0jVK/Rb4QPF/YbZu/oVtmiGvF8gjI= +github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.5/go.mod h1:86sgcd46latOOSvQKbctenNsiEHnow3vip0OnwSqC54= +github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.60.0 h1:cJZPHHPjft5N0BNv9X0bsUdDNGGbTQiT2b7jiN+NYv4= +github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.60.0/go.mod h1:Sc22CT1GPF61n0yJdqquFNvqoyfnQCZ+WS7Uz8daW8c= +github.com/aws/aws-sdk-go-v2/service/databrew v1.39.5 h1:gQDXbDgv5AW3treUAsfQGEeU3+ZmSEfb1TTpiDD7Gc8= +github.com/aws/aws-sdk-go-v2/service/databrew v1.39.5/go.mod h1:hu5s2BoJ9fqmyMoVVvYbAtTFOFg8lsr4TzgJnK58n2Q= +github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.5 h1:P9xrOXwbBxBzq30eiCFUlVE8lUUe6YnHs8j9dQx4YEM= +github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.5/go.mod h1:rwA2QoV4mz3TSrr4QirNyAndfs3EmwbVrGx5nMtTdz0= +github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.11 h1:ZmEqPDpJsiqkVqsRD7pi5SLO0VMyDavr9vlhF2R9iVM= +github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.11/go.mod h1:WZjvFO/jWbSRaxdkTmbL5GZu1HmPV2+DrDFmUCH0BKk= +github.com/aws/aws-sdk-go-v2/service/datasync v1.55.6 h1:pxK2rp4xZ073UMj7KUIX3Bwao02V6P+GXwvhOJW2Qkg= +github.com/aws/aws-sdk-go-v2/service/datasync v1.55.6/go.mod h1:35IO7OkYfIGQJeJ8IOFN7dPrregYgMMxBlSGpR0dEj8= +github.com/aws/aws-sdk-go-v2/service/datazone v1.48.0 h1:ON4CIIi/LgvXPKl+9FcuHI6evqfbFWbKvpngpS2IqvY= +github.com/aws/aws-sdk-go-v2/service/datazone v1.48.0/go.mod h1:ELpY+QIvAO5sH048NMmxDNMDuAKWbRmHCl0rrNR4V5s= +github.com/aws/aws-sdk-go-v2/service/dax v1.29.7 h1:d+Iq53DFhoJ4m+PKRCCosIodRTuWvlsh+LAWuOe7zWE= +github.com/aws/aws-sdk-go-v2/service/dax v1.29.7/go.mod h1:LqCHisA88LmdWAT7R/FsvLksZZs7ghdIUwZsZSu0xKs= +github.com/aws/aws-sdk-go-v2/service/detective v1.38.4 h1:iR9Cjiohq4R9veZr6DadbXEbKj1FADofRNJZ3hEjuwY= +github.com/aws/aws-sdk-go-v2/service/detective v1.38.4/go.mod h1:cOhEIcmxoL4V4Uavp0LRUV30gYNTGiTd2G0/ECJlIls= +github.com/aws/aws-sdk-go-v2/service/devicefarm v1.37.0 h1:VdU+oiTksNqUwRw5xv6AkoVKq6RecX6HrZmWGm/7lpY= +github.com/aws/aws-sdk-go-v2/service/devicefarm v1.37.0/go.mod h1:DOlSchQTITKhdLgShZBymT+x+kX6jSJx8ArGf2jvFVs= +github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.3 h1:pyh8Q7gwaW9mKsPG52ql7tarNkBn7jiYKmhXwzOAEO0= +github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.3/go.mod h1:pOx5GDFaf6hXYuvqq18r+Op5BCfuMuZKX2ZJgacqWNk= +github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.5 h1:XLpifFvzfFmQ0i4EX/xosiSt/yYEN7Wtw1LqffT3o0c= +github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.5/go.mod h1:ozhPmvMQlk6trPDKahoaHUUEzmgiRxuHjXMWqdBy/Is= +github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.6 h1:33I5jbO/kG0WEg/U4GyMYR1RfOfEk+hRQhUmiBOrFBE= +github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.6/go.mod h1:yv/LQu/I+t1HsDl5wBlBxhnFDmLe8sk+6EkFW1WTb10= +github.com/aws/aws-sdk-go-v2/service/dlm v1.35.6 h1:D7GyrH7x87n6IwM4sdujnhYdm+tRR3M6j9Q/uZV6GEI= +github.com/aws/aws-sdk-go-v2/service/dlm v1.35.6/go.mod h1:rP4rq5uek/rreEV2CzUzGPNcD36+ZLDeh9HzyxePFnE= +github.com/aws/aws-sdk-go-v2/service/docdb v1.48.3 h1:4VZq8ExlKiUtoFswYkkA36jHO4DwMHJe+EINHAbtVnc= +github.com/aws/aws-sdk-go-v2/service/docdb v1.48.3/go.mod h1:13D9OjKPmSXbWE+20zVYaesIuFSUtx1pEouI2hu8yp0= +github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.4 h1:0BkoVJIQfd3qMdianq8AUXcOxY9325OVroccwV3MGg4= +github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.4/go.mod h1:GXVZTuVYCRQvfLiT+fKmnXLYap5xGTfz+UD47bxJEKE= +github.com/aws/aws-sdk-go-v2/service/drs v1.36.4 h1:HH+yOVt1hVdw3q5OyG6dYjMi5mg+pGC7aza93j0sMNw= +github.com/aws/aws-sdk-go-v2/service/drs v1.36.4/go.mod h1:qO9+wcb7meZj7R8VQd8QnHb+ZPRWdODsexKGr3ru7cA= +github.com/aws/aws-sdk-go-v2/service/dsql v1.11.2 h1:+dLCcQdBv+JiLDp25/cDm5GiK2vKg5+y1n+Lm+ve3zY= +github.com/aws/aws-sdk-go-v2/service/dsql v1.11.2/go.mod h1:qAIMlh9aATA3n6dbs3aHQD7MOCAN8km548KABpaxqUs= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.0 h1:oyaZ6mvMgqy3Vm2RMD6ni2sQi4G9T6ntOXP5/PFtnVs= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.0/go.mod h1:6eUUnWOJ8sucL5Uk8rPkFo8FYioM0CTNGHga8hwzXVc= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.272.0 h1:zWYlsIUX88ZSDiKQR4603gVjPLR7Wn1+/hv76lsrMvA= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.272.0/go.mod h1:NDdDLLW5PtLLXN661gKcvJvqAH5OBXsfhMlmKVu1/pY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.53.0 h1:ReOAhAmW/8c2yLfr7fuLeD6WgXrp12yL27CCQMP6eQM= +github.com/aws/aws-sdk-go-v2/service/ecr v1.53.0/go.mod h1:1NVD1KuMjH2GqnPwMotPndQaT/MreKkWpjkF12d6oKU= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.4 h1:0rqbFeBlrTHNEIdrcH9g1yW0QjBOaCrGcTQ6sLcsH9w= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.4/go.mod h1:x7gU4CAyAz4BsM9hlRkhHiYw2GIr1QCmN45uwQw9l/E= +github.com/aws/aws-sdk-go-v2/service/ecs v1.68.0 h1:eKgxT+0Aj9zkdw2qcfCP9FyfrQlQwsfH7lQyeqwODmY= +github.com/aws/aws-sdk-go-v2/service/ecs v1.68.0/go.mod h1:rrhqfkXfa2DSNq0RyFhnnFEAyI+yJB4+2QlZKeJvMjs= +github.com/aws/aws-sdk-go-v2/service/efs v1.41.4 h1:Uk/tvWjdaeVQxmKTjleCJ05SPoXL5Upgq+rffBcolZI= +github.com/aws/aws-sdk-go-v2/service/efs v1.41.4/go.mod h1:ddWcpZJhvKugMHfwzBsq3dtaBLH7PsTgtAyiL3BEdxo= +github.com/aws/aws-sdk-go-v2/service/eks v1.74.9 h1:ugqH9Vu52QlUhpTbW75rsv0WA9k704DEwOCoxWsLy+4= +github.com/aws/aws-sdk-go-v2/service/eks v1.74.9/go.mod h1:xHVz3A2oEVl3UzjCOSEz/fBeBoFrS6FJ3cc/jo0WLyM= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.3 h1:a7jZ0M15w4FAGi7VsRvNSfUZk6ozGiFNz/eJ7DySiiE= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.3/go.mod h1:m21nBoJHIHVbICAgJgvaZuO2AEfamKO53hl05xQ1ZUQ= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.13 h1:l4FFXPDGzjr3bXU3tamm1cAmz4c7OWOiHPSekTdRllg= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.13/go.mod h1:V3Yl2vXro/+nzAmexAXOc1GdkTmEE+UHp0YMuTn5G5k= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.13 h1:VygvbUZq3ancO3iutKRr5zsdVR3X5wQPFoYMD1P8hhg= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.13/go.mod h1:ImGbJ8W4fb8KZekLSWCnuuabYN5WusCD7cnW4Nz7i14= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.53.0 h1:FW40Wq7eYkzoBc/7X4Ds7OLKXv+CM5w7n1mMN+qxSRI= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.53.0/go.mod h1:Uyo8wjqYyZaHVqoe+APHe4+THRGv4pctJzItYYnRe5Q= +github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.13 h1:hqyzd5cRYxvjVLa9FmmR39IM76hSNf+ROudLUpZviSE= +github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.13/go.mod h1:GXyWYhCWYQQhGzxzNDU6CRL++zIsBgguWJFTa/iTOqI= +github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.12 h1:Aqvjf0SzPHFEq7stD7515Osa/l8dXxnkdZiwjTrGE6c= +github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.12/go.mod h1:hV8KFAz+flqQ0eHBEJYGU4NWzTqQBtrRyqVwfm3Gi2Q= +github.com/aws/aws-sdk-go-v2/service/emr v1.56.0 h1:g185SYMRcklpYhul88jlO00EMsuOpfAwcXoys9KaeNk= +github.com/aws/aws-sdk-go-v2/service/emr v1.56.0/go.mod h1:NZatCe1XK65DogTuEG2emmEN3NIZtwLsXtJzWpkqSx0= +github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.8 h1:h4R+o2xRhtn4SPIao+6aU1TVTYBk0CfoLd9bhXZ3OTw= +github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.8/go.mod h1:ncWhqV69Tim5BrNp98qdJfLvlD/WwCs5X3lBPgV62rs= +github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.3 h1:axxXrvkaQcqcmEfNoIhU5oRLX7ufI2sAX+2a1j8xN1k= +github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.3/go.mod h1:osVEDevOxiptmGI1/Q3CCm0FFIRf0MhwnWoL8Br0Pso= +github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.12 h1:KsjKcIasbPhVthcDQcAJAyouihkQq5ZS5UJDMwx7yMM= +github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.12/go.mod h1:WVMQLFJTxCpu7h7eKnItFtVWitmVRJLsHTbZFYOmkTs= +github.com/aws/aws-sdk-go-v2/service/evidently v1.28.11 h1:Gz7BrxUHRme9DZt145R0WhRk6Kc4a8W5Wdl6Mw7oDp0= +github.com/aws/aws-sdk-go-v2/service/evidently v1.28.11/go.mod h1:3Dt+ChkPyMq1eJTpXmBu4AUtsXN0oqfYph09KNICC6Q= +github.com/aws/aws-sdk-go-v2/service/evs v1.5.8 h1:DBvUxll31Wr0ZiahXp+xzR4cuFmO1eFXXk41FopsAl4= +github.com/aws/aws-sdk-go-v2/service/evs v1.5.8/go.mod h1:/IUqdRVJhNRM7OjN7cdlxnM2j+nuf8b1C6j20YzKTeg= +github.com/aws/aws-sdk-go-v2/service/finspace v1.33.12 h1:f88cDjxWDscEu/9pLvTEn+xISRibEuceOFpX4xwoOxw= +github.com/aws/aws-sdk-go-v2/service/finspace v1.33.12/go.mod h1:L9hrtvHZKfvGwvP3rZcNgaZhhH0QWarqvcuw66JUqR8= +github.com/aws/aws-sdk-go-v2/service/firehose v1.42.3 h1:EwlA0X8pv8N6/sVK4r0A4JlZyib7nos8yU9YJSaiKV8= +github.com/aws/aws-sdk-go-v2/service/firehose v1.42.3/go.mod h1:tHbE62j5gxIYxqmus+zqDQEZama0aWmglUnAk5+lAUs= +github.com/aws/aws-sdk-go-v2/service/fis v1.37.11 h1:Z0sI7NcI76E0ok3s29O5TVM0ye2Qi4YGeeRGr7qDP9A= +github.com/aws/aws-sdk-go-v2/service/fis v1.37.11/go.mod h1:Ja2eowkEbK8dfjWqxg96k4lkVjnf7YTUpEtQKHflynQ= +github.com/aws/aws-sdk-go-v2/service/fms v1.44.12 h1:wqtKrEUifaZHVItsMfgAcHzHce8UUQfOvP6vDb2XqpY= +github.com/aws/aws-sdk-go-v2/service/fms v1.44.12/go.mod h1:qKGD0P+Hxcbq4w6Q6PUrDDLd0C2PcgwLtIS2BT6+2yo= +github.com/aws/aws-sdk-go-v2/service/fsx v1.64.0 h1:pIzBzYXgK8naqPgQ0H7VDd6hEi05rZG6DCrAxsn9f2Q= +github.com/aws/aws-sdk-go-v2/service/fsx v1.64.0/go.mod h1:MCyHv+eBeciHOldY/pOKwp7j02Jo2HS1cpvThq2hSqs= +github.com/aws/aws-sdk-go-v2/service/gamelift v1.48.2 h1:cdqUPiNlaSdNumcrBGIag7Qpi6rHwLZHxBvjP08LDBs= +github.com/aws/aws-sdk-go-v2/service/gamelift v1.48.2/go.mod h1:dcVPaAeS/WE1PQeOldz0EuPud1gttdoQXajAKhNf0rE= +github.com/aws/aws-sdk-go-v2/service/glacier v1.31.12 h1:8Az5fIk1L9pRU81KubxXn8QzUZJbticx8KBbTrc+s5c= +github.com/aws/aws-sdk-go-v2/service/glacier v1.31.12/go.mod h1:qkG1pn5qsa79Ovau5ZJ3DpYa9Ar534RyQU8PjjMalCM= +github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.5 h1:h80nAJssBG0S3yD8ZHoigFjmVFJIiL6jfx5FTUihdwo= +github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.5/go.mod h1:La9wJnRUasTkBLOLqH2JVrApk1WG0vui4MVyr+rGS8Y= +github.com/aws/aws-sdk-go-v2/service/glue v1.133.0 h1:bIzOBSUg62ENeRK0t7p8TjdXDhGgVZppSVrSNYSzSgQ= +github.com/aws/aws-sdk-go-v2/service/glue v1.133.0/go.mod h1:KBo/tKQu4KUTMQ88jWZR79PNgEeDCD8QrO8oMmAq8ng= +github.com/aws/aws-sdk-go-v2/service/grafana v1.32.5 h1:eTAfP6KrOmbUK4at7wlX8vG7qc8Ao110th4/Lw7xxI4= +github.com/aws/aws-sdk-go-v2/service/grafana v1.32.5/go.mod h1:6tjVI48fzvjSAKY486cvKQPNeuIcV5YULNlFyAPZ+UU= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.12 h1:0OhsswAs8h4vSCyGYx283pH+3Ks4Qngui0/g/KOhUYc= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.12/go.mod h1:wXnnE8KHU07d8VHPGTibk+Kx2TXFaCsL92wJoPPvCvM= +github.com/aws/aws-sdk-go-v2/service/groundstation v1.39.2 h1:BsyqAKq5RduYyz1muDRvvsKwXHd6yG/C+9TpdD+8O/o= +github.com/aws/aws-sdk-go-v2/service/groundstation v1.39.2/go.mod h1:mg5Mut9Q671xNH+VvfaPBVvS4U9vLw1R5wz4bJvPjd4= +github.com/aws/aws-sdk-go-v2/service/guardduty v1.68.0 h1:CMWFVQQDypdxhS1d4V19fP/Y3XNB72WLyteyafQMCsI= +github.com/aws/aws-sdk-go-v2/service/guardduty v1.68.0/go.mod h1:U8kxZNr/dDtSqvr9L8e+fyqVmU/BNyI9fKWAatpu1CE= +github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.4 h1:Dt34+Yu6fRgiZgSMoO6J65IMKawDGjJn7BkPvjrI0ns= +github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.4/go.mod h1:1GUJHZK3s9RIYhn/cLwh5/08/EfcnpCllSHWeJ23nVg= +github.com/aws/aws-sdk-go-v2/service/iam v1.52.0 h1:tXH4OrcRq053tqoWcmk9V3yfeedhgoa8o1J04S5JeYc= +github.com/aws/aws-sdk-go-v2/service/iam v1.52.0/go.mod h1:cuEMbL1mNtO1sUyT+DYDNIA8Y7aJG1oIdgHqUk29Uzk= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.34.2 h1:Ch+EIqM8RIEtVQqQl14XazfYBCzzxiZ1f7jbrOJ5D+8= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.34.2/go.mod h1:uuQmaV23i5w+5Jy2XFnquY0Z41iR6oDDdu+Sqz6bsNg= +github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.49.0 h1:VTKPR2R1q0o7N7T0ilqSajWWTlKNjsSzxvu319pLitc= +github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.49.0/go.mod h1:VD7bLCk88KQgyRB+yIQH9BNmtmSpwgRQ0Q7Wp1bsCuk= +github.com/aws/aws-sdk-go-v2/service/inspector v1.30.11 h1:I2WBSlw0rFVTTMDdg+7a77/kQFNKxJh1lJDZyI77ZTc= +github.com/aws/aws-sdk-go-v2/service/inspector v1.30.11/go.mod h1:Ce8Iac726mzXgIOgFkMllAZsgb5XTOjzC5og1vPkHu0= +github.com/aws/aws-sdk-go-v2/service/inspector2 v1.45.0 h1:gQW64ZGON3XG+UX2hDSHEXyRGd0YRxEqnyAYQRBK8tQ= +github.com/aws/aws-sdk-go-v2/service/inspector2 v1.45.0/go.mod h1:btzexzBLvYxamIptsxWMmHhXXx/FFmdKGgH96IM6HE8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4= @@ -303,272 +303,272 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 h1:zhBJXdhWIFZ1acfDYIhu4+LCzdUS2Vbcum7D01dXlHQ= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13/go.mod h1:JaaOeCE368qn2Hzi3sEzY6FgAZVCIYcC2nwbro2QCh8= -github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.2 h1:R3iBZpeWSueilpxnZqptm7//UzoW2mAwSbGfpwrgHas= -github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.2/go.mod h1:1J+jvIbqr9u7BwNyDWrriI1BsFBVMBEi6XP2T8QSAXw= -github.com/aws/aws-sdk-go-v2/service/invoicing v1.6.12 h1:b+ezLKuapXzffpj0V4lxpBrlUvgMi0Ddp1Ynpi9pgWo= -github.com/aws/aws-sdk-go-v2/service/invoicing v1.6.12/go.mod h1:077SFzwNIDjtHm35vjTtBHkweLVXtd3ahiPqfxo9Jms= -github.com/aws/aws-sdk-go-v2/service/iot v1.69.9 h1:rsNyU/ki3ze6KbSmeQERIuWiWXGbd1iN3wOJ4WjIqeI= -github.com/aws/aws-sdk-go-v2/service/iot v1.69.9/go.mod h1:Qsm1SgHzgKxy9TPqGfVBL+ULu/LW1iIOTn7kbsFhWE8= -github.com/aws/aws-sdk-go-v2/service/ivs v1.48.3 h1:hbSN4lzuMWMUM63kQuGZax6fUJUFHGqFsbTaTFbF49Q= -github.com/aws/aws-sdk-go-v2/service/ivs v1.48.3/go.mod h1:LWpDgCXaAZgKF5EH2xincNziWa0GkknDhx+ig0pAWzo= -github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.9 h1:yPmlx3GZDtjBsc348D9z7oxfs73+NX2uh2uUr0HvaPA= -github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.9/go.mod h1:gHijQmBJujk/KV3Y+trzDPVZ16MS5JkITQX5MqO3wiA= -github.com/aws/aws-sdk-go-v2/service/kafka v1.44.3 h1:rtf6o1k1DV/iuZXAx8ApQ3w0m4a+hx9QNF1zxDAq9NE= -github.com/aws/aws-sdk-go-v2/service/kafka v1.44.3/go.mod h1:Duj0BV8XyPzvoVF2LYtLDTCoQkIJ+NU1ui7QyMyCM/Y= -github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.10 h1:6wwedFSTr7XOFiqJirGQG1fGtELNpJDdzVfJ0S4qSUY= -github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.10/go.mod h1:wnbOw77+1dcXjlDl1JhSQmsO0+r3np9nFxvaX4HgUQ0= -github.com/aws/aws-sdk-go-v2/service/kendra v1.60.10 h1:sa9ZsmYBxXbpy8ATgyKBbgXS9IkQ2jCdZFv0jO7Fw2U= -github.com/aws/aws-sdk-go-v2/service/kendra v1.60.10/go.mod h1:KeQsf6zSp1LMwzIHnjOGuBzDWisc1sXHoJkLBFrsZ9c= -github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.3 h1:92nm3I/RtA49i3xgVdX4vs3FzxKWnlNoCRDf/AAt9eg= -github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.3/go.mod h1:W3i/Z8SlfqFwSoCNyYtKGd/LgR1vi08/35YQ1bxcEh8= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.1 h1:dSwPbGWGhA37laPvoToLp1b1wHRKUuPMorKCL/E+pi8= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.1/go.mod h1:jTDNZao/9uv/6JeaeDWEqA4s+l6c8+cqaDeYFpM+818= -github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.10 h1:F2leRXPB8l3bERzuAA5yE3Vmul8vodlOgwkLXtNNelw= -github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.10/go.mod h1:LHFWG4nhpu6EEIU4ZReJbmDVVL/up6CVhgkUTacFVyM= -github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.11 h1:z2Hkz9wcDTzCspYMf5YaTU3gw2ChPkSvUGfPlctUvMM= -github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.11/go.mod h1:tzsKwzVe1LFyj0teoeHk5bMpNCUNaHwX76Fw0Tc7xZg= -github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.9 h1:IBoHR14X2/wkLpJwCIK1YTKQyhHz0MheLspTJDK+qAY= -github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.9/go.mod h1:ml4xarTHw7hFk3uIw4wioNdFnATCJQhvlbGBHIMTRH0= -github.com/aws/aws-sdk-go-v2/service/kms v1.47.1 h1:6+C0RoGF4HJQALrsecOXN7cm/l5rgNHCw2xbcvFgpH4= -github.com/aws/aws-sdk-go-v2/service/kms v1.47.1/go.mod h1:VJcNH6BLr+3VJwinRKdotLOMglHO8mIKlD3ea5c7hbw= -github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.9 h1:DQkbOooOIjsmjey98tb+fNB1BYONPTYuUHLDad6xmsM= -github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.9/go.mod h1:1oR3VqBIi345fZEqaBh7HbB/GKLZU5F1+nbXQV5csnY= -github.com/aws/aws-sdk-go-v2/service/lambda v1.81.1 h1:s+T+4SWN2H4xTl/U1K6yTMEyos4Y7J5AhmKpw19y5H8= -github.com/aws/aws-sdk-go-v2/service/lambda v1.81.1/go.mod h1:X9xD+03BeNMi9vA0zcJ0rL4jaGRaBpB/54ukKjhz6ik= -github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.10 h1:ecPwW7d6Z67LossPeGqZ+QWbAzroa/G9+eaX6x+0n68= -github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.10/go.mod h1://3iRAUIqql/dPeYQI4lIv4JA8FiZzgIifX0EiX+9uU= -github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.3 h1:nwhmZ1Zg2TiaIfqXUlCvh+t6BAIfWFY8gGUkx+yeEHM= -github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.3/go.mod h1:iE4e1/ovGtt3keD9WWXuHfjoascElN+sEwN0Ff5Tys4= -github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.56.10 h1:Br0sxO83x7IDEZOq/uOkBKsb9Hm8RtYR/2ppiWaS3oA= -github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.56.10/go.mod h1:jcWBQtwCe0xBJLEVkz4ny1N+SRNRQQdpPUT1MKRwyu0= -github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.10 h1:tYEfcHgpwNLOKWksg/3cVq8xk+BjUqXQk7IxIJTxLW0= -github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.10/go.mod h1:jXdt+CSYTcfzhA60pRhvdlBEGWkHdb96/4+v8hJrYxU= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.4 h1:/1o2AYwHJojUDeMvQNyJiKZwcWCc3e4kQuTXqRLuThc= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.4/go.mod h1:Nn2xx6HojGuNMtUFxxz/nyNLSS+tHMRsMhe3+W3wB5k= -github.com/aws/aws-sdk-go-v2/service/location v1.50.2 h1:/TMbkCN8tXLQDW7ioTiyXeywn0Tj1HajEdZhPU6z8Sc= -github.com/aws/aws-sdk-go-v2/service/location v1.50.2/go.mod h1:XqDleYNKtPYvlUb14t3vWzJL/j81V1wyxALzAkhakfs= +github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.4 h1:i0+jLDeUbGVMnbM062bNuqXSRGvxChArs5Z/HcetByo= +github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.4/go.mod h1:1J+jvIbqr9u7BwNyDWrriI1BsFBVMBEi6XP2T8QSAXw= +github.com/aws/aws-sdk-go-v2/service/invoicing v1.8.0 h1:GmwiBzG6DhuL9w4MgrbUUHE+GFCJ9diSxbTAX27zTdo= +github.com/aws/aws-sdk-go-v2/service/invoicing v1.8.0/go.mod h1:077SFzwNIDjtHm35vjTtBHkweLVXtd3ahiPqfxo9Jms= +github.com/aws/aws-sdk-go-v2/service/iot v1.69.11 h1:E1iadLmKaX8iqk4lIOenXnd52iORtxQItB5kOID2J48= +github.com/aws/aws-sdk-go-v2/service/iot v1.69.11/go.mod h1:Qsm1SgHzgKxy9TPqGfVBL+ULu/LW1iIOTn7kbsFhWE8= +github.com/aws/aws-sdk-go-v2/service/ivs v1.48.5 h1:S7hZ3yWMpTG7jDJIQhWoob0vjAbS7g8VMmqDs+Rr0v8= +github.com/aws/aws-sdk-go-v2/service/ivs v1.48.5/go.mod h1:LWpDgCXaAZgKF5EH2xincNziWa0GkknDhx+ig0pAWzo= +github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.11 h1:3O57ECBVWgTITHZTmIsDdpaUUxGN2YULXDhBtea4A+Q= +github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.11/go.mod h1:gHijQmBJujk/KV3Y+trzDPVZ16MS5JkITQX5MqO3wiA= +github.com/aws/aws-sdk-go-v2/service/kafka v1.46.0 h1:hOOY9fQ95Rfv/L6XRFiJTZlcf52dFQ5txxw49VbFT5k= +github.com/aws/aws-sdk-go-v2/service/kafka v1.46.0/go.mod h1:Duj0BV8XyPzvoVF2LYtLDTCoQkIJ+NU1ui7QyMyCM/Y= +github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.12 h1:7ZayGxzuj2qFwCTUUVGHYS6hxHb5Uly1W4Lbau4BTXs= +github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.12/go.mod h1:wnbOw77+1dcXjlDl1JhSQmsO0+r3np9nFxvaX4HgUQ0= +github.com/aws/aws-sdk-go-v2/service/kendra v1.60.12 h1:MSoRxnPxbIaotIGof/+4CCw1ftfVnvTfB0h+0xDuAJA= +github.com/aws/aws-sdk-go-v2/service/kendra v1.60.12/go.mod h1:KeQsf6zSp1LMwzIHnjOGuBzDWisc1sXHoJkLBFrsZ9c= +github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.5 h1:8xc7vsJS13R7ikYhbREO8XJrekgAzju/kUNML/mibqc= +github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.5/go.mod h1:W3i/Z8SlfqFwSoCNyYtKGd/LgR1vi08/35YQ1bxcEh8= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.3 h1:A2HNxrABEFha5831yAU05G0mYNxaxYH4WG85FV6ZWIQ= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.3/go.mod h1:jTDNZao/9uv/6JeaeDWEqA4s+l6c8+cqaDeYFpM+818= +github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.12 h1:WAfQy/LSjjyAeWtCndtEkJA1tqADh7bqA3eEImVOsQo= +github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.12/go.mod h1:LHFWG4nhpu6EEIU4ZReJbmDVVL/up6CVhgkUTacFVyM= +github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.13 h1:m0QZX2HW98IKt/tS4DJFJwt/Qra46XXCfroHX/kvmA4= +github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.13/go.mod h1:tzsKwzVe1LFyj0teoeHk5bMpNCUNaHwX76Fw0Tc7xZg= +github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.11 h1:P1mPzg4L38jehlGOWnZIc9kCV4OD2Fjk0sJqdDWutzg= +github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.11/go.mod h1:ml4xarTHw7hFk3uIw4wioNdFnATCJQhvlbGBHIMTRH0= +github.com/aws/aws-sdk-go-v2/service/kms v1.48.2 h1:aL8Y/AbB6I+uw0MjLbdo68NQ8t5lNs3CY3S848HpETk= +github.com/aws/aws-sdk-go-v2/service/kms v1.48.2/go.mod h1:VJcNH6BLr+3VJwinRKdotLOMglHO8mIKlD3ea5c7hbw= +github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.11 h1:hF1Qozl8Fh6C1bUeNaL0xLbTlsHaKmxHKFfA08q5mU8= +github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.11/go.mod h1:1oR3VqBIi345fZEqaBh7HbB/GKLZU5F1+nbXQV5csnY= +github.com/aws/aws-sdk-go-v2/service/lambda v1.82.0 h1:MrStO25Ef1TbXFzZr2pZPdwcFHyUgPxCX7MXz09Qk7k= +github.com/aws/aws-sdk-go-v2/service/lambda v1.82.0/go.mod h1:X9xD+03BeNMi9vA0zcJ0rL4jaGRaBpB/54ukKjhz6ik= +github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.12 h1:dN62fbhBm0z/WOjTqQm7+vRpAPrLjFQd08TIhjvOhlA= +github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.12/go.mod h1://3iRAUIqql/dPeYQI4lIv4JA8FiZzgIifX0EiX+9uU= +github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.5 h1:C/Qq1lPIUMssyiBXzlhvOEEMPuLBuSqarHoXpRvML1M= +github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.5/go.mod h1:iE4e1/ovGtt3keD9WWXuHfjoascElN+sEwN0Ff5Tys4= +github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.57.0 h1:alZjWGUSbcTTNYTrOhbFVh7B1mSgMuXEvmsxFybSKYo= +github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.57.0/go.mod h1:jcWBQtwCe0xBJLEVkz4ny1N+SRNRQQdpPUT1MKRwyu0= +github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.12 h1:e6Q/2pgy/KKhpG8uBEq51rboXTepDcMKqmJTn1sv/Hg= +github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.12/go.mod h1:jXdt+CSYTcfzhA60pRhvdlBEGWkHdb96/4+v8hJrYxU= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.6 h1:cMYT6YsNkZjo4vguBxkgGCVffhaS0Dc2BZs/nGr4uLs= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.6/go.mod h1:Nn2xx6HojGuNMtUFxxz/nyNLSS+tHMRsMhe3+W3wB5k= +github.com/aws/aws-sdk-go-v2/service/location v1.50.4 h1:95HV4iCeSPGfTTiPI5JjmZAHud0YCn0wB1KViqk+Epk= +github.com/aws/aws-sdk-go-v2/service/location v1.50.4/go.mod h1:XqDleYNKtPYvlUb14t3vWzJL/j81V1wyxALzAkhakfs= github.com/aws/aws-sdk-go-v2/service/lookoutmetrics v1.37.2 h1:IXo/4IslBFio+k7Pm0gLptSh+B2GvSZQKRTDwfs9jkc= github.com/aws/aws-sdk-go-v2/service/lookoutmetrics v1.37.2/go.mod h1:tF6+C2s8Ru1RIyN1jPJR4VVk10Zz7pBhrYgZ72rFy7c= -github.com/aws/aws-sdk-go-v2/service/m2 v1.26.3 h1:LYEBwyFvctVmWjCz7weoxd054/zULftuyl1zGvyxSKE= -github.com/aws/aws-sdk-go-v2/service/m2 v1.26.3/go.mod h1:TcXLSXdIt/knslZsVOxLz85TXJHYftEnZp2Pkqcmd/g= -github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.2 h1:NkC/s9Wsghaskt8Iqt2wCtffsz7hJreXa4rnkiQL7pw= -github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.2/go.mod h1:UqgjJRAxzo2p/JJAaa4U10r468sb5dB7XdTojQM3J6I= -github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.45.4 h1:M2J4MEpldjlDZXOFJgRHga6PzlD2swL7yVAHo8Uyr4E= -github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.45.4/go.mod h1:h8kJMoJzHMU0zZWycpQpGmcxYLKhrhfC8RI1O4E4lv0= -github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.84.1 h1:wh6KarQYC3sOqSztbLclDsuzbFmnNSTLqxsjsMwA2UA= -github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.84.1/go.mod h1:69w+ev30uz0EQ+Z3brr3IecMA4D7Pkr3PtnQc0VGEZs= -github.com/aws/aws-sdk-go-v2/service/medialive v1.85.3 h1:oxLrq/Utamhh1Zj3MW2qWDSRSkT5bbiHfvvayoqjWbk= -github.com/aws/aws-sdk-go-v2/service/medialive v1.85.3/go.mod h1:SRJh9enbB1Urr1hv5+LKTbRlmXlhbjzvy3AwZkB7AHY= -github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.10 h1:kHJkbuRjwDLvVVxSPBsJxeilUcns3u20i1wSSeFPvjs= -github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.10/go.mod h1:7As8fD4Tr7DZAKWm0YOPFaoNymtw3xsCUkjQobfsZ7E= -github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.32.3 h1:LubivQgq+rRgBHCBbBgZ2UBkAdQ6y0mFGX6C0wSmRPQ= -github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.32.3/go.mod h1:w/Cotl6ORtnl+0i3hsOfzeV3bq5msbjgTrDhN57KTQU= -github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.10 h1:ScPcd6NdvARaVn9gz+EexxAmCtyK2/JSOhwPXwy9eys= -github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.10/go.mod h1:eiBfqNKAQK1rLuvKJOc6n5r9JZjgvdcMjxHHJlQwO3o= -github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.10 h1:iftQsYTyrBgW985/f00n5D8EYIHUieecePLZr7jP08g= -github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.10/go.mod h1:p0DZlc3953qm+OFFjWYXI4pUVN0Vtx7wxn/0sT6HjrQ= -github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.3 h1:WK9HbxC3KkSPF+kOAAAm9erqWNfqqmRMSXNtZTLn/3M= -github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.3/go.mod h1:iehQZb2FgCH28RyIL7fJCWgxmjCilIHVMJ3LXuZakCI= -github.com/aws/aws-sdk-go-v2/service/mgn v1.38.2 h1:CIDOUFOqBbKbJOGYJXm5tQwgRujN0p6i58YVT4InmcM= -github.com/aws/aws-sdk-go-v2/service/mgn v1.38.2/go.mod h1:n6Jxq0qdghot9uUi6ckEeaz0QvYv41DnFnSkNEwkKa8= -github.com/aws/aws-sdk-go-v2/service/mq v1.34.8 h1:4GQVLusZe5utEVcNSGmnoJX/NDlAchlcWSG0oReg+XU= -github.com/aws/aws-sdk-go-v2/service/mq v1.34.8/go.mod h1:ygM6WHFaCHMQ4+Pn3cMqFhWpbc06reGq4VTsv89bBrA= -github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.10 h1:c91LfZold0Ygx7qIoqMlRteiDbfzom3IdrS2VhO+NfQ= -github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.10/go.mod h1:1D+jlQDjJVp+zWuj+7fkdWRAId2DbnWm92v/QxcaMec= -github.com/aws/aws-sdk-go-v2/service/neptune v1.43.1 h1:J+BtvVBstv7HTQ47wtjwvNvTM3kGM64hwRQIx3RdjWs= -github.com/aws/aws-sdk-go-v2/service/neptune v1.43.1/go.mod h1:zZ58Zd5x0GGqnSgDLV4R3C1Xazzg3htNhg3kUpNB94M= -github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.9 h1:OxURddFfKJUKvUGnuhfltbn1xYG+tYMJ5rcVgSVaJEw= -github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.9/go.mod h1:dUFhAeruwm9ZYvMRk2JU6AR+YFcQ+4h34C3yNmz4T88= -github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.57.5 h1:JXSsiFYuM7CTUgN6H1pxsjh+svN/QS6ZNeOj2E8jEGo= -github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.57.5/go.mod h1:wCjIj4guias8uhaV3dqeSag/7v04X3xJQa4Ur9zJttc= -github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.10.3 h1:Pp2ZNKYqmhfmOAmK2N1PjdugfhoAP3W3IJgQJ7M5Fi4= -github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.10.3/go.mod h1:jIxhoFIXY3j5+i8UsPKY1jSMSGP8wKG4rHh1nF8fmzw= -github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.3 h1:HFzSq5FvyfkDE1A7Ti4jLypH79cI89g2lAOAfxec/hE= -github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.3/go.mod h1:nikytN6kEOGDn0q0o2NzpF93khMy4sO69ZVnh7D0owM= -github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.2 h1:DOVeRifiygskHYwQUCF/PMieAP2/Q2yj+o7TZxiP5kI= -github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.2/go.mod h1:6T6POkqNtemejwenhFM2l1sipv8saMi+Xewc2Q+4C+Y= -github.com/aws/aws-sdk-go-v2/service/notifications v1.7.8 h1:+KOW2yg8EyKwqpv45u1LK7BEK01AlLkKD0wOj6o5xyI= -github.com/aws/aws-sdk-go-v2/service/notifications v1.7.8/go.mod h1:DKnhbgXWeGgz1mzRZ+0b/jKqB3xy9yuy8LKIHUnv1ZM= -github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.12 h1:yBU2PHHrJCr7rJBsEkuRIomoaFZx/idWgfQPhKf+ZZY= -github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.12/go.mod h1:D6RFOazSGFCJcdxSEgw0ukJ+k2QgFfOdB3dVYNcHPVA= -github.com/aws/aws-sdk-go-v2/service/oam v1.23.3 h1:HOEc+yEjv38MAJWP+iT2HNILzq7/zAlN0uLQz3Fz1NQ= -github.com/aws/aws-sdk-go-v2/service/oam v1.23.3/go.mod h1:pz+AbYsaeY7dySgPSGl/Zr1zPJMOyOE/mR9+XtyhV9c= -github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.4 h1:Icp0wxQQJhKXiSic7BeYky9JnNdXoheSDQ+iJ5hPskU= -github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.4/go.mod h1:2GvP5es3RAok0PA4Fx95x5fJ0Xn7muSESZFHw1vp1BM= -github.com/aws/aws-sdk-go-v2/service/odb v1.5.4 h1:hYYhhdEqm0iOTXUX8Q5Ca4hPOy78t7P5NKxGW4ICogQ= -github.com/aws/aws-sdk-go-v2/service/odb v1.5.4/go.mod h1:jhCkBILzvRrCEyX2Wl+xn2BOBmrBedW7On1p1gzf3rA= -github.com/aws/aws-sdk-go-v2/service/opensearch v1.52.10 h1:XqBD+3vofEFRqlKEmtN2/0RtZ/yVSDOXHspT4D7GMEo= -github.com/aws/aws-sdk-go-v2/service/opensearch v1.52.10/go.mod h1:iVj8M5s79sFaX4eWUnBihWn+7PPHSdmCH6EqWQoySE4= -github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.2 h1:klZ+r7LYiIiuly4jKAaeSXvbka2NSMcAG3NnKJETxgM= -github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.2/go.mod h1:oLdL9Vhmp6N8H/f8Ttak+0SdUKk1E7Iwe84z9doZ87Q= -github.com/aws/aws-sdk-go-v2/service/organizations v1.46.2 h1:loLB5u3fRKxsz+gSnJCoCSV+0w3JT5C1nyihgOblc4w= -github.com/aws/aws-sdk-go-v2/service/organizations v1.46.2/go.mod h1:tnWiGtBYsKa4astPsL0YPaysffUcAp2C4Y0cZw6ZzGA= -github.com/aws/aws-sdk-go-v2/service/osis v1.21.3 h1:87bUk7OyHl5/KLqZkgyebx5sSFZj3ZFSCbONN8bkcZA= -github.com/aws/aws-sdk-go-v2/service/osis v1.21.3/go.mod h1:QGkOJj++ElJ2YmESnpRrwM7R38qf4ViMCCFIZVOHNgg= -github.com/aws/aws-sdk-go-v2/service/outposts v1.57.4 h1:ogkjd1atvA8QPECHRwFxzm1OBoRKtctlzDIgI8KgKlE= -github.com/aws/aws-sdk-go-v2/service/outposts v1.57.4/go.mod h1:rPsJtWQtj/V1kgdAFC9WyswmqrvJaOgHfLwibijL52o= -github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.1 h1:4hNk4DkVShk2Ngq/VM/gMAkqBAWXJH5ZrOF0l4AyHP0= -github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.1/go.mod h1:GqTw5UV5AIwHTpaKzHzt2KjETEO+hoBdIxbA/s7Fxzc= -github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.10 h1:gB/aU/UNi+E1AmpLKQw3UJLJApyjn9TKNVzhb8aX4wY= -github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.10/go.mod h1:GeIQIKjm5JhrcR/BB7x5DWPo2Bfhfm+Ui4w8x5TFz0I= -github.com/aws/aws-sdk-go-v2/service/pcs v1.14.4 h1:z8ZWB9WbgiePC+cFfLeoQ+swnH4R/p48SWTiddN/5Ko= -github.com/aws/aws-sdk-go-v2/service/pcs v1.14.4/go.mod h1:lG3E3PuHFsK508yCPxHBtDoM7S5bVuZOCaqECHkEM64= -github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.10 h1:3sFhl9X+yE2gReZ3bTcYdDw1eQ5KW9UQaIoZntfAK7A= -github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.10/go.mod h1:TmcGUQZpICbZKTvzURsi73eQMl/psfpgY/xse7pPf/4= -github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.0 h1:QDvzfJjdWFuy1KO9nfxzHSL1o7MVEM189YvEZ0NHQ3U= -github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.0/go.mod h1:eGDzes2BcpQDsKZ37KPgnrUujaLjA6B9doY+PmlROQE= -github.com/aws/aws-sdk-go-v2/service/pipes v1.23.9 h1:fO84zgGs2EguurOOTaDmnlvnqwnn3dN4amkKObK6jus= -github.com/aws/aws-sdk-go-v2/service/pipes v1.23.9/go.mod h1:vIeg0zOANsRAyRGYsXQLdaYh9XGmKMhY8r20NzkPPvg= -github.com/aws/aws-sdk-go-v2/service/polly v1.54.3 h1:luhA1og9lYf6GsNxZiVtY/ABnL/9/EvhlOPooH3sJew= -github.com/aws/aws-sdk-go-v2/service/polly v1.54.3/go.mod h1:IR55PMJ6jNjEu62EfCEP5v5oB4oGuRL3DvECBy0X1ps= -github.com/aws/aws-sdk-go-v2/service/pricing v1.40.3 h1:hyCsLZJCCn3pBNPmq/SUJARPSDSie+LYjvyZiWDbWmI= -github.com/aws/aws-sdk-go-v2/service/pricing v1.40.3/go.mod h1:qlgOQg0EL8GDTAPe5CcbgpaJGfSzA6ndypXctsMiW9E= -github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.10 h1:V/ryIi0WAS9kosnR2+hmexVnQKasn2bAsg1DVs8qbfs= -github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.10/go.mod h1:GrEm52MEfQXhAXsGFZEFiPt8AKvlD1uMkJ8KWRdlft0= +github.com/aws/aws-sdk-go-v2/service/m2 v1.26.5 h1:36dEuPAWGx9dmFvxAbsaoueMqEx24E1VYQEcJiaamF4= +github.com/aws/aws-sdk-go-v2/service/m2 v1.26.5/go.mod h1:TcXLSXdIt/knslZsVOxLz85TXJHYftEnZp2Pkqcmd/g= +github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.4 h1:9RF/3sDLXY55O2MJJl9iejd1IDuTMztpNdpYe9BigVk= +github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.4/go.mod h1:UqgjJRAxzo2p/JJAaa4U10r468sb5dB7XdTojQM3J6I= +github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.46.0 h1:ZISa5LjOv1UP8/i0NZiFVFn0TRcLI8iceeW4MzyWOlk= +github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.46.0/go.mod h1:h8kJMoJzHMU0zZWycpQpGmcxYLKhrhfC8RI1O4E4lv0= +github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.85.0 h1:IQwKEYP9sQ4USJc+xX5N/P85SyLAsWk0Kxx2Bx/xz4k= +github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.85.0/go.mod h1:69w+ev30uz0EQ+Z3brr3IecMA4D7Pkr3PtnQc0VGEZs= +github.com/aws/aws-sdk-go-v2/service/medialive v1.87.0 h1:nkvCXOE1zFYMaq9A7SMAeY+TWPQ/fe0BTkls8SrfyDM= +github.com/aws/aws-sdk-go-v2/service/medialive v1.87.0/go.mod h1:SRJh9enbB1Urr1hv5+LKTbRlmXlhbjzvy3AwZkB7AHY= +github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.12 h1:jw/o+ERI9EecbrQLGzrzHCPlpjd52ysHRkHV2G3T0lw= +github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.12/go.mod h1:7As8fD4Tr7DZAKWm0YOPFaoNymtw3xsCUkjQobfsZ7E= +github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.33.0 h1:0kXTtfY0fCyncN3yEf6UjeVRyouqUPLzrDCF/sRJqsE= +github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.33.0/go.mod h1:w/Cotl6ORtnl+0i3hsOfzeV3bq5msbjgTrDhN57KTQU= +github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.12 h1:3uZcDQNSq2K8+l26JGiI5ruvs8C4ZjG/uiUDU81LLok= +github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.12/go.mod h1:eiBfqNKAQK1rLuvKJOc6n5r9JZjgvdcMjxHHJlQwO3o= +github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.12 h1:NcvtI4JsJXem0VZSkt2u7ODCF7GZpoXr6hakfgOdbqs= +github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.12/go.mod h1:p0DZlc3953qm+OFFjWYXI4pUVN0Vtx7wxn/0sT6HjrQ= +github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.5 h1:jLxCVjcFucXlpF4LFHMPbmeDjyRP0ssZ0+/RlC1Hglk= +github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.5/go.mod h1:iehQZb2FgCH28RyIL7fJCWgxmjCilIHVMJ3LXuZakCI= +github.com/aws/aws-sdk-go-v2/service/mgn v1.38.4 h1:OSiWqiIVbyUiQcwyuPGc+BJRED9cfp8IV7ToFGitzl8= +github.com/aws/aws-sdk-go-v2/service/mgn v1.38.4/go.mod h1:n6Jxq0qdghot9uUi6ckEeaz0QvYv41DnFnSkNEwkKa8= +github.com/aws/aws-sdk-go-v2/service/mq v1.34.10 h1:LkV65nQNkhPblwXWKB6jree3BEgfPtmC93NFRsp+Nuo= +github.com/aws/aws-sdk-go-v2/service/mq v1.34.10/go.mod h1:ygM6WHFaCHMQ4+Pn3cMqFhWpbc06reGq4VTsv89bBrA= +github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.12 h1:GzwknGap79FTpA5CbbD2OF0rDnl0/bqN23zqwzHkdFg= +github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.12/go.mod h1:1D+jlQDjJVp+zWuj+7fkdWRAId2DbnWm92v/QxcaMec= +github.com/aws/aws-sdk-go-v2/service/neptune v1.43.3 h1:PFGZA4R64W8ZvC+MF4qE7Qkav/2LoexbhpdRAGvrQW8= +github.com/aws/aws-sdk-go-v2/service/neptune v1.43.3/go.mod h1:zZ58Zd5x0GGqnSgDLV4R3C1Xazzg3htNhg3kUpNB94M= +github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.11 h1:aHQda8rOysKlF7xSoPu9Qk5t2Ph5fyvrh/HWNEuNwYA= +github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.11/go.mod h1:dUFhAeruwm9ZYvMRk2JU6AR+YFcQ+4h34C3yNmz4T88= +github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.58.0 h1:gH0mo9odFg6ZI2g6pHcvihWMfCEjyOF0U271zEprUoc= +github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.58.0/go.mod h1:wCjIj4guias8uhaV3dqeSag/7v04X3xJQa4Ur9zJttc= +github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.11.0 h1:UiALLI9ec1KVMT+AJcXXIaknC3zkC7zzYoR/9DaX5K4= +github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.11.0/go.mod h1:jIxhoFIXY3j5+i8UsPKY1jSMSGP8wKG4rHh1nF8fmzw= +github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.5 h1:yVU4b7twe9pLU5dxkC0D6lUEgcZa7zWizXuRbvHp/d8= +github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.5/go.mod h1:nikytN6kEOGDn0q0o2NzpF93khMy4sO69ZVnh7D0owM= +github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.4 h1:PmyRpUoTfR2J1CfvGB2qz6kBiOROgDoR95N6CWG2SbA= +github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.4/go.mod h1:6T6POkqNtemejwenhFM2l1sipv8saMi+Xewc2Q+4C+Y= +github.com/aws/aws-sdk-go-v2/service/notifications v1.7.10 h1:i3wbNbKZdi40cAs+qyBEtG75DUOpbJJV/HwqGg35DkE= +github.com/aws/aws-sdk-go-v2/service/notifications v1.7.10/go.mod h1:DKnhbgXWeGgz1mzRZ+0b/jKqB3xy9yuy8LKIHUnv1ZM= +github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.14 h1:jbaCixU9rvfTGNli4NSkT1jwJeoVWTKR5vlta/E5smM= +github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.14/go.mod h1:D6RFOazSGFCJcdxSEgw0ukJ+k2QgFfOdB3dVYNcHPVA= +github.com/aws/aws-sdk-go-v2/service/oam v1.23.5 h1:DJqoutE8UpAtbqWeT/T62W3t9scS9ZZKAJJh6dGb8cY= +github.com/aws/aws-sdk-go-v2/service/oam v1.23.5/go.mod h1:pz+AbYsaeY7dySgPSGl/Zr1zPJMOyOE/mR9+XtyhV9c= +github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.6 h1:MsffOU8pULJVmQcvo8DarlR1rXAazOvITj7XuJB3QWo= +github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.6/go.mod h1:2GvP5es3RAok0PA4Fx95x5fJ0Xn7muSESZFHw1vp1BM= +github.com/aws/aws-sdk-go-v2/service/odb v1.5.6 h1:JLUu5UEdUX210Ojg5uTjzeRw5auZe6/10dd1vuCFlso= +github.com/aws/aws-sdk-go-v2/service/odb v1.5.6/go.mod h1:jhCkBILzvRrCEyX2Wl+xn2BOBmrBedW7On1p1gzf3rA= +github.com/aws/aws-sdk-go-v2/service/opensearch v1.54.0 h1:hN7HAN0qO5eLnh08ezJPfqsBBdNj6AWD7w5YQSLtYiM= +github.com/aws/aws-sdk-go-v2/service/opensearch v1.54.0/go.mod h1:iVj8M5s79sFaX4eWUnBihWn+7PPHSdmCH6EqWQoySE4= +github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.4 h1:7ijoIap1uO5GkJR6lzllEYYJxYp31nGQbKuyCbMMCZs= +github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.4/go.mod h1:oLdL9Vhmp6N8H/f8Ttak+0SdUKk1E7Iwe84z9doZ87Q= +github.com/aws/aws-sdk-go-v2/service/organizations v1.46.4 h1:a8FVhpNC4CSPnlXcgHzyIxm2/8LpQ9F60WPV6+tyFmU= +github.com/aws/aws-sdk-go-v2/service/organizations v1.46.4/go.mod h1:tnWiGtBYsKa4astPsL0YPaysffUcAp2C4Y0cZw6ZzGA= +github.com/aws/aws-sdk-go-v2/service/osis v1.21.5 h1:02dpYRwi3zGFWKll5a0IVr2u0g0QGZCB7+PfvtR2eCA= +github.com/aws/aws-sdk-go-v2/service/osis v1.21.5/go.mod h1:QGkOJj++ElJ2YmESnpRrwM7R38qf4ViMCCFIZVOHNgg= +github.com/aws/aws-sdk-go-v2/service/outposts v1.57.6 h1:FXA9OzvJlakCrbvKw3qmLrRG6q3EDt9FZnaS4Tx3upQ= +github.com/aws/aws-sdk-go-v2/service/outposts v1.57.6/go.mod h1:rPsJtWQtj/V1kgdAFC9WyswmqrvJaOgHfLwibijL52o= +github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.3 h1:Cws5mb47NYtqUZxkcCRR/9T0gwXmrXoweeVDeD0sRRI= +github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.3/go.mod h1:GqTw5UV5AIwHTpaKzHzt2KjETEO+hoBdIxbA/s7Fxzc= +github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.12 h1:VIxyAXmasuMqPn26ayhxZX6FK2yD+1iHHL0WDcGVIgk= +github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.12/go.mod h1:GeIQIKjm5JhrcR/BB7x5DWPo2Bfhfm+Ui4w8x5TFz0I= +github.com/aws/aws-sdk-go-v2/service/pcs v1.15.0 h1:jODJJvvzp3BtBc2rREK0foH2e8vyEhaCZ2z+nnOI/oE= +github.com/aws/aws-sdk-go-v2/service/pcs v1.15.0/go.mod h1:lG3E3PuHFsK508yCPxHBtDoM7S5bVuZOCaqECHkEM64= +github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.12 h1:fvCN4jZKj+gNhl/miNYBAs0OnVDKYwqrWLjpWdIV/zU= +github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.12/go.mod h1:TmcGUQZpICbZKTvzURsi73eQMl/psfpgY/xse7pPf/4= +github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.2 h1:LUeDu/bWhIz1eO8ANBlxcxm7bjv3BY6r4fF7p2CIDQE= +github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.2/go.mod h1:eGDzes2BcpQDsKZ37KPgnrUujaLjA6B9doY+PmlROQE= +github.com/aws/aws-sdk-go-v2/service/pipes v1.23.11 h1:PiQERt6yzJUeuPtcKgZ+HKhcJfFdLEU75rPX4O0XCqY= +github.com/aws/aws-sdk-go-v2/service/pipes v1.23.11/go.mod h1:vIeg0zOANsRAyRGYsXQLdaYh9XGmKMhY8r20NzkPPvg= +github.com/aws/aws-sdk-go-v2/service/polly v1.54.5 h1:72kDYtnJAiFF/9xzKpPEUZBGNetCC9tiNK6K8Moypkk= +github.com/aws/aws-sdk-go-v2/service/polly v1.54.5/go.mod h1:IR55PMJ6jNjEu62EfCEP5v5oB4oGuRL3DvECBy0X1ps= +github.com/aws/aws-sdk-go-v2/service/pricing v1.40.5 h1:H10gQvrDF1MX5vzVlTgQxH4UipAZunirvOSLHLO1QMc= +github.com/aws/aws-sdk-go-v2/service/pricing v1.40.5/go.mod h1:qlgOQg0EL8GDTAPe5CcbgpaJGfSzA6ndypXctsMiW9E= +github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.12 h1:5cOyDQZyhL094oRlmMiRtn1QhaESZWyTvIBIJkMMozo= +github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.12/go.mod h1:GrEm52MEfQXhAXsGFZEFiPt8AKvlD1uMkJ8KWRdlft0= github.com/aws/aws-sdk-go-v2/service/qldb v1.32.2 h1:tSctQisNHgXnDmyoOdLXkSQmHYo5yPQuvYK+4c4QiNI= github.com/aws/aws-sdk-go-v2/service/qldb v1.32.2/go.mod h1:m6bmXbLs5XiGnTLcgKn9eNk5+GCO5e/wHQsIuN7d1Tw= -github.com/aws/aws-sdk-go-v2/service/quicksight v1.95.4 h1:c0jYoV8b/sLbu8lPGd13mN3l3nOs1drpBHyXQxPkr5I= -github.com/aws/aws-sdk-go-v2/service/quicksight v1.95.4/go.mod h1:I8KrlgJxmNejc1VR3BWJ+J/uJuoLgaqTS/u/tJHIKA8= -github.com/aws/aws-sdk-go-v2/service/ram v1.34.11 h1:I8owg2znzlb5VJj5eeYOnsHS8iel8WPGIAkcveFqyLk= -github.com/aws/aws-sdk-go-v2/service/ram v1.34.11/go.mod h1:XVmWvCpgKVITq+ThzyDzJkCbVycgzv8P8KzdhwijsyQ= -github.com/aws/aws-sdk-go-v2/service/rbin v1.26.11 h1:+6YOD+rzIionatIPp5qpYzoH/aRwfpIR1dMVyZntPRI= -github.com/aws/aws-sdk-go-v2/service/rbin v1.26.11/go.mod h1:HSYlwezMfkOFle385IG72Np892kUVbGvYsdM+BEG+9U= -github.com/aws/aws-sdk-go-v2/service/rds v1.108.7 h1:q/854OSiNabB+vVTXG15TPHEcY3WpFB31JMy71Yr69w= -github.com/aws/aws-sdk-go-v2/service/rds v1.108.7/go.mod h1:mGQNxzRLKlj1cQU5uaMIjAhle0HkSeZDwoPfP+/nRYk= -github.com/aws/aws-sdk-go-v2/service/redshift v1.59.5 h1:Sg/jqBPF7A1UYtiGsXwVzyKBqfRjGzKola3RbH7cLwQ= -github.com/aws/aws-sdk-go-v2/service/redshift v1.59.5/go.mod h1:nroSRWOCQNS3b/vooHNsxwT5KRXzO+A8ouHyKsQenRc= -github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.10 h1:gYym5cRE9v1OEjwZLTWB5/uXDRePT11wiumfq49ffcs= -github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.10/go.mod h1:9beFz0fgqQr+Lkcz0lD54cquuuPUIV54fRbnLDQ7MNI= -github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.13 h1:h1LRp/NOYs+7OPyHnkFsVnLjjtdP/JhMK3vty1SZAG8= -github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.13/go.mod h1:fgg+LQ1jrDB3K18lra3Qx4tTGCZE9yX+eUQzxUjMhAs= -github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.9 h1:NbwYC74ooF+i6GYHhsO/HfSKizrH8p2cw70IURp0K2U= -github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.9/go.mod h1:r0M9WlvDeB2fPsZk2es9ZrjyUNIRPKoxm8xEU+CKbE0= -github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.2 h1:+wYMhcZrpqSNRXHY7wdylkgKvOx5NojGwgvUuvAgJoo= -github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.2/go.mod h1:efsKs5+XMP1JeFtYuLvLfHrBN3GmitdOUgKqDW2Xp9M= -github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.4 h1:WiOOC5M8n45IG+RaJD3N6q+Mv2VHbQhCkJM7NdwAyDI= -github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.4/go.mod h1:3A/lTLOEWLwbIFsOrriZuVdhibD0E4riboU0VaoV1mc= -github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.12 h1:/FDiAb1xNW3rnd/LHRhMLP74aVoAjDC1jkLA2EnhU2M= -github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.12/go.mod h1:6k9FPdJPkYmyrO0PFg1R+k3Rw5RYJT4MGdNqvodIGGY= -github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.30.11 h1:Ry8CcxRQeHUa4fw2yg+3xMC1BwdeQ29ccyWX+g+KPqw= -github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.30.11/go.mod h1:+nL0z6xUm9NK9bOAkam66NQDgNH8Qa6T6SS3f8dkzXU= -github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.10 h1:WvM1EXw1uU/75IS8QGgUtRahGTN5bIoIw5wx/1PufOg= -github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.10/go.mod h1:/WVeeJKvbKmaTWEtt7y2005MHRKlh+Ee5Nr3qmPMQpY= -github.com/aws/aws-sdk-go-v2/service/route53 v1.59.3 h1:YZrYzMaF4J0GbZwxlgSwXgHLBnYzklW3GakKFoOJQik= -github.com/aws/aws-sdk-go-v2/service/route53 v1.59.3/go.mod h1:TUbfYOisWZWyT2qjmlMh93ERw1Ry8G4q/yT2Q8TsDag= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.8 h1:77szvLM4Q3adxgXKL0RzgygnRi0WwgV5j4Nyj+xF7dU= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.8/go.mod h1:lxTo/orhKjYQIgzo0ED2KQyU5yC7zPw6vgImZBp5Opc= -github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.10 h1:jP72mUNCxMX25D6KOJzgs9lWpEjaD3KWDaa79c/pK/o= -github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.10/go.mod h1:Nvyw2yEW8po15FmApho3Biz63mgQirrO6dxseYQb1u8= -github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.3 h1:OE8VfFmM2yrBOF9OTwmsxM8+yqOY/ENMf7JJBUrKbWs= -github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.3/go.mod h1:uuKkzsDRNyxWABenHqS3Ms7KoEUf+3EHsNCnMBVMslo= -github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.10 h1:c9HRNESb/DZO1JmgOXRp6xf0q9sIpr56fdNE7kbXAyA= -github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.10/go.mod h1:FPoma320xUxwC7BRaqJPYjpyIgbuxrAF//JdP9ybfjQ= -github.com/aws/aws-sdk-go-v2/service/route53resolver v1.40.10 h1:nsmB5RhnPqbDDK0ZfA2fmlv2+BF6G1ejIAVLfVNyJKQ= -github.com/aws/aws-sdk-go-v2/service/route53resolver v1.40.10/go.mod h1:RtTRuj33VUDMd7i7eDEuhX2x69JWtPkWODE2b2TeiS4= -github.com/aws/aws-sdk-go-v2/service/rum v1.29.2 h1:tSG82w0z96VIuR+f30qXknzk5DHH0ezj8qKsWXEbMe0= -github.com/aws/aws-sdk-go-v2/service/rum v1.29.2/go.mod h1:aoij2zkJWvNtGzPvyaOZtNazKNjMBEVOmdDystHnh8g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2 h1:xgBWsgaeUESl8A8k80p6yBdexMWDVeiDmJ/pkjohJ7c= -github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw= -github.com/aws/aws-sdk-go-v2/service/s3control v1.66.7 h1:YMrm0OzfAv9KKuMYqV4reUMFNn9RnpRz3cBtIpsn8Rg= -github.com/aws/aws-sdk-go-v2/service/s3control v1.66.7/go.mod h1:c+ERB7DbWT1uR6QvBn7W0gB2YczXacCEoLegFLwPAE8= -github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.1 h1:PLLJqTqozJOGAWidlJIZhp/15PDLi1livXevOs6ZZ1k= -github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.1/go.mod h1:4XtnGsaxnIiUsurxxTMzn9Wl9/utEAN46rcMPVKLGAM= -github.com/aws/aws-sdk-go-v2/service/s3tables v1.10.9 h1:v3sRC7iJnffnh2WJpxufO09tnu/1o+d0wtSpq9HD2FE= -github.com/aws/aws-sdk-go-v2/service/s3tables v1.10.9/go.mod h1:t1l6loaBQWttife9bosS3OspbGv+CP18UbGxMIQie4A= -github.com/aws/aws-sdk-go-v2/service/s3vectors v1.4.12 h1:Bxhm/mRfKKNsKOIS0REnk6Ll6exvm0hPwt2lk51nF+Q= -github.com/aws/aws-sdk-go-v2/service/s3vectors v1.4.12/go.mod h1:+sgMaDJqPLY3w2QXsvbhgSlvIaQ4+4cYk6Cdp388Swg= -github.com/aws/aws-sdk-go-v2/service/sagemaker v1.219.1 h1:1CvE2DPquhIlym4eqtZElsmIs9sTHmMT7nHHqYgwzRo= -github.com/aws/aws-sdk-go-v2/service/sagemaker v1.219.1/go.mod h1:JnrlXHI1oM/gVNI0/NH1Ru4UZr4sWx/WZclCsJtbmCM= -github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.9 h1:DEk7LCDFI32irAvdrsVtqUr5OHtojMUL0JcUXjvRUB8= -github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.9/go.mod h1:UohrBXfiKjUlaqaMzj3jtBBfrNFSCjq+LLwDbtsvAIo= -github.com/aws/aws-sdk-go-v2/service/schemas v1.34.1 h1:pDHoETz2rncUE0tny2qug/GarMIcRaYD2shjjoXMxN0= -github.com/aws/aws-sdk-go-v2/service/schemas v1.34.1/go.mod h1:ipui3c5k/ozPT734rqfqsFgieDEny9ABk4sp7zCWjkM= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.11 h1:DouhxUREBjfnNJFp1yNn/p1Gk5pzr1YNixcIOIudI2g= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.11/go.mod h1:QgVIY03/XoQs2iFr0MbQuQ/Tf1RwlkOvuySWMh1wph4= -github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.2 h1:JhuxQSODGqdC3H0/K/4mtHlGiLdZyA8kANEA/Aexu/k= -github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.2/go.mod h1:QaXNTOs7OkNR7y9uFWajUymXwUh28Q7cTz3tqWiE6sc= -github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.2 h1:UtpQrbgUyjeTTZMgsB1VhVypFNAaIhAaS92pZvIIzD8= -github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.2/go.mod h1:8psZ/OINrXmUJhyXWm0NzLaKP5bp1t/dh0/D2Pj/YAo= -github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.1 h1:5OGkJWlC0B6jiyl69Q8ufrHweM4h0RsPqKtwSXgAvcg= -github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.1/go.mod h1:OmVOd812JbwvNOwaQMpeMmj2bnN6dgUZnVaD1UIvyVg= -github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.1 h1:z39h5nEO73EhUUzWvXN9Pg/WhA54HlCrBEePsKHgTUE= -github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.1/go.mod h1:fA60HaKYi8WBwj1uf+n2sZkyefVWWUTkKB69Th3pTB0= -github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.10 h1:eaBZKLRCRUs7THKWGT+mpd57ZoP9f4m9nzJ17YnA3Kk= -github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.10/go.mod h1:H/pz3dQJmZHdKf3DMgD0znZwoP0h8Umx9uPhBRXOkxE= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.14 h1:O/7WE5d5cWpOA71mudgEvyawhAPEI/C3ZTkFYZFSyNc= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.14/go.mod h1:lYyuDbeQ6vtjRP4gb9h2MReluEb0US5u+07X84akGKg= -github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.5 h1:nifPvTgsPLFy9a5eAWQ/+oSdY4MOvzgHpGZhvJBZ9vo= -github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.5/go.mod h1:TvpkfbD0qaLoadCivfVCzpgavaEJvmRpG0pzZOo4pX0= -github.com/aws/aws-sdk-go-v2/service/ses v1.34.9 h1:hrUBTmbCLLQ+X21wdcoK78sjRW3HGspp/vkAL3TkMx4= -github.com/aws/aws-sdk-go-v2/service/ses v1.34.9/go.mod h1:CeGX4LAFCsrBp24qazKmO/dwxghNCGbAoTbi64dGSEM= -github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.2 h1:na42MutKh8BRm7cKhf/h57kXPVP6yxhHJD1wyrJ4azo= -github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.2/go.mod h1:uxpQTTvKs2FUajNzmQic0lqMB5X0zjX8jpalkvkhIQI= -github.com/aws/aws-sdk-go-v2/service/sfn v1.39.11 h1:ALX8T3GCfowrsodpsh6WDM55BFG1APIT5pKNSMpRHsg= -github.com/aws/aws-sdk-go-v2/service/sfn v1.39.11/go.mod h1:fhG61r7sW7WsxXcZAips5CFQta1i2sQwRaEQeQwSrks= -github.com/aws/aws-sdk-go-v2/service/shield v1.34.10 h1:KUgzVt14lPJ1vLWYTIa4rAfDgeQwWk8S4NxtpIwPoJI= -github.com/aws/aws-sdk-go-v2/service/shield v1.34.10/go.mod h1:6B2EvRYLO2QsWbNoEsxazaKhVufZBDPApqPkpQ2arJI= -github.com/aws/aws-sdk-go-v2/service/signer v1.31.10 h1:6PDee9gY2Hho7TdAu9vL4qG7idlMds1jNaafA5d874U= -github.com/aws/aws-sdk-go-v2/service/signer v1.31.10/go.mod h1:F44pi85d2IzaTcwWULuLl2cdYjFkKr948NbU7gCmcKY= -github.com/aws/aws-sdk-go-v2/service/sns v1.39.3 h1:/i7MD7ZNdjf9BSiD5KQtS5G00902dU477E6zaR85eBE= -github.com/aws/aws-sdk-go-v2/service/sns v1.39.3/go.mod h1:1LvRsmADXI6174y66InuSDQiEztkQgCLbcw62VLC0FQ= -github.com/aws/aws-sdk-go-v2/service/sqs v1.42.13 h1:gfwPJhrWDHUeisN2p7bji+wocVmoJLJ3jgEQCKSiiMo= -github.com/aws/aws-sdk-go-v2/service/sqs v1.42.13/go.mod h1:ZS67woOy/ftzvKK2+P53u2NPqImAPTWz+hBn+tchP7k= -github.com/aws/aws-sdk-go-v2/service/ssm v1.66.4 h1:UmkF0ipNy0Ps6csJl/ZRJ3K+DWe9q0A7LT3xfxoHbgg= -github.com/aws/aws-sdk-go-v2/service/ssm v1.66.4/go.mod h1:uNHuYAQazkHqpD+hVomA2+eDSuKJzerno7Fnha6N6/Y= -github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.3 h1:kLuz4YTmXq+aINLty7O+x0XolYNYNK0feRIJLYOfmbw= -github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.3/go.mod h1:m9mkIFFGnEY00U3IpPs/TZLbbgOxARLDtqsDbGqzjik= -github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.9 h1:TWDKCXLDwxAhTHBqLUvKaYSN6Nim+ZvLIn5z4gl/Cag= -github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.9/go.mod h1:TUCeZ43VbibNN5TTa0oWium4Cj2ee/Xg93xNRVx+iUw= -github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.10 h1:luxs8NtvzPvhSKrZuRKtH+Fh11Ou/+qpF8RP7Xlgslo= -github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.10/go.mod h1:h/ogxk4gxt67ItMvhzCJSST5AHjaYYuMC/wdLMBLOrI= -github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.9 h1:xPbieVqdcD/IlQKyAzmW+cet+XbyhYydsDhSXJ+ISf4= -github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.9/go.mod h1:9/Q7dAszR79doau18RBveSfZX9RASAs4Tubh196QR8A= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= -github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.6 h1:UDapqbyf6JQcmFlYdzcwgModRtkuGvf9JBYDiza/mrQ= -github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.6/go.mod h1:CzDlwLoYGIK0Q7ISrzqCD1/Zgf6nsIdct4f0ZoyKoHI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= -github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.2 h1:gsG5dor2az8bej9BK1n00zk3azWSicYgnXXpUKwt6Nc= -github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.2/go.mod h1:JKIFhh/dRv/Ft85RarJH3G3ewl419X6gmD/1fEXjDnI= -github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs= -github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= -github.com/aws/aws-sdk-go-v2/service/swf v1.33.4 h1:RYnaNdZP2odU51vYnGW2PO9ubU455kW6JTbLiPmINNk= -github.com/aws/aws-sdk-go-v2/service/swf v1.33.4/go.mod h1:mmUGhXHOTZ0YLexnps/Zn0u5T+p9QkpGRpXuf5L2b7A= -github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.2 h1:ZwpnnzJUcb1MiH7HeotM4w2tAXATbJY3GSGHD/9QrVM= -github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.2/go.mod h1:NoN2h4JljGuHzAYWNB3WVGKnuKczRbHoqVh5Z7Z4YdM= -github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.10 h1:U+qf8OLSdxYntNgJhugFBuVs992P49gkYoeldflom6I= -github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.10/go.mod h1:mch3G+DUo5AjLDfRe7XL3QhVf1K+tk+u1WQiAj5tvzs= -github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.4 h1:3gsL0XSo0kEEhiejnaZmbaJi4iyPbekbIs/tplNA/98= -github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.4/go.mod h1:ATSASzt7xr2/Xcj8ZjMQg9woL5SyhrghAPCb7nArWVY= -github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.3 h1:aCLSUkSfQWKTFYW+lwgM6BNIQ2tZ2DVzXlRJeTZcNY8= -github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.3/go.mod h1:b34PXpekNN9TeyqzUNcFiOEAm3DFd4e+viL/XbQtzuk= -github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.9 h1:dxRHB2qTysfdmeDNV2X2HMP3OAvz0WPZs+SLMZhey2I= -github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.9/go.mod h1:WOhN8208dG/kUp22L0kch06lMtCQJ/+Ypv2W3TTC6vg= -github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.4 h1:TD/9gwYUVEQHUs1Z08iTH3krJ1Z/TlJc+ByrD2FQ4C8= -github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.4/go.mod h1:juatw/4IEOV9unN2B/ZmVXIGA8YnhDTXzY/ZdIBS11w= -github.com/aws/aws-sdk-go-v2/service/transfer v1.67.4 h1:MzHFkeGONTed2UaI8sA36lI5sKwvL2j+wOTinw0Pe4A= -github.com/aws/aws-sdk-go-v2/service/transfer v1.67.4/go.mod h1:X1hqrnuqgk5EY3Ic+agUr6P4/CJCrp8HrcC343qi/74= -github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.29.9 h1:NYKTbEwnpUEnfC48JCtlxZe01lwymCCQykJQAk3l5ds= -github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.29.9/go.mod h1:m3YeM8yB49t1fzKYEe43wiowaSO7x/3YmHS/UGOaks8= -github.com/aws/aws-sdk-go-v2/service/vpclattice v1.19.4 h1:xKm2EasIL5Nlt1GTUwzceJwlsWU0bt3aCnrD8e8seNA= -github.com/aws/aws-sdk-go-v2/service/vpclattice v1.19.4/go.mod h1:fp9PvIVx7/jyef3CaWCemFPGK+ghu2Du2XJFGaqc4iE= -github.com/aws/aws-sdk-go-v2/service/waf v1.30.9 h1:C7RzuDKL7ClRunLCUq7YIZ9fm/InzZub4gismnTJ5bk= -github.com/aws/aws-sdk-go-v2/service/waf v1.30.9/go.mod h1:/wwPzZRBcPxG/kAOAzei/UX/FKo2H+aZcx0x99xJPpA= -github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.10 h1:wJ7JtFsctEc/A5XzBQnNPR6inkmc1JrOedkn6kQJjUM= -github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.10/go.mod h1:eaFrizONYIw5QJPDxoBUr8NNM21ISTZDjFhkGVt4NZY= -github.com/aws/aws-sdk-go-v2/service/wafv2 v1.68.4 h1:vcsrFjqOXQnerenkA0/RwskchKgFeP7eJUgOq8X4VSs= -github.com/aws/aws-sdk-go-v2/service/wafv2 v1.68.4/go.mod h1:RtLkquPOQfQASVPWLuXr4hJgaZ5ChNq7eWahkj/CoCQ= -github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.10 h1:vybsh+OcmReX2OnJ5TJa6OixiEH8aCrUchqzAdiv9a8= -github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.10/go.mod h1:t6nyl94d8gQdt34LEo0SH4uGPNruy0T3oMaxcOHdWUU= -github.com/aws/aws-sdk-go-v2/service/workmail v1.36.8 h1:oHtcXkhT12ePAHIaagvFTxtLAI9rtGnwQm/PmvqKCrQ= -github.com/aws/aws-sdk-go-v2/service/workmail v1.36.8/go.mod h1:JW6rMNuboHOnWx7I1fZfHAG1kcUiBZfTkZuD69oNw2w= -github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.2 h1:U1NCC1loRNJZmPyZ4fChpmaXXMNc6Z7sobgKcaIJ8KY= -github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.2/go.mod h1:TmJI48Dm4ftRxBmMoZOeC8Et2WEStJoPpv8BoXZ/eZw= -github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.33.3 h1:79PtELyWQItacygUX3OdYvBBbGuZ4jdhlcRbiTM00tE= -github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.33.3/go.mod h1:V4nPCxgIBn6Yf5JhnI3Cs0iKVTB+wkzXG8fEGYqLYkU= -github.com/aws/aws-sdk-go-v2/service/xray v1.36.9 h1:oxLVMnJFpR7VSUMsPk0Uel0CbVE/tvTQWMp8g1GAuS0= -github.com/aws/aws-sdk-go-v2/service/xray v1.36.9/go.mod h1:JghyUyM7u0syGGk+S5Res2mLfceuyLigCgtcrpsEESM= +github.com/aws/aws-sdk-go-v2/service/quicksight v1.96.2 h1:OLAvMy2oEGGNRh7qjf+cGzupp/dEW57yH4oJ8eLfp9E= +github.com/aws/aws-sdk-go-v2/service/quicksight v1.96.2/go.mod h1:I8KrlgJxmNejc1VR3BWJ+J/uJuoLgaqTS/u/tJHIKA8= +github.com/aws/aws-sdk-go-v2/service/ram v1.34.13 h1:cr/kal5RvNdcBTmjjzOaRoBALpH9I/owczic7k/Ir18= +github.com/aws/aws-sdk-go-v2/service/ram v1.34.13/go.mod h1:XVmWvCpgKVITq+ThzyDzJkCbVycgzv8P8KzdhwijsyQ= +github.com/aws/aws-sdk-go-v2/service/rbin v1.26.13 h1:NHQqKZhCNB6K7hNanxoMKZQ9ZSY7Osg9wJ/4JFmY4lU= +github.com/aws/aws-sdk-go-v2/service/rbin v1.26.13/go.mod h1:HSYlwezMfkOFle385IG72Np892kUVbGvYsdM+BEG+9U= +github.com/aws/aws-sdk-go-v2/service/rds v1.109.0 h1:kAHatNQ1iaWVqVoFcZr5k0+o3dNSrnd+QZRFq4uTvZY= +github.com/aws/aws-sdk-go-v2/service/rds v1.109.0/go.mod h1:mGQNxzRLKlj1cQU5uaMIjAhle0HkSeZDwoPfP+/nRYk= +github.com/aws/aws-sdk-go-v2/service/redshift v1.60.0 h1:Kmh10uuGvak38mlg3FcveihltgP5rXbVcguCj9j3Ms8= +github.com/aws/aws-sdk-go-v2/service/redshift v1.60.0/go.mod h1:nroSRWOCQNS3b/vooHNsxwT5KRXzO+A8ouHyKsQenRc= +github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.12 h1:oGiE4s2UAJmarRMSjui8/um4sqXnk2LFwPL+A1KV3UI= +github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.12/go.mod h1:9beFz0fgqQr+Lkcz0lD54cquuuPUIV54fRbnLDQ7MNI= +github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.15 h1:q9nTCnHFttPjoz2vMC7u35u4jONksuXE060nBOcXD6E= +github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.15/go.mod h1:fgg+LQ1jrDB3K18lra3Qx4tTGCZE9yX+eUQzxUjMhAs= +github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.11 h1:bs3xqr92wJuHiHkNhlkipDe2HSY1LZ4hUkEAek/N4X4= +github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.11/go.mod h1:r0M9WlvDeB2fPsZk2es9ZrjyUNIRPKoxm8xEU+CKbE0= +github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.4 h1:8yORXc5cW+paBUU1f7z41+ZpwMjt4FHUS3kJEC+YQo0= +github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.4/go.mod h1:efsKs5+XMP1JeFtYuLvLfHrBN3GmitdOUgKqDW2Xp9M= +github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.6 h1:kkoaQ06wQZ5AlqoJ+QYaqMs/WSho8Eii+E++PI5g+H8= +github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.6/go.mod h1:3A/lTLOEWLwbIFsOrriZuVdhibD0E4riboU0VaoV1mc= +github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.14 h1:257Y5fn4QZOqofLk8ckt9yJT8LV57lpDEHKO4lchu6U= +github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.14/go.mod h1:6k9FPdJPkYmyrO0PFg1R+k3Rw5RYJT4MGdNqvodIGGY= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.0 h1:W8c1GPeHBlwIeuz+DuwvYaoRBrSDy1Cp8DwXIzXTAWg= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.0/go.mod h1:+nL0z6xUm9NK9bOAkam66NQDgNH8Qa6T6SS3f8dkzXU= +github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.12 h1:voPlA/Poy1EatBhjehk4yVWnC+os9+Wn0VwxAB6aPzs= +github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.12/go.mod h1:/WVeeJKvbKmaTWEtt7y2005MHRKlh+Ee5Nr3qmPMQpY= +github.com/aws/aws-sdk-go-v2/service/route53 v1.60.0 h1:UlmdpHo/xdaEB/80wOqcBVkzsPdmct02FuOfg5Rrd3U= +github.com/aws/aws-sdk-go-v2/service/route53 v1.60.0/go.mod h1:TUbfYOisWZWyT2qjmlMh93ERw1Ry8G4q/yT2Q8TsDag= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.10 h1:+eeUZjA6+GoTYmFjOlfx21du3eljT6fea39jI3TWjDw= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.10/go.mod h1:lxTo/orhKjYQIgzo0ED2KQyU5yC7zPw6vgImZBp5Opc= +github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.12 h1:6W3ERfxp0q+oNMinc59z4Uzcd5vDC4NOsIxFl71CNmI= +github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.12/go.mod h1:Nvyw2yEW8po15FmApho3Biz63mgQirrO6dxseYQb1u8= +github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.5 h1:hT6/2e3FTRRh/QPYW73GRJlLZLH6hqxDn+F76EL1Gxg= +github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.5/go.mod h1:uuKkzsDRNyxWABenHqS3Ms7KoEUf+3EHsNCnMBVMslo= +github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.12 h1:Iury32NIQy7GGFzQzPAUJlydeeo6O+Gf1iheLW8Ax9Y= +github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.12/go.mod h1:FPoma320xUxwC7BRaqJPYjpyIgbuxrAF//JdP9ybfjQ= +github.com/aws/aws-sdk-go-v2/service/route53resolver v1.41.0 h1:8dRPme2++LKhXPTD3VbiCGkwZ1tfPgwjkFwhpiMF1Yk= +github.com/aws/aws-sdk-go-v2/service/route53resolver v1.41.0/go.mod h1:RtTRuj33VUDMd7i7eDEuhX2x69JWtPkWODE2b2TeiS4= +github.com/aws/aws-sdk-go-v2/service/rum v1.30.0 h1:EVwrOhq7sTe0luu/k/blau3VyU4ub/Mkw8yuTbF4yuU= +github.com/aws/aws-sdk-go-v2/service/rum v1.30.0/go.mod h1:aoij2zkJWvNtGzPvyaOZtNazKNjMBEVOmdDystHnh8g= +github.com/aws/aws-sdk-go-v2/service/s3 v1.91.0 h1:b8FQI84BFRqCHjInLKS7bo+iSH8oVJ9C2noKC2H3jwY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.91.0/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw= +github.com/aws/aws-sdk-go-v2/service/s3control v1.66.9 h1:1GWUaLfzsa0AzsRQW3KUNkO1ZnD7ngR1aPedX9HwqxY= +github.com/aws/aws-sdk-go-v2/service/s3control v1.66.9/go.mod h1:c+ERB7DbWT1uR6QvBn7W0gB2YczXacCEoLegFLwPAE8= +github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.3 h1:iCv2rBKUo+ZbWwZW+/sEjmAX+X0HsT9bgs9DqORRaPc= +github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.3/go.mod h1:4XtnGsaxnIiUsurxxTMzn9Wl9/utEAN46rcMPVKLGAM= +github.com/aws/aws-sdk-go-v2/service/s3tables v1.12.0 h1:11XumI/hI9fLn3MXs0rAAzU+c01TPpnXmgDGX2gprVU= +github.com/aws/aws-sdk-go-v2/service/s3tables v1.12.0/go.mod h1:t1l6loaBQWttife9bosS3OspbGv+CP18UbGxMIQie4A= +github.com/aws/aws-sdk-go-v2/service/s3vectors v1.5.2 h1:QX1IetutOdnutzPJ+FD9YnkguYqnIKGv9wDcZLaphWM= +github.com/aws/aws-sdk-go-v2/service/s3vectors v1.5.2/go.mod h1:+sgMaDJqPLY3w2QXsvbhgSlvIaQ4+4cYk6Cdp388Swg= +github.com/aws/aws-sdk-go-v2/service/sagemaker v1.224.0 h1:HJdoaripEfZVveELxCCgNdMsRXc9/5zNNMpr++nB2Lk= +github.com/aws/aws-sdk-go-v2/service/sagemaker v1.224.0/go.mod h1:JnrlXHI1oM/gVNI0/NH1Ru4UZr4sWx/WZclCsJtbmCM= +github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.12 h1:VOBt5H2SeS7yGq7YIOp38dW2cLeEMjIULi68tvP6iE0= +github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.12/go.mod h1:UohrBXfiKjUlaqaMzj3jtBBfrNFSCjq+LLwDbtsvAIo= +github.com/aws/aws-sdk-go-v2/service/schemas v1.34.3 h1:s+siGYfqvmOJGiQJRRz/eUzsDJDZoQ6oN3F5m+AEL0I= +github.com/aws/aws-sdk-go-v2/service/schemas v1.34.3/go.mod h1:ipui3c5k/ozPT734rqfqsFgieDEny9ABk4sp7zCWjkM= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.0 h1:Wm8i2WjGbemRw3adxuKQAbzi3Uq7DgynajCxVnKGQyQ= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.0/go.mod h1:QgVIY03/XoQs2iFr0MbQuQ/Tf1RwlkOvuySWMh1wph4= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.4 h1:PkMuUN9eBC5BrK3msGCz5lajFeCjG8qBJsK3e81pUzo= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.4/go.mod h1:QaXNTOs7OkNR7y9uFWajUymXwUh28Q7cTz3tqWiE6sc= +github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.4 h1:8wd+JhD0YwePy+QiMLpm/jMwNKhN6SdCZTJtB/nDiWI= +github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.4/go.mod h1:8psZ/OINrXmUJhyXWm0NzLaKP5bp1t/dh0/D2Pj/YAo= +github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.3 h1:b6b1QcN9yzuAQw4bq34kAF75u5ToRBFgmTuBC4dnksI= +github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.3/go.mod h1:OmVOd812JbwvNOwaQMpeMmj2bnN6dgUZnVaD1UIvyVg= +github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.3 h1:IcQ+ja++SXCVUvsvp7lKUHZqB+Ee6KhktY4OINyknUs= +github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.3/go.mod h1:fA60HaKYi8WBwj1uf+n2sZkyefVWWUTkKB69Th3pTB0= +github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.12 h1:5f7+VPi0JMU1U0fdmvh4u3h1BzCXYl21S72hMrTTXqk= +github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.12/go.mod h1:H/pz3dQJmZHdKf3DMgD0znZwoP0h8Umx9uPhBRXOkxE= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.16 h1:lzAqM9zMFwAy3ghxjeJfROdwnzO/KCPY8RYEAYpGbCM= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.16/go.mod h1:lYyuDbeQ6vtjRP4gb9h2MReluEb0US5u+07X84akGKg= +github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.7 h1:f0u4ARkdAWxISBgm7RtckKuKHyn8BWprVOLjyM31Loo= +github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.7/go.mod h1:TvpkfbD0qaLoadCivfVCzpgavaEJvmRpG0pzZOo4pX0= +github.com/aws/aws-sdk-go-v2/service/ses v1.34.11 h1:DZpXGSoAP6ZB0//dl31ZkRCrEVwmGzgT6AR86WeThbo= +github.com/aws/aws-sdk-go-v2/service/ses v1.34.11/go.mod h1:CeGX4LAFCsrBp24qazKmO/dwxghNCGbAoTbi64dGSEM= +github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.4 h1:T8XudbCBzHztu2uYYUzlAQhSMxWJVk7zya/7/RLocZE= +github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.4/go.mod h1:uxpQTTvKs2FUajNzmQic0lqMB5X0zjX8jpalkvkhIQI= +github.com/aws/aws-sdk-go-v2/service/sfn v1.40.0 h1:nbTZ7tF36OMkm6anz5M35t9iqRKYGSInHCrHRWMvQQE= +github.com/aws/aws-sdk-go-v2/service/sfn v1.40.0/go.mod h1:fhG61r7sW7WsxXcZAips5CFQta1i2sQwRaEQeQwSrks= +github.com/aws/aws-sdk-go-v2/service/shield v1.34.12 h1:+TCfMnn82wi0zO4NzoqRNHlFIwWn0nQVGYxUZggnSFM= +github.com/aws/aws-sdk-go-v2/service/shield v1.34.12/go.mod h1:6B2EvRYLO2QsWbNoEsxazaKhVufZBDPApqPkpQ2arJI= +github.com/aws/aws-sdk-go-v2/service/signer v1.31.12 h1:HieRc7Lr0KPod0rv7dIa3F51/cGcV5yYCaUZNocJ6SA= +github.com/aws/aws-sdk-go-v2/service/signer v1.31.12/go.mod h1:F44pi85d2IzaTcwWULuLl2cdYjFkKr948NbU7gCmcKY= +github.com/aws/aws-sdk-go-v2/service/sns v1.39.5 h1:SKUhwz9XqabTspg48L5ZTP2D5pdbNHttPFeG0Fljqtg= +github.com/aws/aws-sdk-go-v2/service/sns v1.39.5/go.mod h1:1LvRsmADXI6174y66InuSDQiEztkQgCLbcw62VLC0FQ= +github.com/aws/aws-sdk-go-v2/service/sqs v1.42.15 h1:uoPRUh1/r/E2Vn3Witk0tZppmmsCXmsAuBmx3QorXDk= +github.com/aws/aws-sdk-go-v2/service/sqs v1.42.15/go.mod h1:ZS67woOy/ftzvKK2+P53u2NPqImAPTWz+hBn+tchP7k= +github.com/aws/aws-sdk-go-v2/service/ssm v1.67.2 h1:ybM2UK1Fx4AeurfSGzLKdnjw5j6g6mwVI0Lsr7ZnuEc= +github.com/aws/aws-sdk-go-v2/service/ssm v1.67.2/go.mod h1:uNHuYAQazkHqpD+hVomA2+eDSuKJzerno7Fnha6N6/Y= +github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.5 h1:56hyzh8TcjBUxUNg05wj427i+fBMc2y31grE28B37nI= +github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.5/go.mod h1:m9mkIFFGnEY00U3IpPs/TZLbbgOxARLDtqsDbGqzjik= +github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.11 h1:X3FuvC+O/n15wFyRhUct0uR3u68GvQwpngvFHrZ6d+o= +github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.11/go.mod h1:TUCeZ43VbibNN5TTa0oWium4Cj2ee/Xg93xNRVx+iUw= +github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.12 h1:a03QlxefOXmq1sVd60DDteR70yaT7X2Q2zaXAz2i3Z0= +github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.12/go.mod h1:h/ogxk4gxt67ItMvhzCJSST5AHjaYYuMC/wdLMBLOrI= +github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.11 h1:i2bIm3mt03P2bH1oybSOAID7FRm0IZD2+C5cUMmcYEo= +github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.11/go.mod h1:9/Q7dAszR79doau18RBveSfZX9RASAs4Tubh196QR8A= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 h1:NjShtS1t8r5LUfFVtFeI8xLAHQNTa7UI0VawXlrBMFQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.3/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.8 h1:7g2FaXrm2gJyjcVjyC1jweXVNRhlK9X52wJ7wcUBISA= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.8/go.mod h1:CzDlwLoYGIK0Q7ISrzqCD1/Zgf6nsIdct4f0ZoyKoHI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 h1:gTsnx0xXNQ6SBbymoDvcoRHL+q4l/dAFsQuKfDWSaGc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= +github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.4 h1:bz3k661WLBZIXESAlqqumtcYSQp2m8rjT8m1/b0QLUE= +github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.4/go.mod h1:JKIFhh/dRv/Ft85RarJH3G3ewl419X6gmD/1fEXjDnI= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.0 h1:JoO/STlEltv5nSbzbg709MLNW0/BWgyK2t/R9OWcCyQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.0/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/aws-sdk-go-v2/service/swf v1.33.6 h1:VsuWtkucF7FwWd7cBXwXPx5BOU853UEws1maHKmY0iQ= +github.com/aws/aws-sdk-go-v2/service/swf v1.33.6/go.mod h1:mmUGhXHOTZ0YLexnps/Zn0u5T+p9QkpGRpXuf5L2b7A= +github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.4 h1:XO316jX9V7JywHSsmjhgp19K0NUzFAXbGRUSIl5zABU= +github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.4/go.mod h1:NoN2h4JljGuHzAYWNB3WVGKnuKczRbHoqVh5Z7Z4YdM= +github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.12 h1:m20Zhil+oCtuHCpNrkoG2ihK3xjbsGWJRdv7jX3U2bU= +github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.12/go.mod h1:mch3G+DUo5AjLDfRe7XL3QhVf1K+tk+u1WQiAj5tvzs= +github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.6 h1:wYMxv6TtFtGARWlzQ4IAR8+VbTHB9Lncg+Gi5nB06h4= +github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.6/go.mod h1:ATSASzt7xr2/Xcj8ZjMQg9woL5SyhrghAPCb7nArWVY= +github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.5 h1:qZgibsVrtn0JVsk+g6eb5jQiQFtpvngQMn0MtwMPwz8= +github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.5/go.mod h1:b34PXpekNN9TeyqzUNcFiOEAm3DFd4e+viL/XbQtzuk= +github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.11 h1:ylTUvLe7i1rEk7nTsL1qW2kUIdZSqYw5Jb0XFfnp6H8= +github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.11/go.mod h1:WOhN8208dG/kUp22L0kch06lMtCQJ/+Ypv2W3TTC6vg= +github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.6 h1:2k93IkW8MnhrLQdAJDqKKTL9mjvy7N0GhE8lQi/Gy0A= +github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.6/go.mod h1:juatw/4IEOV9unN2B/ZmVXIGA8YnhDTXzY/ZdIBS11w= +github.com/aws/aws-sdk-go-v2/service/transfer v1.67.6 h1:yJnWTq8tYhxl677goBXEHi/JQ12gQB+yb8JEZQC+Jv8= +github.com/aws/aws-sdk-go-v2/service/transfer v1.67.6/go.mod h1:X1hqrnuqgk5EY3Ic+agUr6P4/CJCrp8HrcC343qi/74= +github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.30.2 h1:OpOUGQJm2fHX/miVu6DS1rlreleaoNihxaxrQFpanLM= +github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.30.2/go.mod h1:m3YeM8yB49t1fzKYEe43wiowaSO7x/3YmHS/UGOaks8= +github.com/aws/aws-sdk-go-v2/service/vpclattice v1.20.2 h1:WLmuDZpc9IlVVKQ+XID+bebCjtbxbrvCfg7Kb6LBiKw= +github.com/aws/aws-sdk-go-v2/service/vpclattice v1.20.2/go.mod h1:fp9PvIVx7/jyef3CaWCemFPGK+ghu2Du2XJFGaqc4iE= +github.com/aws/aws-sdk-go-v2/service/waf v1.30.11 h1:Lq4PpRIWw/3HSansKRRhycylCwp85287783VTCNfJMo= +github.com/aws/aws-sdk-go-v2/service/waf v1.30.11/go.mod h1:/wwPzZRBcPxG/kAOAzei/UX/FKo2H+aZcx0x99xJPpA= +github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.12 h1:kkie0K7P3VOnwJhaaofC4lbJpc82e3rbGKmXW+PjhHE= +github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.12/go.mod h1:eaFrizONYIw5QJPDxoBUr8NNM21ISTZDjFhkGVt4NZY= +github.com/aws/aws-sdk-go-v2/service/wafv2 v1.70.0 h1:mZMnchrgTVjUinijiTKDh0tvz5HhzAoMXfIjOAWpdB4= +github.com/aws/aws-sdk-go-v2/service/wafv2 v1.70.0/go.mod h1:RtLkquPOQfQASVPWLuXr4hJgaZ5ChNq7eWahkj/CoCQ= +github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.12 h1:niwCZWFfIaglbSRA1Cbc7fMCOfsmAfeaWX8ll25sfOI= +github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.12/go.mod h1:t6nyl94d8gQdt34LEo0SH4uGPNruy0T3oMaxcOHdWUU= +github.com/aws/aws-sdk-go-v2/service/workmail v1.36.10 h1:lznZYmkvDu6gHqSKpornaZw2WCwYDN/NYSpfziIgsr8= +github.com/aws/aws-sdk-go-v2/service/workmail v1.36.10/go.mod h1:JW6rMNuboHOnWx7I1fZfHAG1kcUiBZfTkZuD69oNw2w= +github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.4 h1:yX/JSkp/zildXMrGuqm7VRUn+S8an7dZt0Jyy8L6DVg= +github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.4/go.mod h1:TmJI48Dm4ftRxBmMoZOeC8Et2WEStJoPpv8BoXZ/eZw= +github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.34.0 h1:gfDV7Oa2SA+xTJxWZwPiGF/aBew2/OVIGRZ1qipeZ6Q= +github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.34.0/go.mod h1:V4nPCxgIBn6Yf5JhnI3Cs0iKVTB+wkzXG8fEGYqLYkU= +github.com/aws/aws-sdk-go-v2/service/xray v1.36.11 h1:K0g9kBUVHv8da1OpfeLbvteZyTy2dUWBO2ZfwYXw1D8= +github.com/aws/aws-sdk-go-v2/service/xray v1.36.11/go.mod h1:JghyUyM7u0syGGk+S5Res2mLfceuyLigCgtcrpsEESM= github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= @@ -579,8 +579,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/cedar-policy/cedar-go v1.2.9 h1:Wza6MAH6zdr4eYtujcfFoTj8FJbtDHJVjGUl4QpPn14= -github.com/cedar-policy/cedar-go v1.2.9/go.mod h1:h5+3CVW1oI5LXVskJG+my9TFCYI5yjh/+Ul3EJie6MI= +github.com/cedar-policy/cedar-go v1.3.0 h1:QOyZgY1jOFB0si7b6pCFIrqOSVHArUHdeJu8mk070FM= +github.com/cedar-policy/cedar-go v1.3.0/go.mod h1:h5+3CVW1oI5LXVskJG+my9TFCYI5yjh/+Ul3EJie6MI= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= @@ -658,6 +658,8 @@ github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshf github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-set/v3 v3.0.1 h1:ZwO15ZYmIrFYL9zSm2wBuwcRiHxVdp46m/XA/MUlM6I= +github.com/hashicorp/go-set/v3 v3.0.1/go.mod h1:0oPQqhtitglZeT2ZiWnRIfUG6gJAHnn7LzrS7SbgNY4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -702,8 +704,8 @@ github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/jaswdr/faker/v2 v2.8.1 h1:2AcPgHDBXYQregFUH9LgVZKfFupc4SIquYhp29sf5wQ= -github.com/jaswdr/faker/v2 v2.8.1/go.mod h1:jZq+qzNQr8/P+5fHd9t3txe2GNPnthrTfohtnJ7B+68= +github.com/jaswdr/faker/v2 v2.9.0 h1:Sqqpp+pxduDO+MGOhYE3UHtI9Sowt9j95f8h8nVvips= +github.com/jaswdr/faker/v2 v2.9.0/go.mod h1:jZq+qzNQr8/P+5fHd9t3txe2GNPnthrTfohtnJ7B+68= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -763,6 +765,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shoenig/test v1.12.1 h1:mLHfnMv7gmhhP44WrvT+nKSxKkPDiNkIuHGdIGI9RLU= +github.com/shoenig/test v1.12.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= @@ -815,25 +819,25 @@ go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42s golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/exp v0.0.0-20220921023135-46d9e7742f1e h1:Ctm9yurWsg7aWwIpH9Bnap/IdSVxixymIb3MhiMEQQA= golang.org/x/exp v0.0.0-20220921023135-46d9e7742f1e/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -846,25 +850,25 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= diff --git a/infrastructure/repository/main.tf b/infrastructure/repository/main.tf index c4e340248592..55504ce32b0f 100644 --- a/infrastructure/repository/main.tf +++ b/infrastructure/repository/main.tf @@ -13,7 +13,7 @@ terraform { required_providers { github = { source = "integrations/github" - version = "6.7.5" + version = "6.8.3" } } diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go index 629a17e8211b..0428f5ecdedb 100644 --- a/internal/acctest/acctest.go +++ b/internal/acctest/acctest.go @@ -68,6 +68,7 @@ import ( tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" tforganizations "github.com/hashicorp/terraform-provider-aws/internal/service/organizations" tfsts "github.com/hashicorp/terraform-provider-aws/internal/service/sts" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" "github.com/jmespath/go-jmespath" @@ -2225,3 +2226,9 @@ func ExpectErrorAttrAtLeastOneOf(attrs ...string) *regexp.Regexp { func ExpectErrorAttrMinItems(attr string, expected, actual int) *regexp.Regexp { return regexache.MustCompile(fmt.Sprintf(`Attribute %s requires %d\s+item minimum, but config has only %d declared`, attr, expected, actual)) } + +func ListOfStrings[E ~string](s ...E) string { + return strings.Join(tfslices.ApplyToAll(s, func(e E) string { + return strconv.Quote(string(e)) + }), ", ") +} diff --git a/internal/acctest/configs.go b/internal/acctest/configs.go index f5f000e0a245..5e7d1c11a89a 100644 --- a/internal/acctest/configs.go +++ b/internal/acctest/configs.go @@ -752,17 +752,22 @@ resource "aws_iam_role_policy_attachment" "secrets_manager_read_write" { policy_arn = "arn:${data.aws_partition.current.partition}:iam::${data.aws_partition.current.partition}:policy/SecretsManagerReadWrite" } +data "aws_rds_orderable_db_instance" "test" { + engine = "aurora-postgresql" + engine_latest_version = true + preferred_instance_classes = ["db.serverless"] +} + resource "aws_rds_cluster" "test" { cluster_identifier = %[1]q - engine = "aurora-postgresql" - engine_mode = "provisioned" - engine_version = "15.4" - database_name = "test" master_username = "test" manage_master_user_password = true + database_name = "test" + skip_final_snapshot = true + engine = data.aws_rds_orderable_db_instance.test.engine + engine_version = data.aws_rds_orderable_db_instance.test.engine_version enable_http_endpoint = true vpc_security_group_ids = [aws_security_group.test.id] - skip_final_snapshot = true db_subnet_group_name = aws_db_subnet_group.test.name serverlessv2_scaling_configuration { @@ -846,9 +851,10 @@ resource "null_resource" "db_setup" { psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE SCHEMA IF NOT EXISTS bedrock_new;" psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE ROLE bedrock_user WITH PASSWORD '$PGPASSWORD' LOGIN;" psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "GRANT ALL ON SCHEMA bedrock_integration TO bedrock_user;" - psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE TABLE bedrock_integration.bedrock_kb (id uuid PRIMARY KEY, embedding vector(1536), chunks text, metadata json);" + psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE TABLE bedrock_integration.bedrock_kb (id uuid PRIMARY KEY, embedding vector(1536), chunks text, metadata json, custom_metadata jsonb);" psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE INDEX ON bedrock_integration.bedrock_kb USING hnsw (embedding vector_cosine_ops);" psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE INDEX ON bedrock_integration.bedrock_kb USING gin (to_tsvector('simple', chunks));" + psql -h ${aws_rds_cluster.test.endpoint} -U ${aws_rds_cluster.test.master_username} -d ${aws_rds_cluster.test.database_name} -c "CREATE INDEX ON bedrock_integration.bedrock_kb USING gin (custom_metadata);" EOT } } diff --git a/internal/acctest/statecheck/expect_identity_regional_arn_format.go b/internal/acctest/statecheck/expect_identity_regional_arn_format.go index e6faa93e3c1a..eff0c21cbc77 100644 --- a/internal/acctest/statecheck/expect_identity_regional_arn_format.go +++ b/internal/acctest/statecheck/expect_identity_regional_arn_format.go @@ -8,6 +8,8 @@ import ( "fmt" "maps" "slices" + "strconv" + "strings" "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/statecheck" @@ -86,7 +88,7 @@ func ExpectIdentityRegionalARNAlternateRegionFormat(resourceAddress string, arnS // createDeltaString prints the map keys that are present in mapA and not present in mapB func createDeltaString[T any, V any](mapA map[string]T, mapB map[string]V, msgPrefix string) string { - deltaMsg := "" + var deltaMsg strings.Builder deltaMap := make(map[string]T, len(mapA)) maps.Copy(deltaMap, mapA) @@ -98,12 +100,12 @@ func createDeltaString[T any, V any](mapA map[string]T, mapB map[string]V, msgPr for i, k := range deltaKeys { if i == 0 { - deltaMsg += msgPrefix + deltaMsg.WriteString(msgPrefix) } else { - deltaMsg += ", " + deltaMsg.WriteString(", ") } - deltaMsg += fmt.Sprintf("%q", k) + deltaMsg.WriteString(strconv.Quote(k)) } - return deltaMsg + return deltaMsg.String() } diff --git a/internal/acctest/statecheck/full_tags.go b/internal/acctest/statecheck/full_tags.go index c55ddcb058b1..153fac5ae4b7 100644 --- a/internal/acctest/statecheck/full_tags.go +++ b/internal/acctest/statecheck/full_tags.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tfmaps "github.com/hashicorp/terraform-provider-aws/internal/maps" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" tfunique "github.com/hashicorp/terraform-provider-aws/internal/unique" ) @@ -117,7 +117,7 @@ func ExpectFullResourceTags(servicePackage conns.ServicePackage, resourceAddress } } -func ExpectFullResourceTagsSpecTags(servicePackage conns.ServicePackage, resourceAddress string, tagsSpec unique.Handle[types.ServicePackageResourceTags], knownValue knownvalue.Check) expectFullTagsCheck { +func ExpectFullResourceTagsSpecTags(servicePackage conns.ServicePackage, resourceAddress string, tagsSpec unique.Handle[inttypes.ServicePackageResourceTags], knownValue knownvalue.Check) expectFullTagsCheck { return expectFullTagsCheck{ base: NewBase(resourceAddress), knownValue: knownValue, @@ -137,7 +137,7 @@ func ExpectFullDataSourceTags(servicePackage conns.ServicePackage, resourceAddre } } -func ExpectFullDataSourceTagsSpecTags(servicePackage conns.ServicePackage, resourceAddress string, tagsSpec unique.Handle[types.ServicePackageResourceTags], knownValue knownvalue.Check) expectFullTagsCheck { +func ExpectFullDataSourceTagsSpecTags(servicePackage conns.ServicePackage, resourceAddress string, tagsSpec unique.Handle[inttypes.ServicePackageResourceTags], knownValue knownvalue.Check) expectFullTagsCheck { return expectFullTagsCheck{ base: NewBase(resourceAddress), knownValue: knownValue, @@ -147,9 +147,9 @@ func ExpectFullDataSourceTagsSpecTags(servicePackage conns.ServicePackage, resou } } -type tagSpecFinder func(context.Context, conns.ServicePackage, string) unique.Handle[types.ServicePackageResourceTags] +type tagSpecFinder func(context.Context, conns.ServicePackage, string) unique.Handle[inttypes.ServicePackageResourceTags] -func findResourceTagSpec(ctx context.Context, sp conns.ServicePackage, typeName string) (tagsSpec unique.Handle[types.ServicePackageResourceTags]) { +func findResourceTagSpec(ctx context.Context, sp conns.ServicePackage, typeName string) (tagsSpec unique.Handle[inttypes.ServicePackageResourceTags]) { for _, r := range sp.FrameworkResources(ctx) { if r.TypeName == typeName { tagsSpec = r.Tags @@ -167,7 +167,7 @@ func findResourceTagSpec(ctx context.Context, sp conns.ServicePackage, typeName return tagsSpec } -func findDataSourceTagSpec(ctx context.Context, sp conns.ServicePackage, typeName string) (tagsSpec unique.Handle[types.ServicePackageResourceTags]) { +func findDataSourceTagSpec(ctx context.Context, sp conns.ServicePackage, typeName string) (tagsSpec unique.Handle[inttypes.ServicePackageResourceTags]) { for _, r := range sp.FrameworkDataSources(ctx) { if r.TypeName == typeName { tagsSpec = r.Tags @@ -185,8 +185,8 @@ func findDataSourceTagSpec(ctx context.Context, sp conns.ServicePackage, typeNam return tagsSpec } -func identityTagSpec(tagsSpec unique.Handle[types.ServicePackageResourceTags]) tagSpecFinder { - return func(ctx context.Context, sp conns.ServicePackage, typeName string) unique.Handle[types.ServicePackageResourceTags] { +func identityTagSpec(tagsSpec unique.Handle[inttypes.ServicePackageResourceTags]) tagSpecFinder { + return func(ctx context.Context, sp conns.ServicePackage, typeName string) unique.Handle[inttypes.ServicePackageResourceTags] { return tagsSpec } } diff --git a/internal/conns/conns.go b/internal/conns/conns.go index 66256f099b82..c824c3d33b20 100644 --- a/internal/conns/conns.go +++ b/internal/conns/conns.go @@ -7,17 +7,17 @@ import ( "context" "iter" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/vcr" ) // ServicePackage is the minimal interface exported from each AWS service package. // Its methods return the Plugin SDK and Framework resources and data sources implemented in the package. type ServicePackage interface { - FrameworkDataSources(context.Context) []*types.ServicePackageFrameworkDataSource - FrameworkResources(context.Context) []*types.ServicePackageFrameworkResource - SDKDataSources(context.Context) []*types.ServicePackageSDKDataSource - SDKResources(context.Context) []*types.ServicePackageSDKResource + FrameworkDataSources(context.Context) []*inttypes.ServicePackageFrameworkDataSource + FrameworkResources(context.Context) []*inttypes.ServicePackageFrameworkResource + SDKDataSources(context.Context) []*inttypes.ServicePackageSDKDataSource + SDKResources(context.Context) []*inttypes.ServicePackageSDKResource ServicePackageName() string } @@ -25,24 +25,24 @@ type ServicePackage interface { // Actions are imperative operations that can be invoked to perform Day-2 operations. type ServicePackageWithActions interface { ServicePackage - Actions(context.Context) []*types.ServicePackageAction + Actions(context.Context) []*inttypes.ServicePackageAction } // ServicePackageWithEphemeralResources is an interface that extends ServicePackage with ephemeral resources. // Ephemeral resources are resources that are not part of the Terraform state, but are used to create other resources. type ServicePackageWithEphemeralResources interface { ServicePackage - EphemeralResources(context.Context) []*types.ServicePackageEphemeralResource + EphemeralResources(context.Context) []*inttypes.ServicePackageEphemeralResource } type ServicePackageWithFrameworkListResources interface { ServicePackage - FrameworkListResources(context.Context) iter.Seq[*types.ServicePackageFrameworkListResource] + FrameworkListResources(context.Context) iter.Seq[*inttypes.ServicePackageFrameworkListResource] } type ServicePackageWithSDKListResources interface { ServicePackage - SDKListResources(ctx context.Context) iter.Seq[*types.ServicePackageSDKListResource] + SDKListResources(ctx context.Context) iter.Seq[*inttypes.ServicePackageSDKListResource] } type ( diff --git a/internal/flex/flex.go b/internal/flex/flex.go index 164b51c5629e..064a5a1837d8 100644 --- a/internal/flex/flex.go +++ b/internal/flex/flex.go @@ -16,7 +16,7 @@ import ( tfmaps "github.com/hashicorp/terraform-provider-aws/internal/maps" "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/shopspring/decimal" ) @@ -389,7 +389,7 @@ func StringToInt32Value(v *string) int32 { // StringValueToBase64String converts a string to a Go base64 string pointer. func StringValueToBase64String(v string) *string { - return aws.String(itypes.Base64EncodeOnce([]byte(v))) + return aws.String(inttypes.Base64EncodeOnce([]byte(v))) } // StringValueToInt64 converts a string to a Go int32 pointer. diff --git a/internal/framework/flex/autoflex.go b/internal/framework/flex/autoflex.go index dce7baf563c5..1322c7504893 100644 --- a/internal/framework/flex/autoflex.go +++ b/internal/framework/flex/autoflex.go @@ -166,8 +166,9 @@ func autoflexTags(field reflect.StructField) (string, tagOptions) { } type fieldOpts struct { - legacy bool - omitempty bool + legacy bool + omitempty bool + xmlWrapper bool } // valueWithElementsAs extends the Value interface for values that have an ElementsAs method. diff --git a/internal/framework/flex/autoflex_expand.go b/internal/framework/flex/autoflex_expand.go index c76c31ee6d3f..22d543d5499e 100644 --- a/internal/framework/flex/autoflex_expand.go +++ b/internal/framework/flex/autoflex_expand.go @@ -182,19 +182,19 @@ func (expander autoExpander) convert(ctx context.Context, sourcePath path.Path, // Aggregate types. case basetypes.ObjectValuable: - diags.Append(expander.object(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.object(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags case basetypes.ListValuable: - diags.Append(expander.list(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.list(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags case basetypes.MapValuable: - diags.Append(expander.map_(ctx, vFrom, vTo)...) + diags.Append(expander.map_(ctx, vFrom, vTo, fieldOpts)...) return diags case basetypes.SetValuable: - diags.Append(expander.set(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.set(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags } @@ -538,7 +538,7 @@ func (expander autoExpander) string(ctx context.Context, vFrom basetypes.StringV } // string copies a Plugin Framework Object(ish) value to a compatible AWS API value. -func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, vFrom basetypes.ObjectValuable, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, vFrom basetypes.ObjectValuable, targetPath path.Path, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics _, d := vFrom.ToObjectValue(ctx) @@ -588,7 +588,7 @@ func (expander autoExpander) object(ctx context.Context, sourcePath path.Path, v } // list copies a Plugin Framework List(ish) value to a compatible AWS API value. -func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFrom basetypes.ListValuable, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFrom basetypes.ListValuable, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToListValue(ctx) @@ -599,16 +599,16 @@ func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFr switch v.ElementType(ctx).(type) { case basetypes.Int64Typable: - diags.Append(expander.listOrSetOfInt64(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfInt64(ctx, v, vTo, fieldOpts)...) return diags case basetypes.StringTypable: - diags.Append(expander.listOrSetOfString(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfString(ctx, v, vTo, fieldOpts)...) return diags case basetypes.ObjectTypable: if vFrom, ok := vFrom.(fwtypes.NestedObjectCollectionValue); ok { - diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags } } @@ -622,13 +622,13 @@ func (expander autoExpander) list(ctx context.Context, sourcePath path.Path, vFr } // listOrSetOfInt64 copies a Plugin Framework ListOfInt64(ish) or SetOfInt64(ish) value to a compatible AWS API value. -func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct - if isXMLWrapperStruct(vTo.Type()) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(vTo.Type()) { diags.Append(expander.xmlWrapper(ctx, vFrom, vTo, "Items")...) return diags } @@ -701,13 +701,13 @@ func (expander autoExpander) listOrSetOfInt64(ctx context.Context, vFrom valueWi } // listOrSetOfString copies a Plugin Framework ListOfString(ish) or SetOfString(ish) value to a compatible AWS API value. -func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueWithElementsAs, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct - if isXMLWrapperStruct(vTo.Type()) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(vTo.Type()) { diags.Append(expander.xmlWrapper(ctx, vFrom, vTo, "Items")...) return diags } @@ -766,7 +766,7 @@ func (expander autoExpander) listOrSetOfString(ctx context.Context, vFrom valueW } // map_ copies a Plugin Framework Map(ish) value to a compatible AWS API value. -func (expander autoExpander) map_(ctx context.Context, vFrom basetypes.MapValuable, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) map_(ctx context.Context, vFrom basetypes.MapValuable, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToMapValue(ctx) @@ -893,7 +893,7 @@ func (expander autoExpander) mapOfString(ctx context.Context, vFrom basetypes.Ma } // set copies a Plugin Framework Set(ish) value to a compatible AWS API value. -func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFrom basetypes.SetValuable, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFrom basetypes.SetValuable, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics v, d := vFrom.ToSetValue(ctx) @@ -904,16 +904,16 @@ func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFro switch v.ElementType(ctx).(type) { case basetypes.Int64Typable: - diags.Append(expander.listOrSetOfInt64(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfInt64(ctx, v, vTo, fieldOpts)...) return diags case basetypes.StringTypable: - diags.Append(expander.listOrSetOfString(ctx, v, vTo)...) + diags.Append(expander.listOrSetOfString(ctx, v, vTo, fieldOpts)...) return diags case basetypes.ObjectTypable: if vFrom, ok := vFrom.(fwtypes.NestedObjectCollectionValue); ok { - diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo)...) + diags.Append(expander.nestedObjectCollection(ctx, sourcePath, vFrom, targetPath, vTo, fieldOpts)...) return diags } } @@ -927,13 +927,13 @@ func (expander autoExpander) set(ctx context.Context, sourcePath path.Path, vFro } // nestedObjectCollection copies a Plugin Framework NestedObjectCollectionValue value to a compatible AWS API value. -func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourcePath path.Path, vFrom fwtypes.NestedObjectCollectionValue, targetPath path.Path, vTo reflect.Value) diag.Diagnostics { +func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourcePath path.Path, vFrom fwtypes.NestedObjectCollectionValue, targetPath path.Path, vTo reflect.Value, fieldOpts fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch tTo := vTo.Type(); vTo.Kind() { case reflect.Struct: // Check if target is an XML wrapper struct before handling as generic struct - if isXMLWrapperStruct(tTo) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(tTo) { diags.Append(expander.nestedObjectCollectionToXMLWrapper(ctx, sourcePath, vFrom, targetPath, vTo)...) return diags } @@ -947,7 +947,7 @@ func (expander autoExpander) nestedObjectCollection(ctx context.Context, sourceP switch tElem := tTo.Elem(); tElem.Kind() { case reflect.Struct: // Check if target is a pointer to XML wrapper struct - if isXMLWrapperStruct(tElem) { + if fieldOpts.xmlWrapper && isXMLWrapperStruct(tElem) { // Create new instance of the XML wrapper struct newWrapper := reflect.New(tElem) diags.Append(expander.nestedObjectCollectionToXMLWrapper(ctx, sourcePath, vFrom, targetPath, newWrapper.Elem())...) @@ -1221,7 +1221,8 @@ func expandStruct(ctx context.Context, sourcePath path.Path, from any, targetPat }) opts := fieldOpts{ - legacy: fromFieldOpts.Legacy(), + legacy: fromFieldOpts.Legacy(), + xmlWrapper: fromFieldOpts.XMLWrapperField() != "", } diags.Append(flexer.convert(ctx, sourcePath.AtName(fromFieldName), valFrom.FieldByIndex(fromField.Index), targetPath.AtName(toFieldName), toFieldVal, opts)...) @@ -1587,7 +1588,15 @@ func isXMLWrapperStruct(t reflect.Type) bool { return false } - return true + // Items and Quantity should be the only non-anonymous fields + nNonAnonymousFields := 0 + for i := 0; i < t.NumField(); i++ { + if !t.Field(i).Anonymous { + nNonAnonymousFields++ + } + } + + return nNonAnonymousFields == 2 } // nestedObjectCollectionToXMLWrapper converts a NestedObjectCollectionValue to an XML wrapper struct diff --git a/internal/framework/flex/autoflex_flatten.go b/internal/framework/flex/autoflex_flatten.go index a3496004a268..c7f6513bf48f 100644 --- a/internal/framework/flex/autoflex_flatten.go +++ b/internal/framework/flex/autoflex_flatten.go @@ -185,7 +185,7 @@ func (flattener autoFlattener) convert(ctx context.Context, sourcePath path.Path return diags case reflect.Map: - diags.Append(flattener.map_(ctx, sourcePath, vFrom, targetPath, tTo, vTo)...) + diags.Append(flattener.map_(ctx, sourcePath, vFrom, targetPath, tTo, vTo, fieldOpts)...) return diags case reflect.Struct: @@ -193,7 +193,7 @@ func (flattener autoFlattener) convert(ctx context.Context, sourcePath path.Path return diags case reflect.Interface: - diags.Append(flattener.interface_(ctx, vFrom, tTo, vTo)...) + diags.Append(flattener.interface_(ctx, vFrom, tTo, vTo, fieldOpts)...) return diags } @@ -612,7 +612,7 @@ func (flattener autoFlattener) pointer(ctx context.Context, sourcePath path.Path return diags } -func (flattener autoFlattener) interface_(ctx context.Context, vFrom reflect.Value, tTo attr.Type, vTo reflect.Value) diag.Diagnostics { +func (flattener autoFlattener) interface_(ctx context.Context, vFrom reflect.Value, tTo attr.Type, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch tTo := tTo.(type) { @@ -846,7 +846,7 @@ func (flattener autoFlattener) slice(ctx context.Context, sourcePath path.Path, } // map_ copies an AWS API map value to a compatible Plugin Framework value. -func (flattener autoFlattener) map_(ctx context.Context, sourcePath path.Path, vFrom reflect.Value, targetPath path.Path, tTo attr.Type, vTo reflect.Value) diag.Diagnostics { +func (flattener autoFlattener) map_(ctx context.Context, sourcePath path.Path, vFrom reflect.Value, targetPath path.Path, tTo attr.Type, vTo reflect.Value, _ fieldOpts) diag.Diagnostics { var diags diag.Diagnostics switch tMapKey := vFrom.Type().Key(); tMapKey.Kind() { @@ -1731,7 +1731,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa for toField := range tfreflect.ExportedStructFields(typeTo) { toFieldName := toField.Name _, toOpts := autoflexTags(toField) - if wrapperField := toOpts.WrapperField(); wrapperField != "" { + if wrapperField := toOpts.XMLWrapperField(); wrapperField != "" { toFieldVal := valTo.FieldByIndex(toField.Index) if !toFieldVal.CanSet() { continue @@ -1776,7 +1776,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa continue } toFieldName := toField.Name - toNameOverride, toOpts := autoflexTags(toField) + toNameOverride, toFieldOpts := autoflexTags(toField) toFieldVal := valTo.FieldByIndex(toField.Index) if toNameOverride == "-" { tflog.SubsystemTrace(ctx, subsystemName, "Skipping ignored target field", map[string]any{ @@ -1785,7 +1785,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa }) continue } - if toOpts.NoFlatten() { + if toFieldOpts.NoFlatten() { tflog.SubsystemTrace(ctx, subsystemName, "Skipping noflatten target field", map[string]any{ logAttrKeySourceFieldname: fromFieldName, logAttrKeyTargetFieldname: toFieldName, @@ -1807,7 +1807,7 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa }) // Check if target has wrapper tag and source is an XML wrapper struct - if wrapperField := toOpts.WrapperField(); wrapperField != "" { + if wrapperField := toFieldOpts.XMLWrapperField(); wrapperField != "" { fromFieldVal := valFrom.FieldByIndex(fromField.Index) if isXMLWrapperStruct(fromFieldVal.Type()) { tflog.SubsystemTrace(ctx, subsystemName, "Converting XML wrapper struct to collection", map[string]any{ @@ -1836,8 +1836,9 @@ func flattenStruct(ctx context.Context, sourcePath path.Path, from any, targetPa } opts := fieldOpts{ - legacy: toOpts.Legacy(), - omitempty: toOpts.OmitEmpty(), + legacy: toFieldOpts.Legacy(), + omitempty: toFieldOpts.OmitEmpty(), + xmlWrapper: toFieldOpts.XMLWrapperField() != "", } diags.Append(flexer.convert(ctx, sourcePath.AtName(fromFieldName), valFrom.FieldByIndex(fromField.Index), targetPath.AtName(toFieldName), toFieldVal, opts)...) diff --git a/internal/framework/flex/autoflex_maps_test.go b/internal/framework/flex/autoflex_maps_test.go index 025ffc4702d1..574a81a7320c 100644 --- a/internal/framework/flex/autoflex_maps_test.go +++ b/internal/framework/flex/autoflex_maps_test.go @@ -213,7 +213,7 @@ func TestExpandMapBlock(t *testing.T) { }, "map block key list": { Source: &tfMapBlockList{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -242,7 +242,7 @@ func TestExpandMapBlock(t *testing.T) { }, "map block key set": { Source: &tfMapBlockSet{ - MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -329,7 +329,7 @@ func TestExpandMapBlock(t *testing.T) { }, "map block enum key": { Source: &tfMapBlockListEnumKey{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElementEnumKey](ctx, []tfMapBlockElementEnumKey{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElementEnumKey{ { MapBlockKey: fwtypes.StringEnumValue(testEnumList), Attr1: types.StringValue("a"), @@ -359,7 +359,7 @@ func TestExpandMapBlock(t *testing.T) { "map block list no key": { Source: &tfMapBlockListNoKey{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElementNoKey](ctx, []tfMapBlockElementNoKey{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElementNoKey{ { Attr1: types.StringValue("a"), Attr2: types.StringValue("b"), @@ -491,7 +491,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockList{}, WantTarget: &tfMapBlockList{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -511,7 +511,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockSet{}, WantTarget: &tfMapBlockSet{ - MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewSetNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -540,7 +540,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockList{}, WantTarget: &tfMapBlockList{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElement](ctx, []tfMapBlockElement{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElement{ { MapBlockKey: types.StringValue("x"), Attr1: types.StringValue("a"), @@ -580,7 +580,7 @@ func TestFlattenMapBlock(t *testing.T) { }, Target: &tfMapBlockListEnumKey{}, WantTarget: &tfMapBlockListEnumKey{ - MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust[tfMapBlockElementEnumKey](ctx, []tfMapBlockElementEnumKey{ + MapBlock: fwtypes.NewListNestedObjectValueOfValueSliceMust(ctx, []tfMapBlockElementEnumKey{ { MapBlockKey: fwtypes.StringEnumValue(testEnumList), Attr1: types.StringValue("a"), diff --git a/internal/framework/flex/autoflex_nested_test.go b/internal/framework/flex/autoflex_nested_test.go index 18d22d83b64b..3fc3f362f407 100644 --- a/internal/framework/flex/autoflex_nested_test.go +++ b/internal/framework/flex/autoflex_nested_test.go @@ -75,7 +75,7 @@ func TestExpandSimpleSingleNestedBlock(t *testing.T) { ctx := context.Background() testCases := autoFlexTestCases{ "single nested block pointer": { - Source: &tf02{Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, + Source: &tf02{Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, Target: &aws02{}, WantTarget: &aws02{Field1: &aws01{Field1: aws.String("a"), Field2: 1}}, }, @@ -85,7 +85,7 @@ func TestExpandSimpleSingleNestedBlock(t *testing.T) { WantTarget: &aws02{}, }, "single nested block value": { - Source: &tf02{Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, + Source: &tf02{Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{Field1: types.StringValue("a"), Field2: types.Int64Value(1)})}, Target: &aws03{}, WantTarget: &aws03{Field1: aws01{Field1: aws.String("a"), Field2: 1}}, }, @@ -171,10 +171,10 @@ func TestExpandComplexSingleNestedBlock(t *testing.T) { testCases := autoFlexTestCases{ "single nested block pointer": { Source: &tf03{ - Field1: fwtypes.NewObjectValueOfMust[tf02]( + Field1: fwtypes.NewObjectValueOfMust( ctx, &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01]( + Field1: fwtypes.NewObjectValueOfMust( ctx, &tf01{ Field1: types.BoolValue(true), @@ -796,7 +796,7 @@ func TestFlattenSimpleSingleNestedBlock(t *testing.T) { }, Target: &tf02{}, WantTarget: &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{ Field1: types.StringValue("a"), Field2: types.Int64Value(1), }), @@ -817,7 +817,7 @@ func TestFlattenSimpleSingleNestedBlock(t *testing.T) { }, Target: &tf02{}, WantTarget: &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{ Field1: types.StringValue("a"), Field2: types.Int64Value(1), }), @@ -866,8 +866,8 @@ func TestFlattenComplexSingleNestedBlock(t *testing.T) { }, Target: &tf03{}, WantTarget: &tf03{ - Field1: fwtypes.NewObjectValueOfMust[tf02](ctx, &tf02{ - Field1: fwtypes.NewObjectValueOfMust[tf01](ctx, &tf01{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf02{ + Field1: fwtypes.NewObjectValueOfMust(ctx, &tf01{ Field1: types.BoolValue(true), Field2: fwtypes.NewListValueOfMust[types.String](ctx, []attr.Value{ types.StringValue("a"), diff --git a/internal/framework/flex/autoflex_xml_compat_test.go b/internal/framework/flex/autoflex_xml_compat_test.go index 435ca8e00854..630d939eaa3c 100644 --- a/internal/framework/flex/autoflex_xml_compat_test.go +++ b/internal/framework/flex/autoflex_xml_compat_test.go @@ -23,8 +23,8 @@ type FunctionAssociation struct { } type FunctionAssociations struct { - Quantity *int32 - Items []FunctionAssociation + Items []FunctionAssociation `json:"Items"` + Quantity *int32 `json:"Quantity"` } // Terraform model types @@ -34,7 +34,7 @@ type FunctionAssociationTF struct { } type DistributionConfigTF struct { - FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations"` + FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations" autoflex:",xmlwrapper=items"` } type DistributionConfigAWS struct { @@ -132,7 +132,7 @@ type DirectXMLWrapper struct { } type DirectWrapperTF struct { - Items fwtypes.SetValueOf[types.String] `tfsdk:"items"` + Items fwtypes.SetValueOf[types.String] `tfsdk:"items" autoflex:",xmlwrapper=items"` } type DirectWrapperAWS struct { @@ -168,6 +168,11 @@ func TestExpandXMLWrapperDirect(t *testing.T) { func TestIsXMLWrapperStruct(t *testing.T) { t.Parallel() + type embedWithField struct { + Count int64 + } + type embedWithoutField struct{} + testCases := []struct { name string input any @@ -183,6 +188,14 @@ func TestIsXMLWrapperStruct(t *testing.T) { input: DirectXMLWrapper{}, expected: true, }, + { + name: "valid XML wrapper with anonymous struct", + input: struct { + Items []string + Quantity *int32 + }{}, + expected: true, + }, { name: "not a struct", input: "string", @@ -214,6 +227,51 @@ func TestIsXMLWrapperStruct(t *testing.T) { }{}, expected: false, }, + { + name: "struct with extra field", + input: struct { + Items []string + Quantity *int32 + Name string + }{}, + expected: false, + }, + { + name: "struct with anonymous embedWithField", + input: struct { + Items []string + Quantity *int32 + embedWithField + }{}, + expected: true, + }, + { + name: "struct with anonymous embedWithoutField", + input: struct { + Items []string + Quantity *int32 + embedWithoutField + }{}, + expected: true, + }, + { + name: "struct with private embedWithField", + input: struct { + Items []string + Quantity *int32 + private embedWithField + }{}, + expected: false, + }, + { + name: "struct with private embedWithoutField", + input: struct { + Items []string + Quantity *int32 + private embedWithoutField + }{}, + expected: false, + }, } for _, tc := range testCases { @@ -239,23 +297,13 @@ type awsHeadersForFlatten struct { Quantity *int32 } -// CloudFront FunctionAssociation test types -type awsFunctionAssociationsForFlatten struct { - Items []FunctionAssociation `json:"Items"` - Quantity *int32 `json:"Quantity"` -} - -type tfFunctionAssociationsModelForFlatten struct { - FunctionAssociations fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"function_associations" autoflex:",wrapper=items"` -} - // TF model types with wrapper tags (for flattening - AWS to TF) type tfStatusCodesModelForFlatten struct { - StatusCodes fwtypes.SetValueOf[types.Int64] `tfsdk:"status_codes" autoflex:",wrapper=items"` + StatusCodes fwtypes.SetValueOf[types.Int64] `tfsdk:"status_codes" autoflex:",xmlwrapper=items"` } type tfHeadersModelForFlatten struct { - Headers fwtypes.ListValueOf[types.String] `tfsdk:"headers" autoflex:",wrapper=items"` + Headers fwtypes.ListValueOf[types.String] `tfsdk:"headers" autoflex:",xmlwrapper=items"` } func TestFlattenXMLWrapper(t *testing.T) { @@ -291,7 +339,7 @@ func TestFlattenXMLWrapper(t *testing.T) { }, }, "complex type - function associations": { - Source: awsFunctionAssociationsForFlatten{ + Source: FunctionAssociations{ Items: []FunctionAssociation{ { EventType: "viewer-request", @@ -304,22 +352,18 @@ func TestFlattenXMLWrapper(t *testing.T) { }, Quantity: aws.Int32(2), }, - Target: &tfFunctionAssociationsModelForFlatten{}, - WantTarget: &tfFunctionAssociationsModelForFlatten{ - FunctionAssociations: func() fwtypes.SetNestedObjectValueOf[FunctionAssociationTF] { - elems := []*FunctionAssociationTF{ - { - EventType: types.StringValue("viewer-request"), - FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/example-function"), - }, - { - EventType: types.StringValue("viewer-response"), - FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/another-function"), - }, - } - setValue, _ := fwtypes.NewSetNestedObjectValueOfSlice(ctx, elems, nil) - return setValue - }(), + Target: &DistributionConfigTF{}, + WantTarget: &DistributionConfigTF{ + FunctionAssociations: fwtypes.NewSetNestedObjectValueOfSliceMust(ctx, []*FunctionAssociationTF{ + { + EventType: types.StringValue("viewer-request"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/example-function"), + }, + { + EventType: types.StringValue("viewer-response"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/another-function"), + }, + }), }, }, "empty slice to null set": { @@ -336,3 +380,115 @@ func TestFlattenXMLWrapper(t *testing.T) { runAutoFlattenTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) } + +type FunctionAssociationsTF struct { + Items fwtypes.ListNestedObjectValueOf[FunctionAssociationTF] `tfsdk:"items"` + Quantity types.Int64 `tfsdk:"quantity"` +} + +type DistributionConfigTFNoXMLWrapper struct { + FunctionAssociations fwtypes.ListNestedObjectValueOf[FunctionAssociationsTF] `tfsdk:"function_associations"` +} + +func TestExpandNoXMLWrapper(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testCases := autoFlexTestCases{ + "valid function associations": { + Source: DistributionConfigTFNoXMLWrapper{ + FunctionAssociations: fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &FunctionAssociationsTF{ + Items: fwtypes.NewListNestedObjectValueOfSliceMust( + ctx, + []*FunctionAssociationTF{ + { + EventType: types.StringValue("viewer-request"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: types.StringValue("viewer-response"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }, + ), + Quantity: types.Int64Value(2), + }), + }, + Target: &DistributionConfigAWS{}, + WantTarget: &DistributionConfigAWS{ + FunctionAssociations: &FunctionAssociations{ + Quantity: aws.Int32(2), + Items: []FunctionAssociation{ + { + EventType: "viewer-request", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: "viewer-response", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }, + }, + }, + }, + } + + runAutoExpandTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) +} + +func TestFlattenNoXMLWrapper(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + testCases := autoFlexTestCases{ + "complex type - function associations": { + Source: DistributionConfigAWS{ + FunctionAssociations: &FunctionAssociations{ + Quantity: aws.Int32(2), + Items: []FunctionAssociation{ + { + EventType: "viewer-request", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: "viewer-response", + FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }, + }, + }, + // Items: []FunctionAssociation{ + // { + // EventType: "viewer-request", + // FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/example-function"), + // }, + // { + // EventType: "viewer-response", + // FunctionARN: aws.String("arn:aws:cloudfront::123456789012:function/another-function"), + // }, + // }, + // Quantity: aws.Int32(2), + // }, + Target: &DistributionConfigTFNoXMLWrapper{}, + WantTarget: &DistributionConfigTFNoXMLWrapper{ + FunctionAssociations: fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &FunctionAssociationsTF{ + Items: fwtypes.NewListNestedObjectValueOfSliceMust(ctx, []*FunctionAssociationTF{ + { + EventType: types.StringValue("viewer-request"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-1"), + }, + { + EventType: types.StringValue("viewer-response"), + FunctionARN: types.StringValue("arn:aws:cloudfront::123456789012:function/test-function-2"), + }, + }), + Quantity: types.Int64Value(2), + }), + }, + }, + } + + runAutoFlattenTestCases(t, testCases, runChecks{CompareDiags: true, CompareTarget: true, GoldenLogs: true}) +} diff --git a/internal/framework/flex/set_test.go b/internal/framework/flex/set_test.go index d04fe5d1cf04..eb1e0ff4a335 100644 --- a/internal/framework/flex/set_test.go +++ b/internal/framework/flex/set_test.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" ) func TestExpandFrameworkStringValueSet(t *testing.T) { @@ -19,7 +19,7 @@ func TestExpandFrameworkStringValueSet(t *testing.T) { type testCase struct { input types.Set - expected itypes.Set[string] + expected inttypes.Set[string] } tests := map[string]testCase{ "null": { diff --git a/internal/framework/flex/tags.go b/internal/framework/flex/tags.go index 42118c32ce75..9177b43b3755 100644 --- a/internal/framework/flex/tags.go +++ b/internal/framework/flex/tags.go @@ -50,7 +50,7 @@ func (o tagOptions) NoFlatten() bool { return o.Contains("noflatten") } -func (o tagOptions) WrapperField() string { +func (o tagOptions) XMLWrapperField() string { if len(o) == 0 { return "" } @@ -58,7 +58,7 @@ func (o tagOptions) WrapperField() string { for s != "" { var option string option, s, _ = strings.Cut(s, ",") - if name, value, found := strings.Cut(option, "="); found && name == "wrapper" { + if name, value, found := strings.Cut(option, "="); found && name == "xmlwrapper" { return value } } diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden new file mode 100644 index 000000000000..2b6bca7ff6b6 --- /dev/null +++ b/internal/framework/flex/testdata/autoflex/xml_compat/expand_no_xmlwrapper/valid_function_associations.golden @@ -0,0 +1,168 @@ +[ + { + "@level": "info", + "@message": "Expanding", + "@module": "provider.autoflex", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionAssociations", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper", + "autoflex.target.fieldname": "FunctionAssociations", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF]", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Items", + "autoflex.source.path": "FunctionAssociations[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF", + "autoflex.target.fieldname": "Items", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Items", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "trace", + "@message": "Expanding nested object collection", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Items", + "autoflex.source.size": 2, + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "FunctionAssociations[0].Items[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[0]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Items[0].EventType", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "FunctionAssociations.Items[0].EventType", + "autoflex.target.type": "string" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "FunctionAssociations[0].Items[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[0]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Items[0].FunctionARN", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "FunctionAssociations.Items[0].FunctionARN", + "autoflex.target.type": "*string" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "FunctionAssociations[0].Items[1]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[1]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Items[1].EventType", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "FunctionAssociations.Items[1].EventType", + "autoflex.target.type": "string" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "FunctionAssociations[0].Items[1]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[1]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Items[1].FunctionARN", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue", + "autoflex.target.path": "FunctionAssociations.Items[1].FunctionARN", + "autoflex.target.type": "*string" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Quantity", + "autoflex.source.path": "FunctionAssociations[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF", + "autoflex.target.fieldname": "Quantity", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations[0].Quantity", + "autoflex.source.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.Int64Value", + "autoflex.target.path": "FunctionAssociations.Quantity", + "autoflex.target.type": "*int32" + } +] \ No newline at end of file diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden new file mode 100644 index 000000000000..15b240a7e704 --- /dev/null +++ b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_no_xmlwrapper/complex_type__function_associations.golden @@ -0,0 +1,168 @@ +[ + { + "@level": "info", + "@message": "Flattening", + "@module": "provider.autoflex", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionAssociations", + "autoflex.source.path": "", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigAWS", + "autoflex.target.fieldname": "FunctionAssociations", + "autoflex.target.path": "", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTFNoXMLWrapper" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF]" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Items", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.fieldname": "Items", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items", + "autoflex.source.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]" + }, + { + "@level": "trace", + "@message": "Flattening nested object collection", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items", + "autoflex.source.size": 2, + "autoflex.source.type": "[]github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.path": "FunctionAssociations.Items", + "autoflex.target.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/types.ListNestedObjectValueOf[github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF]" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "FunctionAssociations.Items[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[0]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[0].EventType", + "autoflex.source.type": "string", + "autoflex.target.path": "FunctionAssociations.Items[0].EventType", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "FunctionAssociations.Items[0]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[0]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[0].FunctionARN", + "autoflex.source.type": "*string", + "autoflex.target.path": "FunctionAssociations.Items[0].FunctionARN", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "EventType", + "autoflex.source.path": "FunctionAssociations.Items[1]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "EventType", + "autoflex.target.path": "FunctionAssociations.Items[1]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[1].EventType", + "autoflex.source.type": "string", + "autoflex.target.path": "FunctionAssociations.Items[1].EventType", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "FunctionARN", + "autoflex.source.path": "FunctionAssociations.Items[1]", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociation", + "autoflex.target.fieldname": "FunctionARN", + "autoflex.target.path": "FunctionAssociations.Items[1]", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Items[1].FunctionARN", + "autoflex.source.type": "*string", + "autoflex.target.path": "FunctionAssociations.Items[1].FunctionARN", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.StringValue" + }, + { + "@level": "trace", + "@message": "Matched fields", + "@module": "provider.autoflex", + "autoflex.source.fieldname": "Quantity", + "autoflex.source.path": "FunctionAssociations", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.fieldname": "Quantity", + "autoflex.target.path": "FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociationsTF" + }, + { + "@level": "info", + "@message": "Converting", + "@module": "provider.autoflex", + "autoflex.source.path": "FunctionAssociations.Quantity", + "autoflex.source.type": "*int32", + "autoflex.target.path": "FunctionAssociations.Quantity", + "autoflex.target.type": "github.com/hashicorp/terraform-plugin-framework/types/basetypes.Int64Value" + } +] \ No newline at end of file diff --git a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden index bad79202da75..e481e95568ce 100644 --- a/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden +++ b/internal/framework/flex/testdata/autoflex/xml_compat/flatten_xmlwrapper/complex_type__function_associations.golden @@ -3,27 +3,27 @@ "@level": "info", "@message": "Flattening", "@module": "provider.autoflex", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten" + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF" }, { "@level": "info", "@message": "Converting", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten" + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF" }, { "@level": "trace", "@message": "Converting entire XML wrapper struct to collection field", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "flex.FunctionAssociations", "autoflex.target.fieldname": "FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "wrapper_field": "items" }, { @@ -31,10 +31,10 @@ "@message": "Starting XML wrapper flatten", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", - "source_type": "flex.awsFunctionAssociationsForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", + "source_type": "flex.FunctionAssociations", "target_type": "SetNestedObjectTypeOf[flex.FunctionAssociationTF]", "wrapper_field": "items" }, @@ -43,9 +43,9 @@ "@message": "Found Items field", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "items_is_nil": false, "items_kind": "slice", "items_len": 2, @@ -56,9 +56,9 @@ "@message": "Using target element type", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "element_type": "ObjectTypeOf[flex.FunctionAssociationTF]" }, { @@ -66,9 +66,9 @@ "@message": "Converting items to set elements", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "items_count": 2 }, { @@ -76,9 +76,9 @@ "@message": "Processing item", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "index": 0, "item_kind": "struct", "item_value": { @@ -140,9 +140,9 @@ "@message": "Processing item", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "index": 1, "item_kind": "struct", "item_value": { @@ -204,10 +204,10 @@ "@message": "Creating set value", "@module": "provider.autoflex", "autoflex.source.path": "", - "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.awsFunctionAssociationsForFlatten", + "autoflex.source.type": "github.com/hashicorp/terraform-provider-aws/internal/framework/flex.FunctionAssociations", "autoflex.target.path": "", - "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.tfFunctionAssociationsModelForFlatten", + "autoflex.target.type": "*github.com/hashicorp/terraform-provider-aws/internal/framework/flex.DistributionConfigTF", "element_count": 2, "element_type": "ObjectTypeOf[flex.FunctionAssociationTF]" } -] \ No newline at end of file +] diff --git a/internal/framework/types/cidr_block.go b/internal/framework/types/cidr_block.go index 976dc6557d22..bf3f5842964e 100644 --- a/internal/framework/types/cidr_block.go +++ b/internal/framework/types/cidr_block.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-go/tftypes" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" ) var ( @@ -53,7 +53,7 @@ func (t cidrBlockType) ValueFromString(_ context.Context, in types.String) (base } valueString := in.ValueString() - if err := itypes.ValidateCIDRBlock(valueString); err != nil { + if err := inttypes.ValidateCIDRBlock(valueString); err != nil { return CIDRBlockUnknown(), diags // Must not return validation errors } @@ -126,7 +126,7 @@ func (v CIDRBlock) ValidateAttribute(ctx context.Context, req xattr.ValidateAttr return } - if err := itypes.ValidateCIDRBlock(v.ValueString()); err != nil { + if err := inttypes.ValidateCIDRBlock(v.ValueString()); err != nil { resp.Diagnostics.AddAttributeError( req.Path, "Invalid CIDR Block Value", diff --git a/internal/framework/validators/aws_account_id.go b/internal/framework/validators/aws_account_id.go index 9aba4a671254..eb98324f84ee 100644 --- a/internal/framework/validators/aws_account_id.go +++ b/internal/framework/validators/aws_account_id.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" "github.com/hashicorp/terraform-plugin-framework/schema/validator" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" ) // awsAccountIDValidator validates that a string Attribute's value is a valid AWS account ID. @@ -31,7 +31,7 @@ func (validator awsAccountIDValidator) ValidateString(ctx context.Context, reque } // https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-identifiers.html. - if !itypes.IsAWSAccountID(request.ConfigValue.ValueString()) { + if !inttypes.IsAWSAccountID(request.ConfigValue.ValueString()) { response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( request.Path, validator.Description(ctx), diff --git a/internal/generate/acctestconsts/main.go b/internal/generate/acctestconsts/main.go index 65c4094aa809..da0ee56e3df8 100644 --- a/internal/generate/acctestconsts/main.go +++ b/internal/generate/acctestconsts/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/attrconsts/main.go b/internal/generate/attrconsts/main.go index 2383ace03aa1..4dfd11829aaa 100644 --- a/internal/generate/attrconsts/main.go +++ b/internal/generate/attrconsts/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/awsclient/main.go b/internal/generate/awsclient/main.go index f0b7ab2a05de..856381c33942 100644 --- a/internal/generate/awsclient/main.go +++ b/internal/generate/awsclient/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/checknames/main.go b/internal/generate/checknames/main.go index 99e63adae1ee..08937bb71172 100644 --- a/internal/generate/checknames/main.go +++ b/internal/generate/checknames/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/customendsfwschema/main.go b/internal/generate/customendsfwschema/main.go index 2757173eae66..60d6b1d69934 100644 --- a/internal/generate/customendsfwschema/main.go +++ b/internal/generate/customendsfwschema/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/customendsschema/main.go b/internal/generate/customendsschema/main.go index decd28379782..4d0103507bba 100644 --- a/internal/generate/customendsschema/main.go +++ b/internal/generate/customendsschema/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/identitytests/main.go b/internal/generate/identitytests/main.go index 37ac755196b9..113f91e3061d 100644 --- a/internal/generate/identitytests/main.go +++ b/internal/generate/identitytests/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main @@ -381,7 +380,7 @@ type ResourceDatum struct { ARNFormat string arnAttribute string isARNFormatGlobal triBoolean - ArnIdentity bool + isARNIdentity bool MutableIdentity bool IsGlobal bool isSingleton bool @@ -395,7 +394,6 @@ type ResourceDatum struct { HasNoPreExistingResource bool PreIdentityVersion *version.Version IsCustomInherentRegionIdentity bool - customIdentityAttribute string IdentityVersions map[int64]*version.Version tests.CommonArgs } @@ -425,7 +423,11 @@ func (d ResourceDatum) IDAttrDuplicates() string { } func (d ResourceDatum) IsARNIdentity() bool { - return d.ArnIdentity + return d.isARNIdentity +} + +func (d ResourceDatum) IsGlobalARNFormatForRegionalResource() bool { + return d.isARNIdentity && !d.IsGlobal && d.IsARNFormatGlobal() } func (d ResourceDatum) ARNAttribute() string { @@ -448,7 +450,11 @@ func (d ResourceDatum) GenerateRegionOverrideTest() bool { return !d.IsGlobal && d.HasRegionOverrideTest } -func (d ResourceDatum) HasInherentRegion() bool { +func (d ResourceDatum) HasInherentRegionIdentity() bool { + return d.IsARNIdentity() || d.IsCustomInherentRegionIdentity +} + +func (d ResourceDatum) HasInherentRegionImportID() bool { return d.IsARNIdentity() || d.IsRegionalSingleton() || d.IsCustomInherentRegionIdentity } @@ -468,10 +474,6 @@ func (r ResourceDatum) IdentityAttributes() []identityAttribute { return r.identityAttributes } -func (r ResourceDatum) CustomIdentityAttribute() string { - return namesgen.ConstOrQuote(r.customIdentityAttribute) -} - func (r ResourceDatum) LatestIdentityVersion() int64 { if len(r.IdentityVersions) == 0 { return 0 @@ -625,7 +627,7 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) { case "ArnIdentity": hasIdentity = true - d.ArnIdentity = true + d.isARNIdentity = true args := common.ParseArgs(m[3]) if len(args.Positional) == 0 { d.arnAttribute = "arn" @@ -635,18 +637,15 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) { d.identityAttribute = args.Positional[0] } - var attrs []string - if attr, ok := args.Keyword["identityDuplicateAttributes"]; ok { - attrs = strings.Split(attr, ";") - } - if d.Implementation == tests.ImplementationSDK { - attrs = append(attrs, "id") - } - slices.Sort(attrs) - attrs = slices.Compact(attrs) - d.IdentityDuplicateAttrs = tfslices.ApplyToAll(attrs, func(s string) string { - return namesgen.ConstOrQuote(s) - }) + populateInherentRegionIdentity(&d, args) + + case "CustomInherentRegionIdentity": + hasIdentity = true + d.IsCustomInherentRegionIdentity = true + args := common.ParseArgs(m[3]) + d.identityAttribute = args.Positional[0] + + populateInherentRegionIdentity(&d, args) case "IdentityAttribute": hasIdentity = true @@ -744,27 +743,6 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) { } } - case "CustomInherentRegionIdentity": - hasIdentity = true - d.IsCustomInherentRegionIdentity = true - - args := common.ParseArgs(m[3]) - d.customIdentityAttribute = args.Positional[0] - d.identityAttribute = args.Positional[0] - - var attrs []string - if attr, ok := args.Keyword["identityDuplicateAttributes"]; ok { - attrs = strings.Split(attr, ";") - } - if d.Implementation == tests.ImplementationSDK { - attrs = append(attrs, "id") - } - slices.Sort(attrs) - attrs = slices.Compact(attrs) - d.IdentityDuplicateAttrs = tfslices.ApplyToAll(attrs, func(s string) string { - return namesgen.ConstOrQuote(s) - }) - case "Testing": args := common.ParseArgs(m[3]) @@ -913,10 +891,6 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) { d.HasRegionOverrideTest = false } - if len(d.identityAttributes) == 1 { - d.identityAttribute = d.identityAttributes[0].name - } - if hasIdentity { if !skip { if d.idAttrDuplicates != "" { @@ -995,3 +969,22 @@ func generateTestConfig(g *common.Generator, dirPath, test string, tfTemplates * g.Fatalf("generating file (%s): %s", mainPath, err) } } + +func populateInherentRegionIdentity(d *ResourceDatum, args common.Args) { + var attrs []string + if attr, ok := args.Keyword["identityDuplicateAttributes"]; ok { + attrs = strings.Split(attr, ";") + } + if d.Implementation == tests.ImplementationSDK { + attrs = append(attrs, "id") + } else { + if !slices.Contains(attrs, "id") { + d.SetImportStateIDAttribute(d.identityAttribute) + } + } + slices.Sort(attrs) + attrs = slices.Compact(attrs) + d.IdentityDuplicateAttrs = tfslices.ApplyToAll(attrs, func(s string) string { + return namesgen.ConstOrQuote(s) + }) +} diff --git a/internal/generate/identitytests/resource_test.go.gtpl b/internal/generate/identitytests/resource_test.go.gtpl index e0cf4fc076bd..c95179548826 100644 --- a/internal/generate/identitytests/resource_test.go.gtpl +++ b/internal/generate/identitytests/resource_test.go.gtpl @@ -119,16 +119,16 @@ ImportPlanChecks: resource.ImportPlanChecks{ {{ else if eq .PlannableResourceAction "Replace" -}} plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), {{ end -}} - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} {{ if eq .PlannableResourceAction "Replace" -}} - plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ if .HasIdentityDuplicateAttrs -}} {{ range .IdentityDuplicateAttrs -}} plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New({{ . }})), {{ end -}} {{ end -}} {{ else -}} - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .ARNAttribute }}), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .IdentityAttribute }}), knownvalue.NotNull()), {{ if .HasIdentityDuplicateAttrs -}} {{ range .IdentityDuplicateAttrs -}} plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ . }}), knownvalue.NotNull()), @@ -146,13 +146,6 @@ ImportPlanChecks: resource.ImportPlanChecks{ {{ range .IdentityAttributes -}} plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .Name }}), knownvalue.NotNull()), {{ end -}} - {{ else if ne .IdentityAttribute "" -}} - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .IdentityAttribute }}), knownvalue.NotNull()), - {{ if .HasIdentityDuplicateAttrs -}} - {{ range .IdentityDuplicateAttrs -}} - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ . }}), knownvalue.NotNull()), - {{ end -}} - {{ end -}} {{ end -}} {{ if not .IsGlobal -}} plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), @@ -169,16 +162,16 @@ ImportPlanChecks: resource.ImportPlanChecks{ {{ else if eq .PlannableResourceAction "Replace" -}} plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), {{ end -}} - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} {{ if eq .PlannableResourceAction "Replace" -}} - plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ if .HasIdentityDuplicateAttrs -}} {{ range .IdentityDuplicateAttrs -}} plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New({{ . }})), {{ end -}} {{ end -}} {{ else -}} - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .ARNAttribute }}), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .IdentityAttribute }}), knownvalue.NotNull()), {{ if .HasIdentityDuplicateAttrs -}} {{ range .IdentityDuplicateAttrs -}} plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ . }}), knownvalue.NotNull()), @@ -193,13 +186,6 @@ ImportPlanChecks: resource.ImportPlanChecks{ {{ range .IdentityAttributes -}} plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .Name }}), knownvalue.NotNull()), {{ end -}} - {{ else if ne .IdentityAttribute "" -}} - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ .IdentityAttribute }}), knownvalue.NotNull()), - {{ if .HasIdentityDuplicateAttrs -}} - {{ range .IdentityDuplicateAttrs -}} - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New({{ . }}), knownvalue.NotNull()), - {{ end -}} - {{ end -}} {{ end -}} {{ if not .IsGlobal -}} plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), @@ -297,24 +283,19 @@ func {{ template "testname" . }}_Identity_Basic(t *testing.T) { {{ if not .IsGlobal -}} statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), {{ end -}} - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} + {{ if .IsGlobalARNFormatForRegionalResource -}} names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -423,24 +404,19 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New({{ .IDAttrDuplicates }}), compare.ValuesSame()), {{ end -}} statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -458,7 +434,7 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, {{ if not .NoImport }} - {{ if .HasInherentRegion }} + {{ if .HasInherentRegionImportID }} // Step {{ ($step = inc $step) | print }}: Import command with appended "@" {{- else }} // Step {{ ($step = inc $step) | print }}: Import command @@ -475,7 +451,7 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, {{- template "ImportCommandWithIDBodyCrossRegion" . -}} }, - {{ if .HasInherentRegion }} + {{ if .HasInherentRegionImportID }} // Step {{ ($step = inc $step) | print }}: Import command without appended "@" { {{ if .UseAlternateAccount -}} @@ -490,7 +466,7 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { {{- template "ImportCommandWithIDBody" . -}} }, {{ end }} - {{ if .HasInherentRegion }} + {{ if .HasInherentRegionImportID }} // Step {{ ($step = inc $step) | print }}: Import block with Import ID and appended "@" {{- else }} // Step {{ ($step = inc $step) | print }}: Import block with Import ID @@ -511,7 +487,7 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { ExpectNonEmptyPlan: true, {{ end -}} }, - {{ if .HasInherentRegion }} + {{ if .HasInherentRegionImportID }} // Step {{ ($step = inc $step) | print }}: Import block with Import ID and no appended "@" { {{ if .UseAlternateAccount -}} @@ -600,14 +576,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -617,11 +593,6 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -664,14 +635,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { ), {{ end -}} ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -722,14 +693,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -739,11 +710,6 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -811,12 +777,12 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.Null(), + {{ .IdentityAttribute }}: knownvalue.Null(), }), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ @@ -858,14 +824,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -875,11 +841,6 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -999,14 +960,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1016,11 +977,6 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1155,14 +1111,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1212,14 +1168,14 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1229,11 +1185,6 @@ func {{ template "testname" . }}_Identity_RegionOverride(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1357,14 +1308,14 @@ func {{ template "testname" . }}_Identity_Upgrade(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1374,11 +1325,6 @@ func {{ template "testname" . }}_Identity_Upgrade(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1455,14 +1401,14 @@ func {{ template "testname" . }}_Identity_Upgrade_NoRefresh(t *testing.T) { }, }, ConfigStateChecks: []statecheck.StateCheck{ - {{ if .ArnIdentity -}} + {{ if .HasInherentRegionIdentity -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ if and (not .IsGlobal) .IsARNFormatGlobal -}} - names.AttrRegion: knownvalue.StringExact(acctest.Region()), + {{ if .IsGlobalARNFormatForRegionalResource -}} + names.AttrRegion: knownvalue.StringExact(acctest.Region()), {{ end -}} - {{ .ARNAttribute }}: knownvalue.NotNull(), + {{ .IdentityAttribute }}: knownvalue.NotNull(), }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .ARNAttribute }})), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .IdentityAttribute }})), {{ else if .IsRegionalSingleton -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), @@ -1472,11 +1418,6 @@ func {{ template "testname" . }}_Identity_Upgrade_NoRefresh(t *testing.T) { statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), }), - {{ else if .IsCustomInherentRegionIdentity -}} - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - {{ .CustomIdentityAttribute }}: knownvalue.NotNull(), - }), - statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New({{ .CustomIdentityAttribute }})), {{ else -}} statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), diff --git a/internal/generate/issuelabels/main.go b/internal/generate/issuelabels/main.go index 314c6a085d42..f0b3928f735d 100644 --- a/internal/generate/issuelabels/main.go +++ b/internal/generate/issuelabels/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/listpages/main.go b/internal/generate/listpages/main.go index c5d3e8dcbb91..f1cecee48982 100644 --- a/internal/generate/listpages/main.go +++ b/internal/generate/listpages/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/namescapslist/main.go b/internal/generate/namescapslist/main.go index fa1f12a62ede..789bd403dd03 100644 --- a/internal/generate/namescapslist/main.go +++ b/internal/generate/namescapslist/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/namesconsts/main.go b/internal/generate/namesconsts/main.go index 7673c1153b72..c778638579c0 100644 --- a/internal/generate/namesconsts/main.go +++ b/internal/generate/namesconsts/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/namevaluesfilters/main.go b/internal/generate/namevaluesfilters/main.go index 41e2ecfe71bc..40e446e29459 100644 --- a/internal/generate/namevaluesfilters/main.go +++ b/internal/generate/namevaluesfilters/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/prlabels/main.go b/internal/generate/prlabels/main.go index e0b9dd194641..089876e6674e 100644 --- a/internal/generate/prlabels/main.go +++ b/internal/generate/prlabels/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/serviceendpointtests/main.go b/internal/generate/serviceendpointtests/main.go index 8bd315c17075..88719eec3771 100644 --- a/internal/generate/serviceendpointtests/main.go +++ b/internal/generate/serviceendpointtests/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/servicelabels/main.go b/internal/generate/servicelabels/main.go index c7c6f801cd6b..ffbdf7b41e2c 100644 --- a/internal/generate/servicelabels/main.go +++ b/internal/generate/servicelabels/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/servicepackage/main.go b/internal/generate/servicepackage/main.go index 0f6a0c6a9bae..5f346eb02505 100644 --- a/internal/generate/servicepackage/main.go +++ b/internal/generate/servicepackage/main.go @@ -238,6 +238,7 @@ type ResourceDatum struct { HasV6_0SDKv2Fix bool HasIdentityFix bool IdentityVersion int64 + SDKv2IdentityUpgraders []string CustomInherentRegionIdentity bool customIdentityAttribute string CustomInherentRegionParser string @@ -565,6 +566,11 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) { d.IdentityVersion = i } + if attr, ok := args.Keyword["sdkV2IdentityUpgraders"]; ok { + attrs := strings.Split(attr, ";") + d.SDKv2IdentityUpgraders = attrs + } + case "CustomInherentRegionIdentity": d.CustomInherentRegionIdentity = true d.WrappedImport = true diff --git a/internal/generate/servicepackage/service_package_gen.go.gtpl b/internal/generate/servicepackage/service_package_gen.go.gtpl index 9655b6390449..71da93ebe911 100644 --- a/internal/generate/servicepackage/service_package_gen.go.gtpl +++ b/internal/generate/servicepackage/service_package_gen.go.gtpl @@ -29,6 +29,12 @@ inttypes.StringIdentityAttribute( {{- if .HasIdentityFix }} inttypes.WithIdentityFix(), {{ end -}} +{{- if .IdentityVersion }} + inttypes.WithVersion({{ .IdentityVersion }}), +{{ end -}} +{{- if gt (len .SDKv2IdentityUpgraders) 0 -}} + inttypes.WithSDKv2IdentityUpgraders({{- range .SDKv2IdentityUpgraders -}}{{.}},{{- end -}}), +{{ end -}} {{- end }} package {{ .ProviderPackage }} @@ -452,9 +458,6 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa {{- end }} {{- if $value.HasResourceIdentity }} Identity: - {{- if $value.IdentityVersion }} - inttypes.VersionedIdentity({{ $value.IdentityVersion }}, - {{- end -}} {{- if gt (len $value.IdentityAttributes) 1 }} {{- if or $.IsGlobal $value.IsGlobal }} inttypes.GlobalParameterizedIdentity([]inttypes.IdentityAttribute{ @@ -522,9 +525,6 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa {{- template "SDKv2CommonIdentityOpts" . }} ), {{- end -}} - {{- if $value.IdentityVersion -}} - ), - {{- end }} {{- end }} {{- if $value.WrappedImport }} Import: inttypes.SDKv2Import{ @@ -574,9 +574,6 @@ func (p *servicePackage) SDKListResources(ctx context.Context) iter.Seq[*inttype {{- end }} {{- if $value.HasResourceIdentity }} Identity: - {{- if $value.IdentityVersion }} - inttypes.VersionedIdentity({{ $value.IdentityVersion }}, - {{- end -}} {{- if gt (len $value.IdentityAttributes) 1 }} {{- if or $.IsGlobal $value.IsGlobal }} inttypes.GlobalParameterizedIdentity([]inttypes.IdentityAttribute{ @@ -660,9 +657,6 @@ func (p *servicePackage) SDKListResources(ctx context.Context) iter.Seq[*inttype {{- template "SDKv2CommonIdentityOpts" . }} ), {{- end -}} - {{- if $value.IdentityVersion }} - ), - {{- end }} {{- end }} }, {{- end }} diff --git a/internal/generate/servicepackages/main.go b/internal/generate/servicepackages/main.go index 780705e2290b..697c450a96f6 100644 --- a/internal/generate/servicepackages/main.go +++ b/internal/generate/servicepackages/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/servicesemgrep/main.go b/internal/generate/servicesemgrep/main.go index d1c932557158..f37ffa88ddc7 100644 --- a/internal/generate/servicesemgrep/main.go +++ b/internal/generate/servicesemgrep/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/sweeperregistration/main.go b/internal/generate/sweeperregistration/main.go index 290ed096fdd3..d1059ea6f58e 100644 --- a/internal/generate/sweeperregistration/main.go +++ b/internal/generate/sweeperregistration/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/tagresource/main.go b/internal/generate/tagresource/main.go index c7b00e8e960a..91e3b2493842 100644 --- a/internal/generate/tagresource/main.go +++ b/internal/generate/tagresource/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/tags/main.go b/internal/generate/tags/main.go index 5d5683354c94..bac1a0d3fd55 100644 --- a/internal/generate/tags/main.go +++ b/internal/generate/tags/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/tagstests/data_source_test.go.gtpl b/internal/generate/tagstests/data_source_test.go.gtpl index 7474cab3e787..bc946cb77518 100644 --- a/internal/generate/tagstests/data_source_test.go.gtpl +++ b/internal/generate/tagstests/data_source_test.go.gtpl @@ -43,7 +43,7 @@ import ( {{- if .OverrideIdentifier }} tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tf{{ .ProviderPackage }} "github.com/hashicorp/terraform-provider-aws/internal/service/{{ .ProviderPackage }}" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" {{- end }} {{ range .GoImports -}} {{ if .Alias }}{{ .Alias }} {{ end }}"{{ .Path }}" @@ -263,7 +263,7 @@ func {{ template "testname" . }}_tags_IgnoreTags_Overlap_ResourceTag(t *testing. {{ if .OverrideIdentifier }} func {{ template "expectFullDataSourceTags" . }}(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tf{{ .ProviderPackage }}.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tf{{ .ProviderPackage }}.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: {{ .OverrideIdentifierAttribute }}, {{ if ne .OverrideResourceType "" -}} ResourceType: "{{ .OverrideResourceType }}", diff --git a/internal/generate/tagstests/main.go b/internal/generate/tagstests/main.go index e41ffefd55a5..bee4f6ce4b60 100644 --- a/internal/generate/tagstests/main.go +++ b/internal/generate/tagstests/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main @@ -403,6 +402,8 @@ type ResourceDatum struct { overrideIdentifierAttribute string OverrideResourceType string tests.CommonArgs + isARNIdentity bool + identityAttribute string } func (d ResourceDatum) ProviderPackage() string { @@ -579,6 +580,17 @@ func (v *visitor) processFuncDecl(funcDecl *ast.FuncDecl) { case "NoImport": d.NoImport = true + case "ArnIdentity": + d.isARNIdentity = true + args := common.ParseArgs(m[3]) + if len(args.Positional) == 0 { + d.identityAttribute = "arn" + } else { + d.identityAttribute = args.Positional[0] + } + + populateInherentRegionIdentity(&d, args) + case "Testing": args := common.ParseArgs(m[3]) @@ -763,3 +775,19 @@ func count[T any](s iter.Seq[T], f func(T) bool) (c int) { } return c } + +func populateInherentRegionIdentity(d *ResourceDatum, args common.Args) { + var attrs []string + if attr, ok := args.Keyword["identityDuplicateAttributes"]; ok { + attrs = strings.Split(attr, ";") + } + if d.Implementation == tests.ImplementationSDK { + attrs = append(attrs, "id") + } else { + if !slices.Contains(attrs, "id") { + d.SetImportStateIDAttribute(d.identityAttribute) + } + } + slices.Sort(attrs) + attrs = slices.Compact(attrs) +} diff --git a/internal/generate/tagstests/resource_test.go.gtpl b/internal/generate/tagstests/resource_test.go.gtpl index e81e991736dc..eb40f0a2b08f 100644 --- a/internal/generate/tagstests/resource_test.go.gtpl +++ b/internal/generate/tagstests/resource_test.go.gtpl @@ -103,7 +103,7 @@ import ( {{- if .OverrideIdentifier }} tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tf{{ .ProviderPackage }} "github.com/hashicorp/terraform-provider-aws/internal/service/{{ .ProviderPackage }}" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" {{- end }} {{ range .GoImports -}} {{ if .Alias }}{{ .Alias }} {{ end }}"{{ .Path }}" @@ -3037,7 +3037,7 @@ func testAcc{{ .ResourceProviderNameUpper }}{{ .Name }}_removingTagNotSupported( {{ if .OverrideIdentifier }} func {{ template "expectFullResourceTags" . }}(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullResourceTagsSpecTags(tf{{ .ProviderPackage }}.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullResourceTagsSpecTags(tf{{ .ProviderPackage }}.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: {{ .OverrideIdentifierAttribute }}, {{ if ne .OverrideResourceType "" -}} ResourceType: "{{ .OverrideResourceType }}", diff --git a/internal/generate/teamcity/provider_tests.go b/internal/generate/teamcity/provider_tests.go index fe87aaa31466..9d609691131b 100644 --- a/internal/generate/teamcity/provider_tests.go +++ b/internal/generate/teamcity/provider_tests.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/teamcity/services.go b/internal/generate/teamcity/services.go index c22fc8dd5f34..2d7829df024c 100644 --- a/internal/generate/teamcity/services.go +++ b/internal/generate/teamcity/services.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/tests/annotations.go b/internal/generate/tests/annotations.go index 1d6940fb3da3..b4d774761b86 100644 --- a/internal/generate/tests/annotations.go +++ b/internal/generate/tests/annotations.go @@ -83,6 +83,10 @@ func (c CommonArgs) ImportStateIDAttribute() string { return namesgen.ConstOrQuote(c.importStateIDAttribute) } +func (c *CommonArgs) SetImportStateIDAttribute(attrName string) { + c.importStateIDAttribute = attrName +} + func (c CommonArgs) HasImportIgnore() bool { return len(c.ImportIgnore) > 0 } diff --git a/internal/generate/website/allowsubcats.go b/internal/generate/website/allowsubcats.go index c65ae20fce5c..aecbbf47d034 100644 --- a/internal/generate/website/allowsubcats.go +++ b/internal/generate/website/allowsubcats.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/website/customends.go b/internal/generate/website/customends.go index 55c054c78382..ab6f86bfe651 100644 --- a/internal/generate/website/customends.go +++ b/internal/generate/website/customends.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/generate/website/ignregionsubcats.go b/internal/generate/website/ignregionsubcats.go index 07161395672b..46449f4ec3a5 100644 --- a/internal/generate/website/ignregionsubcats.go +++ b/internal/generate/website/ignregionsubcats.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/provider/sdkv2/identity_interceptor.go b/internal/provider/sdkv2/identity_interceptor.go index 00056b6e4314..462600d59944 100644 --- a/internal/provider/sdkv2/identity_interceptor.go +++ b/internal/provider/sdkv2/identity_interceptor.go @@ -147,7 +147,8 @@ func newIdentityInterceptor(identitySpec *inttypes.Identity) interceptorInvocati func newResourceIdentity(v inttypes.Identity) *schema.ResourceIdentity { return &schema.ResourceIdentity{ - Version: v.Version(), + Version: v.Version(), + IdentityUpgraders: v.SDKv2IdentityUpgraders(), SchemaFunc: func() map[string]*schema.Schema { return identity.NewIdentitySchema(v) }, diff --git a/internal/retry/state.go b/internal/retry/state.go index 87bf3884f2ca..125452a6a6b6 100644 --- a/internal/retry/state.go +++ b/internal/retry/state.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/backoff" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/vcr" "gopkg.in/dnaeon/go-vcr.v4/pkg/recorder" ) @@ -106,7 +107,7 @@ func (conf *StateChangeConfOf[T, S]) WaitForStateContext(ctx context.Context) (T return t, err } - if any(t) == nil { + if inttypes.IsZero(t) { // If we're waiting for the absence of a thing, then return. if len(conf.Target) == 0 { targetOccurence++ diff --git a/internal/retry/state_test.go b/internal/retry/state_test.go index 9b1962dc994b..27cdab2168cf 100644 --- a/internal/retry/state_test.go +++ b/internal/retry/state_test.go @@ -6,18 +6,25 @@ package retry import ( "context" "errors" + "iter" + "slices" "strings" "sync/atomic" "testing" "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/google/go-cmp/cmp" ) // // Based on https://github.com/hashicorp/terraform-plugin-sdk/helper/retry/state_test.go. // +type value struct { + val string +} + func FailedStateRefreshFunc() StateRefreshFunc { return func(context.Context) (any, string, error) { return nil, "", errors.New("failed") @@ -31,13 +38,13 @@ func TimeoutStateRefreshFunc() StateRefreshFunc { return nil, "", &aws.RequestCanceledError{Err: ctx.Err()} case <-time.After(5 * time.Second): } - return struct{}{}, "pending", nil + return &value{val: "value"}, "pending", nil } } func SuccessfulStateRefreshFunc() StateRefreshFunc { return func(context.Context) (any, string, error) { - return struct{}{}, "running", nil + return &value{val: "value"}, "running", nil } } @@ -293,6 +300,103 @@ func TestWaitForState_failure(t *testing.T) { } } +func TestWaitForState_NotFound_NotFoundChecks(t *testing.T) { + t.Parallel() + + const notFoundCheckCount = 5 + + expectedErr := &NotFoundError{ + Retries: notFoundCheckCount + 1, + } + + conf := &StateChangeConf{ + Pending: []string{"pending", "incomplete"}, + Target: []string{"running"}, + PollInterval: 10 * time.Millisecond, + Timeout: 100 * time.Millisecond, + NotFoundChecks: notFoundCheckCount, + Refresh: func(context.Context) (any, string, error) { + return nil, "", nil + }, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if obj != nil { + t.Errorf("should not return obj") + } + if err == nil { + t.Fatal("Expected error. No error returned.") + } + + if !cmp.Equal(expectedErr, err) { + t.Errorf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err) + } +} + +type refresh[T any, S ~string] struct { + obj T + state S + err error +} + +func inconsistentResultStateRefreshFunc(t *testing.T) (StateRefreshFunc, func()) { + t.Helper() + + sequence := []refresh[any, string]{ + {nil, "", nil}, // 1 + {&value{val: "value"}, "pending", nil}, + {nil, "", nil}, {nil, "", nil}, // 2 + {&value{val: "value"}, "pending", nil}, + {nil, "", nil}, {nil, "", nil}, {nil, "", nil}, // 3 + } + + next, stop := iter.Pull(slices.Values(sequence)) + + return func(context.Context) (any, string, error) { + v, _ := next() + + return v.obj, v.state, v.err + }, stop +} + +func TestWaitForState_EmptyTarget_ContinuousTargetOccurence(t *testing.T) { + t.Parallel() + + const continuousTargetOccurence = 3 + const expectedCount = 8 + + var count atomic.Int32 + + inner, stop := inconsistentResultStateRefreshFunc(t) + defer stop() + + refresh := func(ctx context.Context) (any, string, error) { + count.Add(1) + return inner(ctx) + } + + conf := &StateChangeConf{ + Pending: []string{"pending", "incomplete"}, + Target: []string{}, + Timeout: 100 * time.Millisecond, + PollInterval: 10 * time.Millisecond, + ContinuousTargetOccurence: continuousTargetOccurence, + Refresh: refresh, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if obj != nil { + t.Errorf("should not return obj") + } + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + if v := count.Load(); v != expectedCount { + t.Errorf("Expected %d refresh calls, got %d", expectedCount, v) + } +} + func TestWaitForStateContext_cancel(t *testing.T) { t.Parallel() diff --git a/internal/retry/stateof_test.go b/internal/retry/stateof_test.go new file mode 100644 index 000000000000..6053a5b81ab5 --- /dev/null +++ b/internal/retry/stateof_test.go @@ -0,0 +1,414 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package retry + +import ( + "context" + "errors" + "iter" + "slices" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/google/go-cmp/cmp" +) + +// +// Based on https://github.com/hashicorp/terraform-plugin-sdk/helper/retry/state_test.go. +// + +func FailedStateRefreshFuncOf() StateRefreshFuncOf[*value, string] { + return func(context.Context) (*value, string, error) { + return nil, "", errors.New("failed") + } +} + +func TimeoutStateRefreshFuncOf() StateRefreshFuncOf[*value, string] { + return func(ctx context.Context) (*value, string, error) { + select { + case <-ctx.Done(): + return nil, "", &aws.RequestCanceledError{Err: ctx.Err()} + case <-time.After(5 * time.Second): + } + return &value{val: "value"}, "pending", nil + } +} + +func SuccessfulStateRefreshFuncOf() StateRefreshFuncOf[*value, string] { + return func(context.Context) (*value, string, error) { + return &value{val: "value"}, "running", nil + } +} + +func InconsistentStateRefreshFuncOf() StateRefreshFuncOf[*int, string] { + sequence := []string{ + "done", "replicating", + "done", "done", "done", + "replicating", + "done", "done", "done", + "replicating", "replicating", "replicating", "replicating", "replicating", + } + + r := NewStateGenerator(sequence) + + return func(context.Context) (*int, string, error) { + idx, s, err := r.NextState() + if err != nil { + return nil, "", err + } + + return &idx, s, nil + } +} + +func UnknownPendingStateRefreshFuncOf() StateRefreshFuncOf[*int, string] { + sequence := []string{ + "unknown1", "unknown2", "done", + } + + r := NewStateGenerator(sequence) + + return func(context.Context) (*int, string, error) { + idx, s, err := r.NextState() + if err != nil { + return nil, "", err + } + + return &idx, s, nil + } +} + +func TestWaitForStateOf_inconsistent_positive(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*int, string]{ + Pending: []string{"replicating"}, + Target: []string{"done"}, + Refresh: InconsistentStateRefreshFuncOf(), + Timeout: 90 * time.Millisecond, + PollInterval: 10 * time.Millisecond, + ContinuousTargetOccurence: 3, + } + + idx, err := conf.WaitForStateContext(t.Context()) + + if err != nil { + t.Fatalf("err: %s", err) + } + + if idx == nil { + t.Fatal("Expected index 4, was nil") + } + if *idx != 4 { + t.Fatalf("Expected index 4, given %d", *idx) + } +} + +func TestWaitForStateOf_inconsistent_negative(t *testing.T) { + t.Parallel() + + refreshCount := int64(0) + f := InconsistentStateRefreshFuncOf() + refresh := func(ctx context.Context) (*int, string, error) { + atomic.AddInt64(&refreshCount, 1) + return f(ctx) + } + + conf := &StateChangeConfOf[*int, string]{ + Pending: []string{"replicating"}, + Target: []string{"done"}, + Refresh: refresh, + Timeout: 85 * time.Millisecond, + PollInterval: 10 * time.Millisecond, + ContinuousTargetOccurence: 4, + } + + _, err := conf.WaitForStateContext(t.Context()) + + if err == nil { + t.Fatal("Expected timeout error. No error returned.") + } + + // we can't guarantee the exact number of refresh calls in the tests by + // timing them, but we want to make sure the test at least went through the + // required states. + if atomic.LoadInt64(&refreshCount) < 6 { + t.Fatal("refreshed called too few times") + } + + expectedErr := "timeout while waiting for state to become 'done'" + if !strings.HasPrefix(err.Error(), expectedErr) { + t.Fatalf("error prefix doesn't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) + } +} + +func TestWaitForStateOf_timeout(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{"running"}, + Refresh: TimeoutStateRefreshFuncOf(), + Timeout: 1 * time.Second, + } + + obj, err := conf.WaitForStateContext(t.Context()) + + if err == nil { + t.Fatal("Expected timeout error. No error returned.") + } + + expectedErr := "timeout while waiting for state to become 'running' (timeout: 1s)" + if !strings.HasPrefix(err.Error(), expectedErr) { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) + } + + if obj != nil { + t.Fatalf("should not return obj") + } +} + +func TestWaitForStateOf_success(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{"running"}, + Refresh: SuccessfulStateRefreshFuncOf(), + Timeout: 200 * time.Second, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if err != nil { + t.Fatalf("err: %s", err) + } + if obj == nil { + t.Fatalf("should return obj") + } +} + +func TestWaitForStateOf_successUnknownPending(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*int, string]{ + Target: []string{"done"}, + Refresh: UnknownPendingStateRefreshFuncOf(), + Timeout: 200 * time.Second, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if err != nil { + t.Fatalf("err: %s", err) + } + if obj == nil { + t.Fatalf("should return obj") + } +} + +func TestWaitForStateOf_successEmpty(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{}, + Refresh: func(context.Context) (*value, string, error) { + return nil, "", nil + }, + Timeout: 200 * time.Second, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if err != nil { + t.Fatalf("err: %s", err) + } + if obj != nil { + t.Fatalf("obj should be nil") + } +} + +func TestWaitForStateOf_failureEmpty(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{}, + NotFoundChecks: 1, + Refresh: func(context.Context) (*value, string, error) { + return &value{val: "forty-two"}, "pending", nil + }, + PollInterval: 10 * time.Millisecond, + Timeout: 100 * time.Millisecond, + } + + _, err := conf.WaitForStateContext(t.Context()) + if err == nil { + t.Fatal("Expected timeout error. Got none.") + } + expectedErr := "timeout while waiting for resource to be gone (last state: 'pending', timeout: 100ms)" + if err.Error() != expectedErr { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) + } +} + +func TestWaitForStateOf_failure(t *testing.T) { + t.Parallel() + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{"running"}, + Refresh: FailedStateRefreshFuncOf(), + Timeout: 200 * time.Second, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if err == nil { + t.Fatal("Expected error. No error returned.") + } + expectedErr := "failed" + if err.Error() != expectedErr { + t.Fatalf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err.Error()) + } + if obj != nil { + t.Fatalf("should not return obj") + } +} + +func TestWaitForStateOf_NotFound_NotFoundChecks(t *testing.T) { + t.Parallel() + + const notFoundCheckCount = 5 + + expectedErr := &NotFoundError{ + Retries: notFoundCheckCount + 1, + } + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{"running"}, + PollInterval: 10 * time.Millisecond, + Timeout: 100 * time.Millisecond, + NotFoundChecks: notFoundCheckCount, + Refresh: func(context.Context) (*value, string, error) { + return nil, "", nil + }, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if obj != nil { + t.Errorf("should not return obj") + } + if err == nil { + t.Fatal("Expected error. No error returned.") + } + + if !cmp.Equal(expectedErr, err) { + t.Errorf("Errors don't match.\nExpected: %q\nGiven: %q\n", expectedErr, err) + } +} + +func inconsistentResultStateRefreshFuncOf(t *testing.T) (StateRefreshFuncOf[*value, string], func()) { + t.Helper() + + sequence := []refresh[*value, string]{ + {nil, "", nil}, // 1 + {&value{val: "value"}, "pending", nil}, + {nil, "", nil}, {nil, "", nil}, // 2 + {&value{val: "value"}, "pending", nil}, + {nil, "", nil}, {nil, "", nil}, {nil, "", nil}, // 3 + } + + next, stop := iter.Pull(slices.Values(sequence)) + + return func(context.Context) (*value, string, error) { + v, _ := next() + + return v.obj, v.state, v.err + }, stop +} + +func TestWaitForStateOf_EmptyTarget_ContinuousTargetOccurence(t *testing.T) { + t.Parallel() + + const continuousTargetOccurence = 3 + const expectedCount = 8 + + var count atomic.Int32 + + inner, stop := inconsistentResultStateRefreshFuncOf(t) + defer stop() + + refresh := func(ctx context.Context) (*value, string, error) { + count.Add(1) + return inner(ctx) + } + + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{}, + Timeout: 100 * time.Millisecond, + PollInterval: 10 * time.Millisecond, + ContinuousTargetOccurence: continuousTargetOccurence, + Refresh: refresh, + } + + obj, err := conf.WaitForStateContext(t.Context()) + if obj != nil { + t.Errorf("should not return obj") + } + if err != nil { + t.Fatalf("Unexpected error: %s", err) + } + + if v := count.Load(); v != expectedCount { + t.Errorf("Expected %d refresh calls, got %d", expectedCount, v) + } +} + +func TestWaitForStateContextOf_cancel(t *testing.T) { + t.Parallel() + + // make this refresh func block until we cancel it + ctx, cancel := context.WithCancel(context.Background()) + refresh := func(context.Context) (*value, string, error) { + <-ctx.Done() + return nil, "pending", nil + } + conf := &StateChangeConfOf[*value, string]{ + Pending: []string{"pending", "incomplete"}, + Target: []string{"running"}, + Refresh: refresh, + Timeout: 10 * time.Second, + } + + var err error + + waitDone := make(chan struct{}) + go func() { + defer close(waitDone) + _, err = conf.WaitForStateContext(ctx) + }() + + // make sure WaitForState is blocked + select { + case <-waitDone: + t.Fatal("WaitForState returned too early") + case <-time.After(10 * time.Millisecond): + } + + // unlock the refresh function + cancel() + // make sure WaitForState returns + select { + case <-waitDone: + case <-time.After(time.Second): + t.Fatal("WaitForState didn't return after refresh finished") + } + + if !errors.Is(err, context.Canceled) { + t.Fatalf("Expected canceled context error, got: %s", err) + } +} diff --git a/internal/sdkv2/schema.go b/internal/sdkv2/schema.go index bc007e8aa9b0..375666c97f2f 100644 --- a/internal/sdkv2/schema.go +++ b/internal/sdkv2/schema.go @@ -80,6 +80,12 @@ var IAMPolicyDocumentSchemaRequired = sync.OnceValue(jsonDocumentSchemaRequiredF // IAMPolicyDocumentSchemaRequiredForceNew returns the standard schema for a required, force-new IAM policy JSON document. var IAMPolicyDocumentSchemaRequiredForceNew = sync.OnceValue(jsonDocumentSchemaRequiredForceNewFunc(SuppressEquivalentIAMPolicyDocuments)) +// JSONDocumentSchemaOptional returns the standard schema for an optional JSON document. +var JSONDocumentSchemaOptional = sync.OnceValue(jsonDocumentSchemaOptionalFunc(SuppressEquivalentJSONDocuments)) + +// JSONDocumentWithEmptySchemaOptional returns the standard schema for an optional JSON document with empty string handling. +var JSONDocumentWithEmptySchemaOptional = sync.OnceValue(jsonDocumentSchemaOptionalFunc(SuppressEquivalentJSONDocumentsWithEmpty)) + // JSONDocumentSchemaOptionalForceNew returns the standard schema for an optional, force-new JSON document. var JSONDocumentSchemaOptionalForceNew = sync.OnceValue(jsonDocumentSchemaOptionalForceNewFunc(SuppressEquivalentJSONDocuments)) diff --git a/internal/sdkv2/suppress.go b/internal/sdkv2/suppress.go index a3b9e7352c95..ceadd1cd4863 100644 --- a/internal/sdkv2/suppress.go +++ b/internal/sdkv2/suppress.go @@ -24,6 +24,18 @@ func SuppressEquivalentJSONDocuments(k, old, new string, _ *schema.ResourceData) return json.EqualStrings(old, new) } +// SuppressEquivalentJSONDocumentsWithEmpty provides custom difference suppression +// for JSON documents in the given strings that are equivalent, handling empty +// strings (`""`) and empty JSON strings (`"{}"`) as equivalent. +// This is useful for suppressing diffs for non-IAM JSON policy documents. +func SuppressEquivalentJSONDocumentsWithEmpty(k, old, new string, _ *schema.ResourceData) bool { + if equalEmptyJSONStrings(old, new) { + return true + } + + return json.EqualStrings(old, new) +} + // SuppressEquivalentCloudWatchLogsLogGroupARN provides custom difference suppression // for strings that represent equal CloudWatch Logs log group ARNs. func SuppressEquivalentCloudWatchLogsLogGroupARN(_, old, new string, _ *schema.ResourceData) bool { diff --git a/internal/service/acmpca/certificate_authority.go b/internal/service/acmpca/certificate_authority.go index 310b8f68c448..2f213a132506 100644 --- a/internal/service/acmpca/certificate_authority.go +++ b/internal/service/acmpca/certificate_authority.go @@ -468,7 +468,7 @@ func resourceCertificateAuthorityUpdate(ctx context.Context, d *schema.ResourceD var diags diag.Diagnostics conn := meta.(*conns.AWSClient).ACMPCAClient(ctx) - if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { + if d.HasChangesExcept(names.AttrRegion, names.AttrTags, names.AttrTagsAll) { input := acmpca.UpdateCertificateAuthorityInput{ CertificateAuthorityArn: aws.String(d.Id()), } diff --git a/internal/service/amp/query_logging_configuration.go b/internal/service/amp/query_logging_configuration.go index f234b33c6a0a..a5806834086f 100644 --- a/internal/service/amp/query_logging_configuration.go +++ b/internal/service/amp/query_logging_configuration.go @@ -9,12 +9,14 @@ import ( "fmt" "time" + "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/amp" awstypes "github.com/aws/aws-sdk-go-v2/service/amp/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -82,6 +84,9 @@ func (r *queryLoggingConfigurationResource) Schema(ctx context.Context, request "log_group_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile(`:\*$`), "ARN must end with `:*`"), + }, }, }, }, diff --git a/internal/service/amp/workspace.go b/internal/service/amp/workspace.go index 8a8c4490ed59..9e403e6dd56c 100644 --- a/internal/service/amp/workspace.go +++ b/internal/service/amp/workspace.go @@ -9,6 +9,7 @@ import ( "log" "time" + "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/amp" "github.com/aws/aws-sdk-go-v2/service/amp/types" @@ -16,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" @@ -70,9 +72,12 @@ func resourceWorkspace() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "log_group_arn": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + verify.ValidARN, + validation.StringMatch(regexache.MustCompile(`:\*$`), "ARN must end with `:*`"), + ), }, }, }, diff --git a/internal/service/amp/workspace_data_source_tags_gen_test.go b/internal/service/amp/workspace_data_source_tags_gen_test.go index e525c6032a3e..3adfe57b5ebd 100644 --- a/internal/service/amp/workspace_data_source_tags_gen_test.go +++ b/internal/service/amp/workspace_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfamp "github.com/hashicorp/terraform-provider-aws/internal/service/amp" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -193,7 +193,7 @@ func TestAccAMPWorkspaceDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testin } func expectFullWorkspaceDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfamp.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfamp.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apigateway/api_key_data_source_tags_gen_test.go b/internal/service/apigateway/api_key_data_source_tags_gen_test.go index 06d973fd0c9a..0d5bb915c879 100644 --- a/internal/service/apigateway/api_key_data_source_tags_gen_test.go +++ b/internal/service/apigateway/api_key_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfapigateway "github.com/hashicorp/terraform-provider-aws/internal/service/apigateway" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccAPIGatewayAPIKeyDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *te } func expectFullAPIKeyDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apigateway/domain_name_data_source_tags_gen_test.go b/internal/service/apigateway/domain_name_data_source_tags_gen_test.go index 4722bc6df58c..5b1c835f9714 100644 --- a/internal/service/apigateway/domain_name_data_source_tags_gen_test.go +++ b/internal/service/apigateway/domain_name_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfapigateway "github.com/hashicorp/terraform-provider-aws/internal/service/apigateway" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -229,7 +229,7 @@ func TestAccAPIGatewayDomainNameDataSource_tags_IgnoreTags_Overlap_ResourceTag(t } func expectFullDomainNameDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apigateway/rest_api_data_source_tags_gen_test.go b/internal/service/apigateway/rest_api_data_source_tags_gen_test.go index 2210f1573494..b451644c02b7 100644 --- a/internal/service/apigateway/rest_api_data_source_tags_gen_test.go +++ b/internal/service/apigateway/rest_api_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfapigateway "github.com/hashicorp/terraform-provider-aws/internal/service/apigateway" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccAPIGatewayRESTAPIDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *t } func expectFullRESTAPIDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apigateway/vpc_link_data_source_tags_gen_test.go b/internal/service/apigateway/vpc_link_data_source_tags_gen_test.go index 6fee566aedab..28a215d39881 100644 --- a/internal/service/apigateway/vpc_link_data_source_tags_gen_test.go +++ b/internal/service/apigateway/vpc_link_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfapigateway "github.com/hashicorp/terraform-provider-aws/internal/service/apigateway" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccAPIGatewayVPCLinkDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *t } func expectFullVPCLinkDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigateway.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apigatewayv2/api_data_source_tags_gen_test.go b/internal/service/apigatewayv2/api_data_source_tags_gen_test.go index a1ae648f5082..b81136ef8c9b 100644 --- a/internal/service/apigatewayv2/api_data_source_tags_gen_test.go +++ b/internal/service/apigatewayv2/api_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfapigatewayv2 "github.com/hashicorp/terraform-provider-aws/internal/service/apigatewayv2" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccAPIGatewayV2APIDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *tes } func expectFullAPIDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigatewayv2.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigatewayv2.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apigatewayv2/vpc_link_data_source_tags_gen_test.go b/internal/service/apigatewayv2/vpc_link_data_source_tags_gen_test.go index 6842674ba63a..27abbdbfda13 100644 --- a/internal/service/apigatewayv2/vpc_link_data_source_tags_gen_test.go +++ b/internal/service/apigatewayv2/vpc_link_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfapigatewayv2 "github.com/hashicorp/terraform-provider-aws/internal/service/apigatewayv2" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccAPIGatewayV2VPCLinkDataSource_tags_IgnoreTags_Overlap_ResourceTag(t } func expectFullVPCLinkDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigatewayv2.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfapigatewayv2.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appflow/flow.go b/internal/service/appflow/flow.go index fc97c1d9f945..f587d9347082 100644 --- a/internal/service/appflow/flow.go +++ b/internal/service/appflow/flow.go @@ -24,7 +24,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -3720,7 +3720,7 @@ func flattenTasks(tasks []types.Task) []any { } func flattenTask(task types.Task) map[string]any { - if itypes.IsZero(&task) { + if inttypes.IsZero(&task) { return nil } diff --git a/internal/service/appintegrations/event_integration_data_source_tags_gen_test.go b/internal/service/appintegrations/event_integration_data_source_tags_gen_test.go index 30e6968f1682..d40168266172 100644 --- a/internal/service/appintegrations/event_integration_data_source_tags_gen_test.go +++ b/internal/service/appintegrations/event_integration_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappintegrations "github.com/hashicorp/terraform-provider-aws/internal/service/appintegrations" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccAppIntegrationsEventIntegrationDataSource_tags_IgnoreTags_Overlap_Re } func expectFullEventIntegrationDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappintegrations.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappintegrations.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/gateway_route_data_source_tags_gen_test.go b/internal/service/appmesh/gateway_route_data_source_tags_gen_test.go index a4a0ce2f0533..8d958d95e6f0 100644 --- a/internal/service/appmesh/gateway_route_data_source_tags_gen_test.go +++ b/internal/service/appmesh/gateway_route_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshGatewayRouteDataSource_tags_IgnoreTags_Overlap_ResourceTag(t } func expectFullGatewayRouteDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/mesh_data_source_tags_gen_test.go b/internal/service/appmesh/mesh_data_source_tags_gen_test.go index 0faa3a9123e0..37649e362f49 100644 --- a/internal/service/appmesh/mesh_data_source_tags_gen_test.go +++ b/internal/service/appmesh/mesh_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshServiceMeshDataSource_tags_IgnoreTags_Overlap_ResourceTag(t * } func expectFullServiceMeshDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/route_data_source_tags_gen_test.go b/internal/service/appmesh/route_data_source_tags_gen_test.go index 09f14447ca63..29ad3b6a078e 100644 --- a/internal/service/appmesh/route_data_source_tags_gen_test.go +++ b/internal/service/appmesh/route_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshRouteDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testin } func expectFullRouteDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/virtual_gateway_data_source_tags_gen_test.go b/internal/service/appmesh/virtual_gateway_data_source_tags_gen_test.go index 6a18e5037e27..9f7bc9789a0b 100644 --- a/internal/service/appmesh/virtual_gateway_data_source_tags_gen_test.go +++ b/internal/service/appmesh/virtual_gateway_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshVirtualGatewayDataSource_tags_IgnoreTags_Overlap_ResourceTag( } func expectFullVirtualGatewayDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/virtual_node_data_source_tags_gen_test.go b/internal/service/appmesh/virtual_node_data_source_tags_gen_test.go index 27bb2c29be53..340b6f55b843 100644 --- a/internal/service/appmesh/virtual_node_data_source_tags_gen_test.go +++ b/internal/service/appmesh/virtual_node_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshVirtualNodeDataSource_tags_IgnoreTags_Overlap_ResourceTag(t * } func expectFullVirtualNodeDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/virtual_router_data_source_tags_gen_test.go b/internal/service/appmesh/virtual_router_data_source_tags_gen_test.go index fa829b1fd44f..a8e0db7f92dd 100644 --- a/internal/service/appmesh/virtual_router_data_source_tags_gen_test.go +++ b/internal/service/appmesh/virtual_router_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshVirtualRouterDataSource_tags_IgnoreTags_Overlap_ResourceTag(t } func expectFullVirtualRouterDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/appmesh/virtual_service_data_source_tags_gen_test.go b/internal/service/appmesh/virtual_service_data_source_tags_gen_test.go index 27141adf4f8c..018612f5a32e 100644 --- a/internal/service/appmesh/virtual_service_data_source_tags_gen_test.go +++ b/internal/service/appmesh/virtual_service_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -220,7 +220,7 @@ func testAccAppMeshVirtualServiceDataSource_tags_IgnoreTags_Overlap_ResourceTag( } func expectFullVirtualServiceDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfappmesh.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/apprunner/service.go b/internal/service/apprunner/service.go index 36fec6b24590..a8764cc96b18 100644 --- a/internal/service/apprunner/service.go +++ b/internal/service/apprunner/service.go @@ -551,7 +551,7 @@ func resourceServiceUpdate(ctx context.Context, d *schema.ResourceData, meta any conn := meta.(*conns.AWSClient).AppRunnerClient(ctx) - if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { + if d.HasChangesExcept(names.AttrRegion, names.AttrTags, names.AttrTagsAll) { input := &apprunner.UpdateServiceInput{ ServiceArn: aws.String(d.Id()), } diff --git a/internal/service/appstream/fleet.go b/internal/service/appstream/fleet.go index e7277b2ccb14..4de1ff1548a4 100644 --- a/internal/service/appstream/fleet.go +++ b/internal/service/appstream/fleet.go @@ -25,7 +25,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -699,7 +699,7 @@ func expandComputeCapacity(tfList []any) *awstypes.ComputeCapacity { apiObject.DesiredSessions = aws.Int32(int32(v.(int))) } - if itypes.IsZero(apiObject) { + if inttypes.IsZero(apiObject) { return nil } @@ -762,7 +762,7 @@ func expandDomainJoinInfo(tfList []any) *awstypes.DomainJoinInfo { apiObject.OrganizationalUnitDistinguishedName = aws.String(v.(string)) } - if itypes.IsZero(apiObject) { + if inttypes.IsZero(apiObject) { return nil } @@ -808,7 +808,7 @@ func expandVPCConfig(tfList []any) *awstypes.VpcConfig { apiObject.SubnetIds = flex.ExpandStringValueList(v.([]any)) } - if itypes.IsZero(apiObject) { + if inttypes.IsZero(apiObject) { return nil } diff --git a/internal/service/autoscaling/launch_configuration.go b/internal/service/autoscaling/launch_configuration.go index 370b7b8630fc..db237b0f2ad7 100644 --- a/internal/service/autoscaling/launch_configuration.go +++ b/internal/service/autoscaling/launch_configuration.go @@ -28,7 +28,7 @@ import ( // nosemgrep:ci.semgrep.aws.multiple-service-imports "github.com/hashicorp/terraform-provider-aws/internal/flex" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -772,7 +772,7 @@ func userDataHashSum(userData string) string { // Check whether the user_data is not Base64 encoded. // Always calculate hash of base64 decoded value since we // check against double-encoding when setting it. - v, err := itypes.Base64Decode(userData) + v, err := inttypes.Base64Decode(userData) if err != nil { v = []byte(userData) } diff --git a/internal/service/backup/logically_air_gapped_vault.go b/internal/service/backup/logically_air_gapped_vault.go index 5d9396b611c5..cdcc58418fd4 100644 --- a/internal/service/backup/logically_air_gapped_vault.go +++ b/internal/service/backup/logically_air_gapped_vault.go @@ -31,6 +31,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" "github.com/hashicorp/terraform-provider-aws/internal/framework" fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" @@ -57,7 +58,15 @@ func (r *logicallyAirGappedVaultResource) Schema(ctx context.Context, request re response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ names.AttrARN: framework.ARNAttributeComputedOnly(), - names.AttrID: framework.IDAttribute(), + "encryption_key_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrID: framework.IDAttribute(), "max_retention_days": schema.Int64Attribute{ Required: true, PlanModifiers: []planmodifier.Int64{ @@ -102,9 +111,9 @@ func (r *logicallyAirGappedVaultResource) Create(ctx context.Context, request re conn := r.Meta().BackupClient(ctx) - name := data.BackupVaultName.ValueString() - input := &backup.CreateLogicallyAirGappedBackupVaultInput{} - response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + name := fwflex.StringValueFromFramework(ctx, data.BackupVaultName) + var input backup.CreateLogicallyAirGappedBackupVaultInput + response.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...) if response.Diagnostics.HasError() { return } @@ -113,7 +122,7 @@ func (r *logicallyAirGappedVaultResource) Create(ctx context.Context, request re input.BackupVaultTags = getTagsIn(ctx) input.CreatorRequestId = aws.String(sdkid.UniqueId()) - output, err := conn.CreateLogicallyAirGappedBackupVault(ctx, input) + output, err := conn.CreateLogicallyAirGappedBackupVault(ctx, &input) if err != nil { response.Diagnostics.AddError(fmt.Sprintf("creating Backup Logically Air Gapped Vault (%s)", name), err.Error()) @@ -123,15 +132,21 @@ func (r *logicallyAirGappedVaultResource) Create(ctx context.Context, request re // Set values for unknowns. data.BackupVaultARN = fwflex.StringToFramework(ctx, output.BackupVaultArn) - data.ID = fwflex.StringToFramework(ctx, output.BackupVaultName) + data.ID = fwflex.StringValueToFramework(ctx, name) - if _, err := waitLogicallyAirGappedVaultCreated(ctx, conn, data.ID.ValueString(), r.CreateTimeout(ctx, data.Timeouts)); err != nil { + vault, err := waitLogicallyAirGappedVaultCreated(ctx, conn, name, r.CreateTimeout(ctx, data.Timeouts)) + if err != nil { response.State.SetAttribute(ctx, path.Root(names.AttrID), data.ID) // Set 'id' so as to taint the resource. - response.Diagnostics.AddError(fmt.Sprintf("waiting for Backup Logically Air Gapped Vault (%s) create", data.ID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("waiting for Backup Logically Air Gapped Vault (%s) create", name), err.Error()) return } + response.Diagnostics.Append(fwflex.Flatten(ctx, vault, &data)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(response.State.Set(ctx, data)...) } @@ -144,7 +159,8 @@ func (r *logicallyAirGappedVaultResource) Read(ctx context.Context, request reso conn := r.Meta().BackupClient(ctx) - output, err := findLogicallyAirGappedBackupVaultByName(ctx, conn, data.ID.ValueString()) + name := fwflex.StringValueFromFramework(ctx, data.ID) + output, err := findLogicallyAirGappedBackupVaultByName(ctx, conn, name) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -154,7 +170,7 @@ func (r *logicallyAirGappedVaultResource) Read(ctx context.Context, request reso } if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Backup Logically Air Gapped Vault (%s)", data.ID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Backup Logically Air Gapped Vault (%s)", name), err.Error()) return } @@ -177,8 +193,9 @@ func (r *logicallyAirGappedVaultResource) Delete(ctx context.Context, request re conn := r.Meta().BackupClient(ctx) + name := fwflex.StringValueFromFramework(ctx, data.ID) input := backup.DeleteBackupVaultInput{ - BackupVaultName: fwflex.StringFromFramework(ctx, data.ID), + BackupVaultName: aws.String(name), } _, err := conn.DeleteBackupVault(ctx, &input) @@ -187,7 +204,7 @@ func (r *logicallyAirGappedVaultResource) Delete(ctx context.Context, request re } if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("deleting Backup Logically Air Gapped Vault (%s)", data.ID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("deleting Backup Logically Air Gapped Vault (%s)", name), err.Error()) return } @@ -197,6 +214,7 @@ type logicallyAirGappedVaultResourceModel struct { framework.WithRegionModel BackupVaultARN types.String `tfsdk:"arn"` BackupVaultName types.String `tfsdk:"name"` + EncryptionKeyARN fwtypes.ARN `tfsdk:"encryption_key_arn"` ID types.String `tfsdk:"id"` MaxRetentionDays types.Int64 `tfsdk:"max_retention_days"` MinRetentionDays types.Int64 `tfsdk:"min_retention_days"` @@ -245,7 +263,6 @@ func waitLogicallyAirGappedVaultCreated(ctx context.Context, conn *backup.Client } outputRaw, err := stateConf.WaitForStateContext(ctx) - if output, ok := outputRaw.(*backup.DescribeBackupVaultOutput); ok { return output, err } diff --git a/internal/service/backup/logically_air_gapped_vault_test.go b/internal/service/backup/logically_air_gapped_vault_test.go index 517123ae155f..204f6704581b 100644 --- a/internal/service/backup/logically_air_gapped_vault_test.go +++ b/internal/service/backup/logically_air_gapped_vault_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/service/backup" + "github.com/hashicorp/terraform-plugin-testing/compare" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" @@ -88,6 +89,41 @@ func TestAccBackupLogicallyAirGappedVault_disappears(t *testing.T) { }) } +func TestAccBackupLogicallyAirGappedVault_encryptionKeyARN(t *testing.T) { + ctx := acctest.Context(t) + var v backup.DescribeBackupVaultOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_backup_logically_air_gapped_vault.test" + kmsKeyResourceName := "aws_kms_key.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.BackupEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BackupServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckLogicallyAirGappedVaultDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccLogicallyAirGappedVaultConfig_encryptionKeyARN(rName), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New("encryption_key_arn"), kmsKeyResourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckLogicallyAirGappedVaultExists(ctx, resourceName, &v), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccBackupLogicallyAirGappedVault_tags(t *testing.T) { ctx := acctest.Context(t) var v backup.DescribeBackupVaultOutput @@ -202,6 +238,22 @@ resource "aws_backup_logically_air_gapped_vault" "test" { `, rName) } +func testAccLogicallyAirGappedVaultConfig_encryptionKeyARN(rName string) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_backup_logically_air_gapped_vault" "test" { + name = %[1]q + max_retention_days = 10 + min_retention_days = 7 + encryption_key_arn = aws_kms_key.test.arn +} +`, rName) +} + func testAccLogicallyAirGappedVaultConfig_tags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_backup_logically_air_gapped_vault" "test" { diff --git a/internal/service/backup/vault.go b/internal/service/backup/vault.go index f54563901e00..98214339ff56 100644 --- a/internal/service/backup/vault.go +++ b/internal/service/backup/vault.go @@ -218,11 +218,11 @@ func findBackupVaultByName(ctx context.Context, conn *backup.Client, name string } func findVaultByName(ctx context.Context, conn *backup.Client, name string) (*backup.DescribeBackupVaultOutput, error) { - input := &backup.DescribeBackupVaultInput{ + input := backup.DescribeBackupVaultInput{ BackupVaultName: aws.String(name), } - output, err := findVault(ctx, conn, input) + output, err := findVault(ctx, conn, &input) if err != nil { return nil, err diff --git a/internal/service/batch/compute_environment_data_source_tags_gen_test.go b/internal/service/batch/compute_environment_data_source_tags_gen_test.go index 462996a71fa9..29684cf17f33 100644 --- a/internal/service/batch/compute_environment_data_source_tags_gen_test.go +++ b/internal/service/batch/compute_environment_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccBatchComputeEnvironmentDataSource_tags_IgnoreTags_Overlap_ResourceTa } func expectFullComputeEnvironmentDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/batch/job_definition_data_source_tags_gen_test.go b/internal/service/batch/job_definition_data_source_tags_gen_test.go index 7e39f437f536..9400a868ab84 100644 --- a/internal/service/batch/job_definition_data_source_tags_gen_test.go +++ b/internal/service/batch/job_definition_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccBatchJobDefinitionDataSource_tags_IgnoreTags_Overlap_ResourceTag(t * } func expectFullJobDefinitionDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/batch/job_queue_data_source_tags_gen_test.go b/internal/service/batch/job_queue_data_source_tags_gen_test.go index 6b4100139650..062ed4b5d4cd 100644 --- a/internal/service/batch/job_queue_data_source_tags_gen_test.go +++ b/internal/service/batch/job_queue_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -204,7 +204,7 @@ func TestAccBatchJobQueueDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testi } func expectFullJobQueueDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/batch/scheduling_policy_data_source_tags_gen_test.go b/internal/service/batch/scheduling_policy_data_source_tags_gen_test.go index cf3dcffd8f28..82ff90cfa73e 100644 --- a/internal/service/batch/scheduling_policy_data_source_tags_gen_test.go +++ b/internal/service/batch/scheduling_policy_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfbatch "github.com/hashicorp/terraform-provider-aws/internal/service/batch" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccBatchSchedulingPolicyDataSource_tags_IgnoreTags_Overlap_ResourceTag( } func expectFullSchedulingPolicyDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfbatch.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 9d1384b53454..dfabab25bf3f 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -336,6 +336,12 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ + "custom_metadata_field": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "metadata_field": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ @@ -870,10 +876,11 @@ type rdsConfigurationModel struct { } type rdsFieldMappingModel struct { - MetadataField types.String `tfsdk:"metadata_field"` - PrimaryKeyField types.String `tfsdk:"primary_key_field"` - TextField types.String `tfsdk:"text_field"` - VectorField types.String `tfsdk:"vector_field"` + CustomMetadataField types.String `tfsdk:"custom_metadata_field"` + MetadataField types.String `tfsdk:"metadata_field"` + PrimaryKeyField types.String `tfsdk:"primary_key_field"` + TextField types.String `tfsdk:"text_field"` + VectorField types.String `tfsdk:"vector_field"` } type redisEnterpriseCloudConfigurationModel struct { diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index eb19ecfc5a69..b12b4f9ecae4 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -77,6 +77,7 @@ func testAccKnowledgeBase_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), ), }, { @@ -108,6 +109,7 @@ func testAccKnowledgeBase_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), ), }, }, @@ -515,10 +517,11 @@ resource "aws_bedrockagent_knowledge_base" "test" { database_name = aws_rds_cluster.test.database_name table_name = "bedrock_integration.bedrock_kb" field_mapping { - vector_field = "embedding" - text_field = "chunks" - metadata_field = "metadata" - primary_key_field = "id" + vector_field = "embedding" + text_field = "chunks" + metadata_field = "metadata" + primary_key_field = "id" + custom_metadata_field = "custom_metadata" } } } @@ -551,10 +554,11 @@ resource "aws_bedrockagent_knowledge_base" "test" { database_name = aws_rds_cluster.test.database_name table_name = "bedrock_integration.bedrock_kb" field_mapping { - vector_field = "embedding" - text_field = "chunks" - metadata_field = "metadata" - primary_key_field = "id" + vector_field = "embedding" + text_field = "chunks" + metadata_field = "metadata" + primary_key_field = "id" + custom_metadata_field = "custom_metadata" } } } @@ -585,10 +589,11 @@ resource "aws_bedrockagent_knowledge_base" "test" { database_name = aws_rds_cluster.test.database_name table_name = "bedrock_integration.bedrock_kb" field_mapping { - vector_field = "embedding" - text_field = "chunks" - metadata_field = "metadata" - primary_key_field = "id" + vector_field = "embedding" + text_field = "chunks" + metadata_field = "metadata" + primary_key_field = "id" + custom_metadata_field = "custom_metadata" } } } @@ -623,10 +628,11 @@ resource "aws_bedrockagent_knowledge_base" "test" { database_name = aws_rds_cluster.test.database_name table_name = "bedrock_integration.bedrock_kb" field_mapping { - vector_field = "embedding" - text_field = "chunks" - metadata_field = "metadata" - primary_key_field = "id" + vector_field = "embedding" + text_field = "chunks" + metadata_field = "metadata" + primary_key_field = "id" + custom_metadata_field = "custom_metadata" } } } diff --git a/internal/service/bedrockagentcore/agent_runtime.go b/internal/service/bedrockagentcore/agent_runtime.go index 4b79b1526dae..7bae8c33e961 100644 --- a/internal/service/bedrockagentcore/agent_runtime.go +++ b/internal/service/bedrockagentcore/agent_runtime.go @@ -104,12 +104,107 @@ func (r *agentRuntimeResource) Schema(ctx context.Context, request resource.Sche listvalidator.IsRequired(), listvalidator.SizeAtMost(1), }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplaceIf( + func(ctx context.Context, request planmodifier.ListRequest, response *listplanmodifier.RequiresReplaceIfFuncResponse) { + // If code_configuration was set in the previous configuration and container_configuration is set in the planned configuration, a replacement is required — and vice versa. + var prev, plan agentRuntimeArtifactModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.State.GetAttribute(ctx, path.Root("agent_runtime_artifact").AtListIndex(0), &prev)) + smerr.AddEnrich(ctx, &response.Diagnostics, request.Plan.GetAttribute(ctx, path.Root("agent_runtime_artifact").AtListIndex(0), &plan)) + if response.Diagnostics.HasError() { + return + } + if (!prev.ContainerConfiguration.IsNull() && !plan.CodeConfiguration.IsNull()) || + (!prev.CodeConfiguration.IsNull() && !plan.ContainerConfiguration.IsNull()) { + response.RequiresReplace = true + } + }, + "Artifact type change between code_configuration and container_configuration requires replacement", + "", + ), + }, NestedObject: schema.NestedBlockObject{ Blocks: map[string]schema.Block{ + "code_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[codeConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("container_configuration"), + path.MatchRelative().AtParent().AtName("code_configuration"), + ), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "entry_point": schema.ListAttribute{ + CustomType: fwtypes.ListOfStringType, + Required: true, + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(2), + listvalidator.ValueStringsAre(stringvalidator.LengthBetween(1, 128)), + }, + ElementType: types.StringType, + }, + "runtime": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.AgentManagedRuntimeType](), + }, + }, + Blocks: map[string]schema.Block{ + "code": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[codeConfigurationCodeModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "s3": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[s3CodeConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + // If another member is added to the union, this will need to be updated. + path.MatchRelative().AtParent().AtName("s3"), + ), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrBucket: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile(`^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$`), "must be a valid S3 bucket name"), + }, + }, + names.AttrPrefix: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 1024), + }, + }, + "version_id": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(3, 1024), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, "container_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[containerConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("container_configuration"), + path.MatchRelative().AtParent().AtName("code_configuration"), + ), }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ @@ -519,6 +614,7 @@ type agentRuntimeResourceModel struct { } type agentRuntimeArtifactModel struct { + CodeConfiguration fwtypes.ListNestedObjectValueOf[codeConfigurationModel] `tfsdk:"code_configuration"` ContainerConfiguration fwtypes.ListNestedObjectValueOf[containerConfigurationModel] `tfsdk:"container_configuration"` } @@ -530,6 +626,13 @@ var ( func (m *agentRuntimeArtifactModel) Flatten(ctx context.Context, v any) diag.Diagnostics { var diags diag.Diagnostics switch t := v.(type) { + case awstypes.AgentRuntimeArtifactMemberCodeConfiguration: + var data codeConfigurationModel + smerr.AddEnrich(ctx, &diags, fwflex.Flatten(ctx, t.Value, &data)) + if diags.HasError() { + return diags + } + m.CodeConfiguration = fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &data) case awstypes.AgentRuntimeArtifactMemberContainerConfiguration: var data containerConfigurationModel smerr.AddEnrich(ctx, &diags, fwflex.Flatten(ctx, t.Value, &data)) @@ -550,6 +653,18 @@ func (m *agentRuntimeArtifactModel) Flatten(ctx context.Context, v any) diag.Dia func (m agentRuntimeArtifactModel) Expand(ctx context.Context) (any, diag.Diagnostics) { var diags diag.Diagnostics switch { + case !m.CodeConfiguration.IsNull(): + data, d := m.CodeConfiguration.ToPtr(ctx) + smerr.AddEnrich(ctx, &diags, d) + if diags.HasError() { + return nil, diags + } + var r awstypes.AgentRuntimeArtifactMemberCodeConfiguration + smerr.AddEnrich(ctx, &diags, fwflex.Expand(ctx, data, &r.Value)) + if diags.HasError() { + return nil, diags + } + return &r, diags case !m.ContainerConfiguration.IsNull(): data, d := m.ContainerConfiguration.ToPtr(ctx) smerr.AddEnrich(ctx, &diags, d) @@ -566,6 +681,66 @@ func (m agentRuntimeArtifactModel) Expand(ctx context.Context) (any, diag.Diagno return nil, diags } +type codeConfigurationModel struct { + Code fwtypes.ListNestedObjectValueOf[codeConfigurationCodeModel] `tfsdk:"code"` + EntryPoint fwtypes.ListOfString `tfsdk:"entry_point"` + Runtime fwtypes.StringEnum[awstypes.AgentManagedRuntimeType] `tfsdk:"runtime"` +} + +type codeConfigurationCodeModel struct { + S3 fwtypes.ListNestedObjectValueOf[s3CodeConfigurationModel] `tfsdk:"s3"` +} + +type s3CodeConfigurationModel struct { + Bucket types.String `tfsdk:"bucket"` + Prefix types.String `tfsdk:"prefix"` + VersionID types.String `tfsdk:"version_id"` +} + +var ( + _ fwflex.Expander = codeConfigurationCodeModel{} + _ fwflex.Flattener = &codeConfigurationCodeModel{} +) + +func (m *codeConfigurationCodeModel) Flatten(ctx context.Context, v any) diag.Diagnostics { + var diags diag.Diagnostics + switch t := v.(type) { + case awstypes.CodeMemberS3: + var data s3CodeConfigurationModel + smerr.AddEnrich(ctx, &diags, fwflex.Flatten(ctx, t.Value, &data)) + if diags.HasError() { + return diags + } + m.S3 = fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &data) + + default: + diags.AddError( + "Unsupported Type", + fmt.Sprintf("code configuration code flatten: %T", v), + ) + } + return diags +} + +func (m codeConfigurationCodeModel) Expand(ctx context.Context) (any, diag.Diagnostics) { + var diags diag.Diagnostics + switch { + case !m.S3.IsNull(): + data, d := m.S3.ToPtr(ctx) + smerr.AddEnrich(ctx, &diags, d) + if diags.HasError() { + return nil, diags + } + var r awstypes.CodeMemberS3 + smerr.AddEnrich(ctx, &diags, fwflex.Expand(ctx, data, &r.Value)) + if diags.HasError() { + return nil, diags + } + return &r, diags + } + return nil, diags +} + type containerConfigurationModel struct { ContainerURI types.String `tfsdk:"container_uri"` } diff --git a/internal/service/bedrockagentcore/agent_runtime_test.go b/internal/service/bedrockagentcore/agent_runtime_test.go index 837faeb4eb0d..827e92cd8986 100644 --- a/internal/service/bedrockagentcore/agent_runtime_test.go +++ b/internal/service/bedrockagentcore/agent_runtime_test.go @@ -458,7 +458,7 @@ func TestAccBedrockAgentCoreAgentRuntime_protocolConfiguration(t *testing.T) { }) } -func TestAccBedrockAgentCoreAgentRuntime_artifact(t *testing.T) { +func TestAccBedrockAgentCoreAgentRuntime_artifactContainer(t *testing.T) { ctx := acctest.Context(t) var agentRuntime bedrockagentcorecontrol.GetAgentRuntimeOutput rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") @@ -490,6 +490,7 @@ func TestAccBedrockAgentCoreAgentRuntime_artifact(t *testing.T) { ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{}), "container_configuration": knownvalue.ListExact([]knownvalue.Check{ knownvalue.ObjectExact(map[string]knownvalue.Check{ "container_uri": knownvalue.StringExact(rImageUriV1), @@ -519,6 +520,7 @@ func TestAccBedrockAgentCoreAgentRuntime_artifact(t *testing.T) { ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{}), "container_configuration": knownvalue.ListExact([]knownvalue.Check{ knownvalue.ObjectExact(map[string]knownvalue.Check{ "container_uri": knownvalue.StringExact(rImageUriV2), @@ -532,6 +534,225 @@ func TestAccBedrockAgentCoreAgentRuntime_artifact(t *testing.T) { }) } +// This test requires a pre-uploaded S3 object containing a ZIP file. +// The test will be skipped if the relevant environment variables are not set. +// A sample ZIP file can be obtained from the AWS Management Console using “Start with a template”. +func TestAccBedrockAgentCoreAgentRuntime_artifactCode(t *testing.T) { + ctx := acctest.Context(t) + var agentRuntime bedrockagentcorecontrol.GetAgentRuntimeOutput + rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + resourceName := "aws_bedrockagentcore_agent_runtime.test" + rCodeS3BucketV1 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V1_S3_BUCKET") + rCodeS3KeyV1 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V1_S3_KEY") + rCodeS3BucketV2 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V2_S3_BUCKET") + rCodeS3KeyV2 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V2_S3_KEY") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) + testAccPreCheckAgentRuntimes(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentCoreServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAgentRuntimeDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAgentRuntimeConfig_codeConfiguration(rName, rCodeS3BucketV1, rCodeS3KeyV1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAgentRuntimeExists(ctx, resourceName, &agentRuntime), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "entry_point": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("main.py"), + }), + "runtime": knownvalue.StringExact(string(awstypes.AgentManagedRuntimeTypePython313)), + "code": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "s3": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrBucket: knownvalue.StringExact(rCodeS3BucketV1), + names.AttrPrefix: knownvalue.StringExact(rCodeS3KeyV1), + "version_id": knownvalue.Null(), + }), + }), + }), + }), + }), + }), + "container_configuration": knownvalue.ListExact([]knownvalue.Check{}), + }), + })), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "agent_runtime_id"), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "agent_runtime_id", + }, + { + Config: testAccAgentRuntimeConfig_codeConfiguration(rName, rCodeS3BucketV2, rCodeS3KeyV2), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAgentRuntimeExists(ctx, resourceName, &agentRuntime), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "entry_point": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("main.py"), + }), + "runtime": knownvalue.StringExact(string(awstypes.AgentManagedRuntimeTypePython313)), + "code": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "s3": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrBucket: knownvalue.StringExact(rCodeS3BucketV2), + names.AttrPrefix: knownvalue.StringExact(rCodeS3KeyV2), + "version_id": knownvalue.Null(), + }), + }), + }), + }), + }), + }), + "container_configuration": knownvalue.ListExact([]knownvalue.Check{}), + }), + })), + }, + }, + }, + }) +} + +// Ensure that changing the artifact type forces a new resource. +func TestAccBedrockAgentCoreAgentRuntime_artifactTypeChanged(t *testing.T) { + ctx := acctest.Context(t) + var agentRuntime bedrockagentcorecontrol.GetAgentRuntimeOutput + rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + resourceName := "aws_bedrockagentcore_agent_runtime.test" + rImageUriV1 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_IMAGE_V1_URI") + rCodeS3BucketV1 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V1_S3_BUCKET") + rCodeS3KeyV1 := acctest.SkipIfEnvVarNotSet(t, "AWS_BEDROCK_AGENTCORE_RUNTIME_CODE_V1_S3_KEY") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) + testAccPreCheckAgentRuntimes(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentCoreServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAgentRuntimeDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAgentRuntimeConfig_basic(rName, rImageUriV1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAgentRuntimeExists(ctx, resourceName, &agentRuntime), + resource.TestCheckResourceAttr(resourceName, "agent_runtime_artifact.0.container_configuration.0.container_uri", rImageUriV1), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{}), + "container_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "container_uri": knownvalue.StringExact(rImageUriV1), + }), + }), + }), + })), + }, + }, + { + // Switch to code artifact, expect destroy/create + Config: testAccAgentRuntimeConfig_codeConfiguration(rName, rCodeS3BucketV1, rCodeS3KeyV1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAgentRuntimeExists(ctx, resourceName, &agentRuntime), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "entry_point": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("main.py"), + }), + "runtime": knownvalue.StringExact(string(awstypes.AgentManagedRuntimeTypePython313)), + "code": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "s3": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrBucket: knownvalue.StringExact(rCodeS3BucketV1), + names.AttrPrefix: knownvalue.StringExact(rCodeS3KeyV1), + "version_id": knownvalue.Null(), + }), + }), + }), + }), + }), + }), + "container_configuration": knownvalue.ListExact([]knownvalue.Check{}), + }), + })), + }, + }, + { + // Switch back to container artifact, expect destroy/create + Config: testAccAgentRuntimeConfig_basic(rName, rImageUriV1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAgentRuntimeExists(ctx, resourceName, &agentRuntime), + resource.TestCheckResourceAttr(resourceName, "agent_runtime_artifact.0.container_configuration.0.container_uri", rImageUriV1), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("agent_runtime_artifact"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "code_configuration": knownvalue.ListExact([]knownvalue.Check{}), + "container_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "container_uri": knownvalue.StringExact(rImageUriV1), + }), + }), + }), + })), + }, + }, + }, + }) +} + func testAccCheckAgentRuntimeDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentCoreClient(ctx) @@ -797,3 +1018,29 @@ resource "aws_bedrockagentcore_agent_runtime" "test" { } `, rName, rImageUri, serverProtocol)) } + +func testAccAgentRuntimeConfig_codeConfiguration(rName, s3Bucket, s3Key string) string { + return acctest.ConfigCompose(testAccAgentRuntimeConfig_baseIAMRole(rName), fmt.Sprintf(` +resource "aws_bedrockagentcore_agent_runtime" "test" { + agent_runtime_name = %[1]q + role_arn = aws_iam_role.test.arn + + agent_runtime_artifact { + code_configuration { + entry_point = ["main.py"] + runtime = "PYTHON_3_13" + code { + s3 { + bucket = %[2]q + prefix = %[3]q + } + } + } + } + + network_configuration { + network_mode = "PUBLIC" + } +} +`, rName, s3Bucket, s3Key)) +} diff --git a/internal/service/bedrockagentcore/browser.go b/internal/service/bedrockagentcore/browser.go index 5a1e95b29810..6bfcf8d289b5 100644 --- a/internal/service/bedrockagentcore/browser.go +++ b/internal/service/bedrockagentcore/browser.go @@ -107,7 +107,7 @@ func (r *browserResource) Schema(ctx context.Context, request resource.SchemaReq }, }, Blocks: map[string]schema.Block{ - "network_mode_config": schema.ListNestedBlock{ + names.AttrVPCConfig: schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[vpcConfigModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), @@ -409,7 +409,7 @@ type browserResourceModel struct { type browserNetworkConfigurationModel struct { NetworkMode fwtypes.StringEnum[awstypes.BrowserNetworkMode] `tfsdk:"network_mode"` - VPCConfig fwtypes.ListNestedObjectValueOf[vpcConfigModel] `tfsdk:"network_mode_config"` + VPCConfig fwtypes.ListNestedObjectValueOf[vpcConfigModel] `tfsdk:"vpc_config"` } type recordingConfigModel struct { diff --git a/internal/service/bedrockagentcore/browser_test.go b/internal/service/bedrockagentcore/browser_test.go index 0e6f630b1827..36b6445ce571 100644 --- a/internal/service/bedrockagentcore/browser_test.go +++ b/internal/service/bedrockagentcore/browser_test.go @@ -11,6 +11,7 @@ import ( "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol" + awstypes "github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" @@ -55,6 +56,10 @@ func TestAccBedrockAgentCoreBrowser_basic(t *testing.T) { ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("browser_arn"), tfknownvalue.RegionalARNRegexp("bedrock-agentcore", regexache.MustCompile(`browser-custom/.+`))), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("browser_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrNetworkConfiguration), knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectExact(map[string]knownvalue.Check{ + "network_mode": tfknownvalue.StringExact(awstypes.BrowserNetworkModePublic), + names.AttrVPCConfig: knownvalue.ListSizeExact(0), + })})), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), }, }, @@ -246,6 +251,15 @@ func TestAccBedrockAgentCoreBrowser_networkConfiguration_vpc(t *testing.T) { plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), }, }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrNetworkConfiguration), knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectExact(map[string]knownvalue.Check{ + "network_mode": tfknownvalue.StringExact(awstypes.BrowserNetworkModeVpc), + names.AttrVPCConfig: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrSecurityGroups: knownvalue.SetSizeExact(1), + names.AttrSubnets: knownvalue.SetSizeExact(2), + })}), + })})), + }, }, { ResourceName: resourceName, @@ -455,7 +469,7 @@ resource "aws_bedrockagentcore_browser" "test" { network_configuration { network_mode = "VPC" - network_mode_config { + vpc_config { security_groups = [aws_security_group.test.id] subnets = aws_subnet.test[*].id } diff --git a/internal/service/bedrockagentcore/gateway_target.go b/internal/service/bedrockagentcore/gateway_target.go index c005c8670559..5702eca15be9 100644 --- a/internal/service/bedrockagentcore/gateway_target.go +++ b/internal/service/bedrockagentcore/gateway_target.go @@ -224,7 +224,6 @@ func (r *gatewayTargetResource) Schema(ctx context.Context, request resource.Sch "credential_provider_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[credentialProviderConfigurationModel](ctx), Validators: []validator.List{ - listvalidator.IsRequired(), listvalidator.SizeAtMost(1), }, NestedObject: schema.NestedBlockObject{ @@ -385,6 +384,25 @@ func (r *gatewayTargetResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "mcp_server": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[mcpServerConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrEndpoint: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexache.MustCompile(`https://.*`), + "Must start with https://", + ), + }, + }, + }, + }, + }, "open_api_schema": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[apiSchemaConfigurationModel](ctx), Validators: []validator.List{ @@ -875,6 +893,8 @@ func (m *targetConfigurationModel) GetConfigurationType(ctx context.Context) str switch mcpData, _ := m.MCP.ToPtr(ctx); { case !mcpData.Lambda.IsNull(): return "lambda" + case !mcpData.MCPServer.IsNull(): + return "mcp_server" case !mcpData.OpenApiSchema.IsNull(): return "open_api_schema" case !mcpData.SmithyModel.IsNull(): @@ -933,6 +953,7 @@ func (m targetConfigurationModel) Expand(ctx context.Context) (any, diag.Diagnos type mcpConfigurationModel struct { Lambda fwtypes.ListNestedObjectValueOf[mcpLambdaConfigurationModel] `tfsdk:"lambda"` + MCPServer fwtypes.ListNestedObjectValueOf[mcpServerConfigurationModel] `tfsdk:"mcp_server"` SmithyModel fwtypes.ListNestedObjectValueOf[apiSchemaConfigurationModel] `tfsdk:"smithy_model"` OpenApiSchema fwtypes.ListNestedObjectValueOf[apiSchemaConfigurationModel] `tfsdk:"open_api_schema"` } @@ -953,6 +974,14 @@ func (m *mcpConfigurationModel) Flatten(ctx context.Context, v any) diag.Diagnos } m.Lambda = fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &model) + case awstypes.McpTargetConfigurationMemberMcpServer: + var model mcpServerConfigurationModel + smerr.AddEnrich(ctx, &diags, fwflex.Flatten(ctx, t.Value, &model)) + if diags.HasError() { + return diags + } + m.MCPServer = fwtypes.NewListNestedObjectValueOfPtrMust(ctx, &model) + case awstypes.McpTargetConfigurationMemberOpenApiSchema: var model apiSchemaConfigurationModel smerr.AddEnrich(ctx, &diags, fwflex.Flatten(ctx, t.Value, &model)) @@ -995,6 +1024,20 @@ func (m mcpConfigurationModel) Expand(ctx context.Context) (any, diag.Diagnostic } return &r, diags + case !m.MCPServer.IsNull(): + mcpServerConfigurationData, d := m.MCPServer.ToPtr(ctx) + smerr.AddEnrich(ctx, &diags, d) + if diags.HasError() { + return nil, diags + } + + var r awstypes.McpTargetConfigurationMemberMcpServer + smerr.AddEnrich(ctx, &diags, fwflex.Expand(ctx, mcpServerConfigurationData, &r.Value)) + if diags.HasError() { + return nil, diags + } + return &r, diags + case !m.OpenApiSchema.IsNull(): openApiMCPConfigurationData, d := m.OpenApiSchema.ToPtr(ctx) smerr.AddEnrich(ctx, &diags, d) @@ -1547,6 +1590,10 @@ type s3ConfigurationModel struct { Uri types.String `tfsdk:"uri"` } +type mcpServerConfigurationModel struct { + Endpoint types.String `tfsdk:"endpoint"` +} + type apiSchemaConfigurationModel struct { InlinePayload fwtypes.ListNestedObjectValueOf[inlinePayloadModel] `tfsdk:"inline_payload"` S3 fwtypes.ListNestedObjectValueOf[s3ConfigurationModel] `tfsdk:"s3"` diff --git a/internal/service/bedrockagentcore/gateway_target_test.go b/internal/service/bedrockagentcore/gateway_target_test.go index a4b9687bb1b4..7e801a28096d 100644 --- a/internal/service/bedrockagentcore/gateway_target_test.go +++ b/internal/service/bedrockagentcore/gateway_target_test.go @@ -241,6 +241,58 @@ func TestAccBedrockAgentCoreGatewayTarget_targetConfiguration(t *testing.T) { }) } +func TestAccBedrockAgentCoreGatewayTarget_targetConfigurationMCPServer(t *testing.T) { + ctx := acctest.Context(t) + var gatewayTarget bedrockagentcorecontrol.GetGatewayTargetOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagentcore_gateway_target.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) + testAccPreCheckGatewayTargets(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentCoreServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayTargetDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayTargetConfig_targetConfigurationMCPServer(rName, "https://knowledge-mcp.global.api.aws"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckGatewayTargetExists(ctx, resourceName, &gatewayTarget), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "target_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_configuration.0.mcp.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_configuration.0.mcp.0.mcp_server.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_configuration.0.mcp.0.mcp_server.0.endpoint", "https://knowledge-mcp.global.api.aws"), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + { + Config: testAccGatewayTargetConfig_targetConfigurationMCPServer(rName, "https://docs.mcp.cloudflare.com/mcp"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckGatewayTargetExists(ctx, resourceName, &gatewayTarget), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "target_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_configuration.0.mcp.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_configuration.0.mcp.0.mcp_server.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_configuration.0.mcp.0.mcp_server.0.endpoint", "https://docs.mcp.cloudflare.com/mcp"), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + }, + }, + }) +} + func TestAccBedrockAgentCoreGatewayTarget_credentialProvider(t *testing.T) { ctx := acctest.Context(t) var gatewayTarget, gatewayTargetPrev bedrockagentcorecontrol.GetGatewayTargetOutput @@ -734,6 +786,23 @@ resource "aws_bedrockagentcore_gateway_target" "test" { `, rName, schemaContent)) } +func testAccGatewayTargetConfig_targetConfigurationMCPServer(rName, endpoint string) string { + return acctest.ConfigCompose(testAccGatewayTargetConfig_infra(rName), fmt.Sprintf(` +resource "aws_bedrockagentcore_gateway_target" "test" { + name = %[1]q + gateway_identifier = aws_bedrockagentcore_gateway.test.gateway_id + + target_configuration { + mcp { + mcp_server { + endpoint = %[2]q + } + } + } +} +`, rName, endpoint)) +} + func testAccSchema_primitive() string { return ` type = "string" diff --git a/internal/service/bedrockagentcore/gateway_test.go b/internal/service/bedrockagentcore/gateway_test.go index 3a1bb3566c16..257d1b288a27 100644 --- a/internal/service/bedrockagentcore/gateway_test.go +++ b/internal/service/bedrockagentcore/gateway_test.go @@ -72,6 +72,41 @@ func TestAccBedrockAgentCoreGateway_basic(t *testing.T) { }) } +func TestAccBedrockAgentCoreGateway_xrayDelivery(t *testing.T) { + ctx := acctest.Context(t) + var gateway bedrockagentcorecontrol.GetGatewayOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagentcore_gateway.test" + deliveryResourceName := "aws_cloudwatch_log_delivery.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) + testAccPreCheckGateways(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentCoreServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayConfig_xrayDelivery(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckGatewayExists(ctx, resourceName, &gateway), + resource.TestCheckResourceAttrSet(deliveryResourceName, names.AttrID), + resource.TestCheckResourceAttr(deliveryResourceName, "delivery_source_name", rName+"-source"), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectResourceAction(deliveryResourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + func TestAccBedrockAgentCoreGateway_disappears(t *testing.T) { ctx := acctest.Context(t) var gateway bedrockagentcorecontrol.GetGatewayOutput @@ -492,6 +527,41 @@ resource "aws_bedrockagentcore_gateway" "test" { `, rName)) } +func testAccGatewayConfig_xrayDelivery(rName string) string { + return acctest.ConfigCompose(testAccGatewayConfig_iamRole(rName), fmt.Sprintf(` +resource "aws_bedrockagentcore_gateway" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + + authorizer_type = "CUSTOM_JWT" + authorizer_configuration { + custom_jwt_authorizer { + discovery_url = "https://accounts.google.com/.well-known/openid-configuration" + allowed_audience = ["test1", "test2"] + } + } + + protocol_type = "MCP" +} + +resource "aws_cloudwatch_log_delivery_source" "test" { + name = "%[1]s-source" + log_type = "TRACES" + resource_arn = aws_bedrockagentcore_gateway.test.gateway_arn +} + +resource "aws_cloudwatch_log_delivery_destination" "test" { + name = "%[1]s-destination" + delivery_destination_type = "XRAY" +} + +resource "aws_cloudwatch_log_delivery" "test" { + delivery_source_name = aws_cloudwatch_log_delivery_source.test.name + delivery_destination_arn = aws_cloudwatch_log_delivery_destination.test.arn +} +`, rName)) +} + func testAccGatewayConfig_protocolConfiguration(rName, instructions string) string { return acctest.ConfigCompose(testAccGatewayConfig_iamRole(rName), fmt.Sprintf(` resource "aws_bedrockagentcore_gateway" "test" { diff --git a/internal/service/cloudformation/stack_set_instance.go b/internal/service/cloudformation/stack_set_instance.go index 167260240dc1..b8a7d82edaaa 100644 --- a/internal/service/cloudformation/stack_set_instance.go +++ b/internal/service/cloudformation/stack_set_instance.go @@ -27,7 +27,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -329,7 +329,7 @@ func resourceStackSetInstanceRead(ctx context.Context, d *schema.ResourceData, m callAs := d.Get("call_as").(string) - if itypes.IsAWSAccountID(accountOrOrgID) { + if inttypes.IsAWSAccountID(accountOrOrgID) { // Stack instances deployed by account ID stackInstance, err := findStackInstanceByFourPartKey(ctx, conn, stackSetName, accountOrOrgID, region, callAs) diff --git a/internal/service/cloudformation/test-fixtures/examplecompany-exampleservice-exampleresource/go.mod b/internal/service/cloudformation/test-fixtures/examplecompany-exampleservice-exampleresource/go.mod index 8df4000e80b7..9d825f516238 100644 --- a/internal/service/cloudformation/test-fixtures/examplecompany-exampleservice-exampleresource/go.mod +++ b/internal/service/cloudformation/test-fixtures/examplecompany-exampleservice-exampleresource/go.mod @@ -1,6 +1,6 @@ module exampleresource -go 1.24.8 +go 1.24.10 require github.com/aws-cloudformation/cloudformation-cli-go-plugin v1.2.0 diff --git a/internal/service/cloudfront/vpc_origin.go b/internal/service/cloudfront/vpc_origin.go index 12b51938214b..23c900e82081 100644 --- a/internal/service/cloudfront/vpc_origin.go +++ b/internal/service/cloudfront/vpc_origin.go @@ -13,7 +13,6 @@ import ( awstypes "github.com/aws/aws-sdk-go-v2/service/cloudfront/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -421,116 +420,3 @@ type originSSLProtocolsModel struct { Items fwtypes.SetOfStringEnum[awstypes.SslProtocol] `tfsdk:"items"` Quantity types.Int64 `tfsdk:"quantity"` } - -var ( - _ fwflex.Expander = vpcOriginEndpointConfigModel{} - _ fwflex.Flattener = &vpcOriginEndpointConfigModel{} -) - -func (m vpcOriginEndpointConfigModel) Expand(ctx context.Context) (any, diag.Diagnostics) { - var diags diag.Diagnostics - - config := &awstypes.VpcOriginEndpointConfig{ - Arn: fwflex.StringFromFramework(ctx, m.ARN), - HTTPPort: aws.Int32(int32(m.HTTPPort.ValueInt64())), - HTTPSPort: aws.Int32(int32(m.HTTPSPort.ValueInt64())), - Name: fwflex.StringFromFramework(ctx, m.Name), - OriginProtocolPolicy: m.OriginProtocolPolicy.ValueEnum(), - } - - if !m.OriginSSLProtocols.IsNull() { - sslList, d := m.OriginSSLProtocols.ToSlice(ctx) - diags.Append(d...) - if diags.HasError() { - return nil, diags - } - if len(sslList) > 0 { - expanded, d := sslList[0].Expand(ctx) - diags.Append(d...) - if diags.HasError() { - return nil, diags - } - if sslProto, ok := expanded.(*awstypes.OriginSslProtocols); ok { - config.OriginSslProtocols = sslProto - } else { - diags.AddError("error expanding Origin SSL Protocols", fmt.Sprintf("expected OriginSslProtocols, got: %T", expanded)) - } - } - } - - return config, diags -} - -func (m *vpcOriginEndpointConfigModel) Flatten(ctx context.Context, v any) diag.Diagnostics { - var diags diag.Diagnostics - - if v == nil { - return diags - } - if t, ok := v.(awstypes.VpcOriginEndpointConfig); ok { - m.ARN = fwflex.StringToFramework(ctx, t.Arn) - m.HTTPPort = types.Int64Value(int64(aws.ToInt32(t.HTTPPort))) - m.HTTPSPort = types.Int64Value(int64(aws.ToInt32(t.HTTPSPort))) - m.Name = fwflex.StringToFramework(ctx, t.Name) - m.OriginProtocolPolicy = fwtypes.StringEnumValue(t.OriginProtocolPolicy) - - if t.OriginSslProtocols != nil { - var sslModel originSSLProtocolsModel - diags.Append(fwflex.Flatten(ctx, t.OriginSslProtocols, &sslModel)...) - if diags.HasError() { - return diags - } - sslList, d := fwtypes.NewListNestedObjectValueOfPtr(ctx, &sslModel) - diags.Append(d...) - if diags.HasError() { - return diags - } - m.OriginSSLProtocols = sslList - } - } else { - diags.AddError("error flattening VPC Origin Endpoint Config", fmt.Sprintf("expected VpcOriginEndpointConfig, got: %T", v)) - } - return diags -} - -var ( - _ fwflex.Expander = originSSLProtocolsModel{} - _ fwflex.Flattener = &originSSLProtocolsModel{} -) - -func (m originSSLProtocolsModel) Expand(ctx context.Context) (any, diag.Diagnostics) { - var diags diag.Diagnostics - - var protocols []awstypes.SslProtocol - diags.Append(fwflex.Expand(ctx, m.Items, &protocols)...) - if diags.HasError() { - return nil, diags - } - - result := awstypes.OriginSslProtocols{ - Items: protocols, - Quantity: aws.Int32(int32(m.Quantity.ValueInt64())), - } - - return &result, diags -} - -func (m *originSSLProtocolsModel) Flatten(ctx context.Context, v any) diag.Diagnostics { - var diags diag.Diagnostics - - if v == nil { - return diags - } - - if t, ok := v.(awstypes.OriginSslProtocols); ok { - diags.Append(fwflex.Flatten(ctx, t.Items, &m.Items)...) - if diags.HasError() { - return diags - } - - m.Quantity = types.Int64Value(int64(aws.ToInt32(t.Quantity))) - } else { - diags.AddError("error flattening Origin SSL Protocols", fmt.Sprintf("expected OriginSslProtocols, got: %T", v)) - } - return diags -} diff --git a/internal/service/cognitoidp/user_pool_data_source_tags_gen_test.go b/internal/service/cognitoidp/user_pool_data_source_tags_gen_test.go index 98eeeff2a1f3..d0ae98ba0c80 100644 --- a/internal/service/cognitoidp/user_pool_data_source_tags_gen_test.go +++ b/internal/service/cognitoidp/user_pool_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfcognitoidp "github.com/hashicorp/terraform-provider-aws/internal/service/cognitoidp" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccCognitoIDPUserPoolDataSource_tags_IgnoreTags_Overlap_ResourceTag(t * } func expectFullUserPoolDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfcognitoidp.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfcognitoidp.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/cognitoidp/user_pool_ui_customization.go b/internal/service/cognitoidp/user_pool_ui_customization.go index f59d80182680..b2aaa05b5b89 100644 --- a/internal/service/cognitoidp/user_pool_ui_customization.go +++ b/internal/service/cognitoidp/user_pool_ui_customization.go @@ -19,7 +19,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -99,7 +99,7 @@ func resourceUserPoolUICustomizationPut(ctx context.Context, d *schema.ResourceD } if v, ok := d.GetOk("image_file"); ok { - v, err := itypes.Base64Decode(v.(string)) + v, err := inttypes.Base64Decode(v.(string)) if err != nil { return sdkdiag.AppendFromErr(diags, err) } @@ -197,7 +197,7 @@ func findUserPoolUICustomizationByTwoPartKey(ctx context.Context, conn *cognitoi // The GetUICustomization API operation will return an empty struct // if nothing is present rather than nil or an error, so we equate that with nil. - if output == nil || output.UICustomization == nil || itypes.IsZero(output.UICustomization) { + if output == nil || output.UICustomization == nil || inttypes.IsZero(output.UICustomization) { return nil, tfresource.NewEmptyResultError(input) } diff --git a/internal/service/comprehend/test-fixtures/generate/document_classifier/main.go b/internal/service/comprehend/test-fixtures/generate/document_classifier/main.go index b2fb0c8a28f8..200f85564177 100644 --- a/internal/service/comprehend/test-fixtures/generate/document_classifier/main.go +++ b/internal/service/comprehend/test-fixtures/generate/document_classifier/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/service/comprehend/test-fixtures/generate/document_classifier_multilabel/main.go b/internal/service/comprehend/test-fixtures/generate/document_classifier_multilabel/main.go index 36cc3ca1965e..514cf5ec3f39 100644 --- a/internal/service/comprehend/test-fixtures/generate/document_classifier_multilabel/main.go +++ b/internal/service/comprehend/test-fixtures/generate/document_classifier_multilabel/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go b/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go index 107595fa50f2..8024a5a7e45f 100644 --- a/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go +++ b/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build generate -// +build generate package main diff --git a/internal/service/connect/connect_test.go b/internal/service/connect/connect_test.go index 4f9a955fd5bb..1bd9d0800121 100644 --- a/internal/service/connect/connect_test.go +++ b/internal/service/connect/connect_test.go @@ -128,6 +128,7 @@ func TestAccConnect_serial(t *testing.T) { acctest.CtDisappears: testAccRoutingProfile_disappears, "tags": testAccRoutingProfile_updateTags, "concurrency": testAccRoutingProfile_updateConcurrency, + "crossChannelBehavior": testAccRoutingProfile_crossChannelBehavior, "defaultOutboundQueue": testAccRoutingProfile_updateDefaultOutboundQueue, "queues": testAccRoutingProfile_updateQueues, "createQueueBatchAssociations": testAccRoutingProfile_createQueueConfigsBatchedAssociateDisassociate, diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index b888578dbff2..279ce2a972ad 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -78,6 +78,20 @@ func resourceRoutingProfile() *schema.Resource { Required: true, ValidateFunc: validation.IntBetween(1, 10), }, + "cross_channel_behavior": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "behavior_type": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.BehaviorType](), + }, + }, + }, + }, }, }, }, @@ -138,7 +152,7 @@ func resourceRoutingProfileCreate(ctx context.Context, d *schema.ResourceData, m instanceID := d.Get(names.AttrInstanceID).(string) name := d.Get(names.AttrName).(string) - input := &connect.CreateRoutingProfileInput{ + input := connect.CreateRoutingProfileInput{ DefaultOutboundQueueId: aws.String(d.Get("default_outbound_queue_id").(string)), Description: aws.String(d.Get(names.AttrDescription).(string)), InstanceId: aws.String(instanceID), @@ -156,7 +170,7 @@ func resourceRoutingProfileCreate(ctx context.Context, d *schema.ResourceData, m input.QueueConfigs = queueConfigs } - output, err := conn.CreateRoutingProfile(ctx, input) + output, err := conn.CreateRoutingProfile(ctx, &input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating Connect Routing Profile (%s): %s", name, err) @@ -185,7 +199,7 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendFromErr(diags, err) } - routingProfile, err := findRoutingProfileByTwoPartKey(ctx, conn, instanceID, routingProfileID) + output, err := findRoutingProfileByTwoPartKey(ctx, conn, instanceID, routingProfileID) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] Connect Routing Profile (%s) not found, removing from state", d.Id()) @@ -197,15 +211,15 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendErrorf(diags, "reading Connect Routing Profile (%s): %s", d.Id(), err) } - d.Set(names.AttrARN, routingProfile.RoutingProfileArn) - d.Set("default_outbound_queue_id", routingProfile.DefaultOutboundQueueId) - d.Set(names.AttrDescription, routingProfile.Description) + d.Set(names.AttrARN, output.RoutingProfileArn) + d.Set("default_outbound_queue_id", output.DefaultOutboundQueueId) + d.Set(names.AttrDescription, output.Description) d.Set(names.AttrInstanceID, instanceID) - if err := d.Set("media_concurrencies", flattenMediaConcurrencies(routingProfile.MediaConcurrencies)); err != nil { + if err := d.Set("media_concurrencies", flattenMediaConcurrencies(output.MediaConcurrencies, d.Get("media_concurrencies").(*schema.Set).List())); err != nil { return sdkdiag.AppendErrorf(diags, "setting media_concurrencies: %s", err) } - d.Set(names.AttrName, routingProfile.Name) - d.Set("routing_profile_id", routingProfile.RoutingProfileId) + d.Set(names.AttrName, output.Name) + d.Set("routing_profile_id", output.RoutingProfileId) queueConfigs, err := findRoutingConfigQueueConfigSummariesByTwoPartKey(ctx, conn, instanceID, routingProfileID) @@ -217,7 +231,7 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met return sdkdiag.AppendErrorf(diags, "setting queue_configs: %s", err) } - setTagsOut(ctx, routingProfile.Tags) + setTagsOut(ctx, output.Tags) return diags } @@ -239,13 +253,13 @@ func resourceRoutingProfileUpdate(ctx context.Context, d *schema.ResourceData, m if d.HasChange("media_concurrencies") { // updates to concurrency - input := &connect.UpdateRoutingProfileConcurrencyInput{ + input := connect.UpdateRoutingProfileConcurrencyInput{ InstanceId: aws.String(instanceID), MediaConcurrencies: expandMediaConcurrencies(d.Get("media_concurrencies").(*schema.Set).List()), RoutingProfileId: aws.String(routingProfileID), } - _, err = conn.UpdateRoutingProfileConcurrency(ctx, input) + _, err = conn.UpdateRoutingProfileConcurrency(ctx, &input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating Connect Routing Profile (%s) Concurrency: %s", d.Id(), err) @@ -254,13 +268,13 @@ func resourceRoutingProfileUpdate(ctx context.Context, d *schema.ResourceData, m if d.HasChange("default_outbound_queue_id") { // updates to default outbound queue id - input := &connect.UpdateRoutingProfileDefaultOutboundQueueInput{ + input := connect.UpdateRoutingProfileDefaultOutboundQueueInput{ DefaultOutboundQueueId: aws.String(d.Get("default_outbound_queue_id").(string)), InstanceId: aws.String(instanceID), RoutingProfileId: aws.String(routingProfileID), } - _, err = conn.UpdateRoutingProfileDefaultOutboundQueue(ctx, input) + _, err = conn.UpdateRoutingProfileDefaultOutboundQueue(ctx, &input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating Connect Routing Profile (%s) DefaultOutboundQueue: %s", d.Id(), err) @@ -269,14 +283,14 @@ func resourceRoutingProfileUpdate(ctx context.Context, d *schema.ResourceData, m if d.HasChanges(names.AttrName, names.AttrDescription) { // updates to name and/or description - input := &connect.UpdateRoutingProfileNameInput{ + input := connect.UpdateRoutingProfileNameInput{ Description: aws.String(d.Get(names.AttrDescription).(string)), InstanceId: aws.String(instanceID), Name: aws.String(d.Get(names.AttrName).(string)), RoutingProfileId: aws.String(routingProfileID), } - _, err = conn.UpdateRoutingProfileName(ctx, input) + _, err = conn.UpdateRoutingProfileName(ctx, &input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating Connect Routing Profile (%s) Name: %s", d.Id(), err) @@ -368,13 +382,13 @@ func updateRoutingProfileQueueAssociations(ctx context.Context, conn *connect.Cl } if len(queueReferences) > 0 { - input := &connect.DisassociateRoutingProfileQueuesInput{ + input := connect.DisassociateRoutingProfileQueuesInput{ InstanceId: aws.String(instanceID), QueueReferences: queueReferences, RoutingProfileId: aws.String(routingProfileID), } - _, err := conn.DisassociateRoutingProfileQueues(ctx, input) + _, err := conn.DisassociateRoutingProfileQueues(ctx, &input) if err != nil { return fmt.Errorf("disassociating Connect Routing Profile (%s) queues: %w", routingProfileID, err) @@ -383,13 +397,13 @@ func updateRoutingProfileQueueAssociations(ctx context.Context, conn *connect.Cl } for chunk := range slices.Chunk(add, routingProfileQueueAssociationChunkSize) { - input := &connect.AssociateRoutingProfileQueuesInput{ + input := connect.AssociateRoutingProfileQueuesInput{ InstanceId: aws.String(instanceID), QueueConfigs: chunk, RoutingProfileId: aws.String(routingProfileID), } - _, err := conn.AssociateRoutingProfileQueues(ctx, input) + _, err := conn.AssociateRoutingProfileQueues(ctx, &input) if err != nil { return fmt.Errorf("associating Connect Routing Profile (%s) queues: %w", routingProfileID, err) @@ -400,12 +414,12 @@ func updateRoutingProfileQueueAssociations(ctx context.Context, conn *connect.Cl } func findRoutingProfileByTwoPartKey(ctx context.Context, conn *connect.Client, instanceID, routingProfileID string) (*awstypes.RoutingProfile, error) { - input := &connect.DescribeRoutingProfileInput{ + input := connect.DescribeRoutingProfileInput{ InstanceId: aws.String(instanceID), RoutingProfileId: aws.String(routingProfileID), } - return findRoutingProfile(ctx, conn, input) + return findRoutingProfile(ctx, conn, &input) } func findRoutingProfile(ctx context.Context, conn *connect.Client, input *connect.DescribeRoutingProfileInput) (*awstypes.RoutingProfile, error) { @@ -431,13 +445,13 @@ func findRoutingProfile(ctx context.Context, conn *connect.Client, input *connec func findRoutingConfigQueueConfigSummariesByTwoPartKey(ctx context.Context, conn *connect.Client, instanceID, routingProfileID string) ([]awstypes.RoutingProfileQueueConfigSummary, error) { const maxResults = 60 - input := &connect.ListRoutingProfileQueuesInput{ + input := connect.ListRoutingProfileQueuesInput{ InstanceId: aws.String(instanceID), MaxResults: aws.Int32(maxResults), RoutingProfileId: aws.String(routingProfileID), } - return findRoutingConfigQueueConfigSummaries(ctx, conn, input) + return findRoutingConfigQueueConfigSummaries(ctx, conn, &input) } func findRoutingConfigQueueConfigSummaries(ctx context.Context, conn *connect.Client, input *connect.ListRoutingProfileQueuesInput) ([]awstypes.RoutingProfileQueueConfigSummary, error) { @@ -477,13 +491,18 @@ func expandMediaConcurrencies(tfList []any) []awstypes.MediaConcurrency { Channel: awstypes.Channel(tfMap["channel"].(string)), Concurrency: aws.Int32(int32(tfMap["concurrency"].(int))), } + + if v, ok := tfMap["cross_channel_behavior"].([]any); ok && len(v) > 0 { + apiObject.CrossChannelBehavior = expandCrossChannelBehavior(v) + } + apiObjects = append(apiObjects, apiObject) } return apiObjects } -func flattenMediaConcurrencies(apiObjects []awstypes.MediaConcurrency) []any { +func flattenMediaConcurrencies(apiObjects []awstypes.MediaConcurrency, mediaConcurrencyCfg []any) []any { tfList := []any{} for _, apiObject := range apiObjects { @@ -492,12 +511,43 @@ func flattenMediaConcurrencies(apiObjects []awstypes.MediaConcurrency) []any { "concurrency": aws.ToInt32(apiObject.Concurrency), } + // Only write cross_channel_behavior to state when explicitly configured + channel := string(apiObject.Channel) + ccbChannels := channelsWithCrossChannelBehavior(mediaConcurrencyCfg) + if apiObject.CrossChannelBehavior != nil && slices.Contains(ccbChannels, channel) { + tfMap["cross_channel_behavior"] = flattenCrossChannelBehavior(apiObject.CrossChannelBehavior) + } + tfList = append(tfList, tfMap) } return tfList } +func expandCrossChannelBehavior(tfList []any) *awstypes.CrossChannelBehavior { + if len(tfList) == 0 { + return nil + } + + tfMap := tfList[0].(map[string]any) + + return &awstypes.CrossChannelBehavior{ + BehaviorType: awstypes.BehaviorType(tfMap["behavior_type"].(string)), + } +} + +func flattenCrossChannelBehavior(apiObject *awstypes.CrossChannelBehavior) []map[string]any { + if apiObject == nil { + return nil + } + + return []map[string]any{ + { + "behavior_type": string(apiObject.BehaviorType), + }, + } +} + func expandRoutingProfileQueueConfigs(tfList []any) []awstypes.RoutingProfileQueueConfig { if len(tfList) == 0 { return nil @@ -540,3 +590,25 @@ func flattenRoutingConfigQueueConfigSummaries(apiObjects []awstypes.RoutingProfi return tfList } + +// channelsWithCrossChannelBehavior returns a list of channel names which have +// cross_channel_behavior set +// +// This data structure can be used to determine when to write the remote cross_channel_behavior +// value to state. Writing the value when a corresponding congiuration is not present +// will trigger persistent drift as the object is nested within a required set attribute. +func channelsWithCrossChannelBehavior(cfgList []any) []string { + var c []string + for _, l := range cfgList { + m := l.(map[string]any) + if m == nil { + continue + } + + if v, ok := m["cross_channel_behavior"].([]any); ok && len(v) > 0 { + c = append(c, m["channel"].(string)) + } + } + + return c +} diff --git a/internal/service/connect/routing_profile_data_source.go b/internal/service/connect/routing_profile_data_source.go index e80799e5d7d8..0f788c8493e0 100644 --- a/internal/service/connect/routing_profile_data_source.go +++ b/internal/service/connect/routing_profile_data_source.go @@ -59,6 +59,18 @@ func dataSourceRoutingProfile() *schema.Resource { Type: schema.TypeInt, Computed: true, }, + "cross_channel_behavior": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "behavior_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, }, }, }, @@ -146,7 +158,7 @@ func dataSourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, m d.Set("default_outbound_queue_id", routingProfile.DefaultOutboundQueueId) d.Set(names.AttrDescription, routingProfile.Description) d.Set(names.AttrInstanceID, instanceID) - if err := d.Set("media_concurrencies", flattenMediaConcurrencies(routingProfile.MediaConcurrencies)); err != nil { + if err := d.Set("media_concurrencies", flattenMediaConcurrencies(routingProfile.MediaConcurrencies, d.Get("media_concurrencies").(*schema.Set).List())); err != nil { return sdkdiag.AppendErrorf(diags, "setting media_concurrencies: %s", err) } d.Set(names.AttrName, routingProfile.Name) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index c1e2aee9a6f4..cb20b539e61b 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -335,6 +335,80 @@ func testAccRoutingProfile_updateQueues(t *testing.T) { }) } +func testAccRoutingProfile_crossChannelBehavior(t *testing.T) { + ctx := acctest.Context(t) + var v awstypes.RoutingProfile + rName := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + resourceName := "aws_connect_routing_profile.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ConnectServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRoutingProfileDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRoutingProfileConfig_crossChannelBehaviorDefault(rName, rName2, rName3), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{ + "channel": string(awstypes.ChannelVoice), + "concurrency": "1", + "cross_channel_behavior.#": "0", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{ + "channel": string(awstypes.ChannelChat), + "concurrency": "2", + "cross_channel_behavior.#": "0", + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRoutingProfileConfig_crossChannelBehaviorCurrentChannelOnly(rName, rName2, rName3), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{ + "channel": string(awstypes.ChannelVoice), + "concurrency": "1", + "cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteCurrentChannelOnly), + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{ + "channel": string(awstypes.ChannelChat), + "concurrency": "3", + "cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteCurrentChannelOnly), + }), + ), + }, + { + Config: testAccRoutingProfileConfig_crossChannelBehaviorMixed(rName, rName2, rName3), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{ + "channel": string(awstypes.ChannelVoice), + "concurrency": "1", + "cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteAnyChannel), + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{ + "channel": string(awstypes.ChannelChat), + "concurrency": "3", + "cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteCurrentChannelOnly), + }), + ), + }, + }, + }) +} + func testAccRoutingProfile_updateTags(t *testing.T) { ctx := acctest.Context(t) var v awstypes.RoutingProfile @@ -997,3 +1071,98 @@ resource "aws_connect_routing_profile" "test" { } `, rName3)) } + +func testAccRoutingProfileConfig_crossChannelBehaviorDefault(rName, rName2, rName3 string) string { + return acctest.ConfigCompose( + testAccRoutingProfileConfig_base(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = "Test cross-channel behavior - default" + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + # behaviour uses AWS server-side default + } + + media_concurrencies { + channel = "CHAT" + concurrency = 2 + # behaviour uses AWS server-side default + } + + tags = { + "Name" = "Test Routing Profile Cross-Channel Behavior", + } +} +`, rName3)) +} + +func testAccRoutingProfileConfig_crossChannelBehaviorCurrentChannelOnly(rName, rName2, rName3 string) string { + return acctest.ConfigCompose( + testAccRoutingProfileConfig_base(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = "Test cross-channel behavior - current channel only" + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + cross_channel_behavior { + behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY" + } + } + + media_concurrencies { + channel = "CHAT" + concurrency = 3 + cross_channel_behavior { + behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY" + } + } + + tags = { + "Name" = "Test Routing Profile Cross-Channel Behavior", + } +} +`, rName3)) +} + +func testAccRoutingProfileConfig_crossChannelBehaviorMixed(rName, rName2, rName3 string) string { + return acctest.ConfigCompose( + testAccRoutingProfileConfig_base(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = "Test cross-channel behavior - mixed" + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + cross_channel_behavior { + behavior_type = "ROUTE_ANY_CHANNEL" + } + } + + media_concurrencies { + channel = "CHAT" + concurrency = 3 + cross_channel_behavior { + behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY" + } + } + + tags = { + "Name" = "Test Routing Profile Cross-Channel Behavior", + } +} +`, rName3)) +} diff --git a/internal/service/dataexchange/revision_assets.go b/internal/service/dataexchange/revision_assets.go index e8aaec60ca1b..1ef67c5302fe 100644 --- a/internal/service/dataexchange/revision_assets.go +++ b/internal/service/dataexchange/revision_assets.go @@ -45,7 +45,7 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" "github.com/hashicorp/terraform-provider-aws/version" ) @@ -1061,5 +1061,5 @@ func md5Reader(src io.Reader) (string, error) { return "", err } - return itypes.Base64Encode(h.Sum(nil)), nil + return inttypes.Base64Encode(h.Sum(nil)), nil } diff --git a/internal/service/datapipeline/pipeline_data_source_tags_gen_test.go b/internal/service/datapipeline/pipeline_data_source_tags_gen_test.go index 86ed0cbdbaaf..b0de6620c3d2 100644 --- a/internal/service/datapipeline/pipeline_data_source_tags_gen_test.go +++ b/internal/service/datapipeline/pipeline_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfdatapipeline "github.com/hashicorp/terraform-provider-aws/internal/service/datapipeline" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccDataPipelinePipelineDataSource_tags_IgnoreTags_Overlap_ResourceTag(t } func expectFullPipelineDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfdatapipeline.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfdatapipeline.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Pipeline", }), knownValue) diff --git a/internal/service/datasync/location_hdfs.go b/internal/service/datasync/location_hdfs.go index 13d509cdb408..cb7ed7ca2f57 100644 --- a/internal/service/datasync/location_hdfs.go +++ b/internal/service/datasync/location_hdfs.go @@ -22,7 +22,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -196,7 +196,7 @@ func resourceLocationHDFSCreate(ctx context.Context, d *schema.ResourceData, met input.KerberosKeytab = []byte(v.(string)) } else if v, ok := d.GetOk("kerberos_keytab_base64"); ok { v := v.(string) - b, err := itypes.Base64Decode(v) + b, err := inttypes.Base64Decode(v) if err != nil { b = []byte(v) } @@ -207,7 +207,7 @@ func resourceLocationHDFSCreate(ctx context.Context, d *schema.ResourceData, met input.KerberosKrb5Conf = []byte(v.(string)) } else if v, ok := d.GetOk("kerberos_krb5_conf_base64"); ok { v := v.(string) - b, err := itypes.Base64Decode(v) + b, err := inttypes.Base64Decode(v) if err != nil { b = []byte(v) } @@ -313,7 +313,7 @@ func resourceLocationHDFSUpdate(ctx context.Context, d *schema.ResourceData, met input.KerberosKeytab = []byte(v.(string)) } else if v, ok := d.GetOk("kerberos_keytab_base64"); ok { v := v.(string) - b, err := itypes.Base64Decode(v) + b, err := inttypes.Base64Decode(v) if err != nil { b = []byte(v) } @@ -326,7 +326,7 @@ func resourceLocationHDFSUpdate(ctx context.Context, d *schema.ResourceData, met input.KerberosKrb5Conf = []byte(v.(string)) } else if v, ok := d.GetOk("kerberos_krb5_conf_base64"); ok { v := v.(string) - b, err := itypes.Base64Decode(v) + b, err := inttypes.Base64Decode(v) if err != nil { b = []byte(v) } diff --git a/internal/service/dms/certificate.go b/internal/service/dms/certificate.go index cc4f8b4b52c3..0ce0f5b5d38a 100644 --- a/internal/service/dms/certificate.go +++ b/internal/service/dms/certificate.go @@ -20,7 +20,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -88,7 +88,7 @@ func resourceCertificateCreate(ctx context.Context, d *schema.ResourceData, meta } if v, ok := d.GetOk("certificate_wallet"); ok { - v, err := itypes.Base64Decode(v.(string)) + v, err := inttypes.Base64Decode(v.(string)) if err != nil { return sdkdiag.AppendFromErr(diags, err) } @@ -129,7 +129,7 @@ func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta a d.Set("certificate_pem", v) } if len(certificate.CertificateWallet) != 0 { - d.Set("certificate_wallet", itypes.Base64EncodeOnce(certificate.CertificateWallet)) + d.Set("certificate_wallet", inttypes.Base64EncodeOnce(certificate.CertificateWallet)) } return diags diff --git a/internal/service/dms/certificate_data_source.go b/internal/service/dms/certificate_data_source.go index 9e76e1f62b5d..3ac81798d96e 100644 --- a/internal/service/dms/certificate_data_source.go +++ b/internal/service/dms/certificate_data_source.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -95,7 +95,7 @@ func dataSourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta d.Set("certificate_id", out.CertificateIdentifier) d.Set("certificate_pem", out.CertificatePem) if len(out.CertificateWallet) != 0 { - d.Set("certificate_wallet", itypes.Base64EncodeOnce(out.CertificateWallet)) + d.Set("certificate_wallet", inttypes.Base64EncodeOnce(out.CertificateWallet)) } d.Set("key_length", out.KeyLength) d.Set("signing_algorithm", out.SigningAlgorithm) diff --git a/internal/service/docdb/cluster.go b/internal/service/docdb/cluster.go index b672d280ece3..917232a21ef6 100644 --- a/internal/service/docdb/cluster.go +++ b/internal/service/docdb/cluster.go @@ -29,7 +29,7 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -1123,7 +1123,7 @@ func findDBClusters(ctx context.Context, conn *docdb.Client, input *docdb.Descri } for _, v := range page.DBClusters { - if !itypes.IsZero(&v) && filter(&v) { + if !inttypes.IsZero(&v) && filter(&v) { output = append(output, v) } } diff --git a/internal/service/docdb/cluster_parameter_group.go b/internal/service/docdb/cluster_parameter_group.go index d76992a040b1..b34937813aee 100644 --- a/internal/service/docdb/cluster_parameter_group.go +++ b/internal/service/docdb/cluster_parameter_group.go @@ -23,7 +23,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -289,7 +289,7 @@ func findDBClusterParameterGroups(ctx context.Context, conn *docdb.Client, input } for _, v := range page.DBClusterParameterGroups { - if !itypes.IsZero(&v) { + if !inttypes.IsZero(&v) { output = append(output, v) } } @@ -317,7 +317,7 @@ func findDBClusterParameters(ctx context.Context, conn *docdb.Client, input *doc } for _, v := range page.Parameters { - if !itypes.IsZero(&v) { + if !inttypes.IsZero(&v) { output = append(output, v) } } diff --git a/internal/service/docdb/cluster_snapshot.go b/internal/service/docdb/cluster_snapshot.go index 6213e76d11ea..9afd07e52128 100644 --- a/internal/service/docdb/cluster_snapshot.go +++ b/internal/service/docdb/cluster_snapshot.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -227,7 +227,7 @@ func findClusterSnapshots(ctx context.Context, conn *docdb.Client, input *docdb. } for _, v := range page.DBClusterSnapshots { - if !itypes.IsZero(&v) { + if !inttypes.IsZero(&v) { output = append(output, v) } } diff --git a/internal/service/docdb/event_subscription.go b/internal/service/docdb/event_subscription.go index 9b0301166448..778cb44cbb84 100644 --- a/internal/service/docdb/event_subscription.go +++ b/internal/service/docdb/event_subscription.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -329,7 +329,7 @@ func findEventSubscriptions(ctx context.Context, conn *docdb.Client, input *docd } for _, v := range page.EventSubscriptionsList { - if !itypes.IsZero(&v) { + if !inttypes.IsZero(&v) { output = append(output, v) } } diff --git a/internal/service/docdb/global_cluster.go b/internal/service/docdb/global_cluster.go index 1efcb4b2c98a..1dc1fa07a3e6 100644 --- a/internal/service/docdb/global_cluster.go +++ b/internal/service/docdb/global_cluster.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -377,7 +377,7 @@ func findGlobalClusters(ctx context.Context, conn *docdb.Client, input *docdb.De } for _, v := range page.GlobalClusters { - if !itypes.IsZero(&v) && filter(&v) { + if !inttypes.IsZero(&v) && filter(&v) { output = append(output, v) } } diff --git a/internal/service/docdb/orderable_db_instance_data_source.go b/internal/service/docdb/orderable_db_instance_data_source.go index cdd65c2cf63e..cae72b993bf7 100644 --- a/internal/service/docdb/orderable_db_instance_data_source.go +++ b/internal/service/docdb/orderable_db_instance_data_source.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -156,7 +156,7 @@ func findOrderableDBInstances(ctx context.Context, conn *docdb.Client, input *do } for _, v := range page.OrderableDBInstanceOptions { - if !itypes.IsZero(&v) { + if !inttypes.IsZero(&v) { output = append(output, v) } } diff --git a/internal/service/dynamodb/create_backup_action.go b/internal/service/dynamodb/create_backup_action.go new file mode 100644 index 000000000000..ef80edd55caa --- /dev/null +++ b/internal/service/dynamodb/create_backup_action.go @@ -0,0 +1,195 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dynamodb + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + awstypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/action" + "github.com/hashicorp/terraform-plugin-framework/action/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-provider-aws/internal/actionwait" + "github.com/hashicorp/terraform-provider-aws/internal/backoff" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @Action(aws_dynamodb_create_backup, name="Create Backup") +func newCreateBackupAction(_ context.Context) (action.ActionWithConfigure, error) { + return &createBackupAction{}, nil +} + +var ( + _ action.Action = (*createBackupAction)(nil) +) + +type createBackupAction struct { + framework.ActionWithModel[createBackupActionModel] +} + +type createBackupActionModel struct { + framework.WithRegionModel + TableName types.String `tfsdk:"table_name"` + BackupName types.String `tfsdk:"backup_name"` + Timeout types.Int64 `tfsdk:"timeout"` +} + +func (a *createBackupAction) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "Creates an on-demand backup of a DynamoDB table. The backup is created asynchronously and typically completes within minutes.", + Attributes: map[string]schema.Attribute{ + names.AttrTableName: schema.StringAttribute{ + Description: "The name or ARN of the DynamoDB table to backup", + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 1024), + }, + }, + "backup_name": schema.StringAttribute{ + Description: "Name for the backup. If not provided, a name will be generated automatically using the table name and a unique identifier", + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(3, 255), + stringvalidator.RegexMatches( + regexache.MustCompile(`^[a-zA-Z0-9_.-]+$`), + "must contain only alphanumeric characters, underscores, periods, and hyphens", + ), + }, + }, + names.AttrTimeout: schema.Int64Attribute{ + Description: "Timeout in minutes for the backup operation. Defaults to 10 minutes", + Optional: true, + }, + }, + } +} + +func (a *createBackupAction) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) { + var config createBackupActionModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + conn := a.Meta().DynamoDBClient(ctx) + + timeout := 10 * time.Minute + if !config.Timeout.IsNull() { + timeout = time.Duration(config.Timeout.ValueInt64()) * time.Minute + } + + tableName := config.TableName.ValueString() + backupName := config.BackupName.ValueString() + + if backupName == "" { + backupName = fmt.Sprintf("%s-backup-%s", tableName, id.UniqueId()) + } + + tflog.Info(ctx, "Starting DynamoDB create backup action", map[string]any{ + names.AttrTableName: tableName, + "backup_name": backupName, + }) + + resp.SendProgress(action.InvokeProgressEvent{ + Message: fmt.Sprintf("Starting backup creation for DynamoDB table %s...", tableName), + }) + + input := &dynamodb.CreateBackupInput{ + TableName: aws.String(tableName), + BackupName: aws.String(backupName), + } + + var output *dynamodb.CreateBackupOutput + var err error + for l := backoff.NewLoop(timeout); l.Continue(ctx); { + output, err = conn.CreateBackup(ctx, input) + + if err != nil { + if errs.IsAErrorMessageContains[*awstypes.ContinuousBackupsUnavailableException](err, "Backups are being enabled") { + continue + } + + if errs.IsA[*awstypes.BackupInUseException](err) || errs.IsA[*awstypes.LimitExceededException](err) { + continue + } + } + + break + } + + if err != nil { + resp.Diagnostics.AddError("creating DynamoDB backup", err.Error()) + return + } + + backupArn := aws.ToString(output.BackupDetails.BackupArn) + + resp.SendProgress(action.InvokeProgressEvent{ + Message: "Backup started, waiting for completion...", + }) + + result, err := actionwait.WaitForStatus(ctx, func(ctx context.Context) (actionwait.FetchResult[*awstypes.BackupDescription], error) { + input := &dynamodb.DescribeBackupInput{BackupArn: aws.String(backupArn)} + output, err := conn.DescribeBackup(ctx, input) + if err != nil { + return actionwait.FetchResult[*awstypes.BackupDescription]{}, err + } + desc := output.BackupDescription + return actionwait.FetchResult[*awstypes.BackupDescription]{Status: actionwait.Status(desc.BackupDetails.BackupStatus), Value: desc}, nil + }, actionwait.Options[*awstypes.BackupDescription]{ + Timeout: timeout, + Interval: actionwait.WithBackoffDelay(backoff.DefaultSDKv2HelperRetryCompatibleDelay()), + ProgressInterval: 30 * time.Second, + SuccessStates: []actionwait.Status{actionwait.Status(awstypes.BackupStatusAvailable)}, + TransitionalStates: []actionwait.Status{actionwait.Status(awstypes.BackupStatusCreating)}, + FailureStates: []actionwait.Status{actionwait.Status(awstypes.BackupStatusDeleted)}, + ProgressSink: func(fr actionwait.FetchResult[any], meta actionwait.ProgressMeta) { + resp.SendProgress(action.InvokeProgressEvent{Message: "Backup currently in state: " + string(fr.Status)}) + }, + }) + if err != nil { + var timeoutErr *actionwait.TimeoutError + var failureErr *actionwait.FailureStateError + var unexpectedErr *actionwait.UnexpectedStateError + if errors.As(err, &timeoutErr) { + resp.Diagnostics.AddError("Backup timeout", "Backup did not complete within the specified timeout") + } else if errors.As(err, &failureErr) { + resp.Diagnostics.AddError("Backup failed", "Backup completed with status: "+err.Error()) + } else if errors.As(err, &unexpectedErr) { + resp.Diagnostics.AddError("Unexpected backup status", err.Error()) + } else { + resp.Diagnostics.AddError("Error waiting for backup", err.Error()) + } + return + } + + backupDetails := result.Value.BackupDetails + backupInfo := fmt.Sprintf("Backup completed successfully\n"+ + " ARN: %s\n"+ + " Created: %s\n"+ + " Size: %d bytes", + aws.ToString(backupDetails.BackupArn), + backupDetails.BackupCreationDateTime.Format(time.RFC3339), + aws.ToInt64(backupDetails.BackupSizeBytes), + ) + resp.SendProgress(action.InvokeProgressEvent{Message: backupInfo}) + + tflog.Info(ctx, "DynamoDB create backup action completed successfully", map[string]any{ + names.AttrTableName: tableName, + "backup_arn": backupArn, + }) +} diff --git a/internal/service/dynamodb/create_backup_action_test.go b/internal/service/dynamodb/create_backup_action_test.go new file mode 100644 index 000000000000..bfc9e66b6f73 --- /dev/null +++ b/internal/service/dynamodb/create_backup_action_test.go @@ -0,0 +1,203 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package dynamodb_test + +import ( + "context" + "fmt" + "testing" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccDynamoDBCreateBackupAction_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCreateBackupActionConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckBackupExists(ctx, rName), + ), + }, + }, + }) +} + +func TestAccDynamoDBCreateBackupAction_customName(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + backupName := acctest.RandomWithPrefix(t, "tf-test-backup") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCreateBackupActionConfig_customName(rName, backupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckBackupExists(ctx, rName), + testAccCheckBackupName(ctx, rName, backupName), + ), + }, + }, + }) +} + +func TestAccDynamoDBCreateBackupAction_nonExistentTable(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCreateBackupActionConfig_nonExistentTable(rName), + ExpectError: regexache.MustCompile(`TableNotFoundException`), + }, + }, + }) +} + +func testAccCheckBackupExists(ctx context.Context, tableName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).DynamoDBClient(ctx) + + input := &dynamodb.ListBackupsInput{ + TableName: &tableName, + } + + output, err := conn.ListBackups(ctx, input) + if err != nil { + return fmt.Errorf("error listing backups for table %s: %w", tableName, err) + } + + if len(output.BackupSummaries) == 0 { + return fmt.Errorf("no backups found for table %s", tableName) + } + + return nil + } +} + +func testAccCheckBackupName(ctx context.Context, tableName, expectedBackupName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).DynamoDBClient(ctx) + + input := &dynamodb.ListBackupsInput{ + TableName: &tableName, + } + + output, err := conn.ListBackups(ctx, input) + if err != nil { + return fmt.Errorf("error listing backups for table %s: %w", tableName, err) + } + + for _, backup := range output.BackupSummaries { + if backup.BackupName != nil && *backup.BackupName == expectedBackupName { + return nil + } + } + + return fmt.Errorf("backup with name %s not found for table %s", expectedBackupName, tableName) + } +} + +func testAccCreateBackupActionConfig_base(rName string) string { + return fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + billing_mode = "PAY_PER_REQUEST" + hash_key = "id" + + attribute { + name = "id" + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} +`, rName) +} + +func testAccCreateBackupActionConfig_basic(rName string) string { + return acctest.ConfigCompose( + testAccCreateBackupActionConfig_base(rName), + ` +action "aws_dynamodb_create_backup" "test" { + config { + table_name = aws_dynamodb_table.test.name + } +} + +resource "terraform_data" "trigger" { + input = "trigger" + lifecycle { + action_trigger { + events = [before_create, before_update] + actions = [action.aws_dynamodb_create_backup.test] + } + } +} +`) +} + +func testAccCreateBackupActionConfig_customName(rName, backupName string) string { + return acctest.ConfigCompose( + testAccCreateBackupActionConfig_base(rName), + fmt.Sprintf(` +action "aws_dynamodb_create_backup" "test" { + config { + table_name = aws_dynamodb_table.test.name + backup_name = %[1]q + } +} + +resource "terraform_data" "trigger" { + input = "trigger" + lifecycle { + action_trigger { + events = [before_create, before_update] + actions = [action.aws_dynamodb_create_backup.test] + } + } +} +`, backupName)) +} + +func testAccCreateBackupActionConfig_nonExistentTable(rName string) string { + return fmt.Sprintf(` +action "aws_dynamodb_create_backup" "test" { + config { + table_name = %[1]q + } +} + +resource "terraform_data" "trigger" { + input = "trigger" + lifecycle { + action_trigger { + events = [before_create, before_update] + actions = [action.aws_dynamodb_create_backup.test] + } + } +} +`, rName) +} diff --git a/internal/service/dynamodb/flex.go b/internal/service/dynamodb/flex.go index 7352c10a59c2..5fe40c234349 100644 --- a/internal/service/dynamodb/flex.go +++ b/internal/service/dynamodb/flex.go @@ -10,7 +10,7 @@ import ( tfjson "github.com/hashicorp/terraform-provider-aws/internal/json" tfmaps "github.com/hashicorp/terraform-provider-aws/internal/maps" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" ) func expandTableItemAttributes(jsonStream string) (map[string]awstypes.AttributeValue, error) { @@ -55,7 +55,7 @@ func attributeFromRaw(v any) (awstypes.AttributeValue, error) { case string: switch k { case dataTypeDescriptorBinary: - v, err := itypes.Base64Decode(v) + v, err := inttypes.Base64Decode(v) if err != nil { return nil, err } @@ -71,7 +71,7 @@ func attributeFromRaw(v any) (awstypes.AttributeValue, error) { v, err := tfslices.ApplyToAllWithError(v, func(v any) ([]byte, error) { switch v := v.(type) { case string: - return itypes.Base64Decode(v) + return inttypes.Base64Decode(v) default: return nil, unexpectedRawAttributeElementTypeError(v, k) } @@ -125,11 +125,11 @@ func rawFromAttribute(a awstypes.AttributeValue) (any, error) { switch a := a.(type) { case *awstypes.AttributeValueMemberB: - m[dataTypeDescriptorBinary] = itypes.Base64Encode(a.Value) + m[dataTypeDescriptorBinary] = inttypes.Base64Encode(a.Value) case *awstypes.AttributeValueMemberBOOL: m[dataTypeDescriptorBoolean] = a.Value case *awstypes.AttributeValueMemberBS: - m[dataTypeDescriptorBinarySet] = tfslices.ApplyToAll(a.Value, itypes.Base64Encode) + m[dataTypeDescriptorBinarySet] = tfslices.ApplyToAll(a.Value, inttypes.Base64Encode) case *awstypes.AttributeValueMemberL: v, err := tfslices.ApplyToAllWithError(a.Value, rawFromAttribute) if err != nil { diff --git a/internal/service/dynamodb/service_package_gen.go b/internal/service/dynamodb/service_package_gen.go index f0fe873f787d..67ae1522f93a 100644 --- a/internal/service/dynamodb/service_package_gen.go +++ b/internal/service/dynamodb/service_package_gen.go @@ -17,6 +17,17 @@ import ( type servicePackage struct{} +func (p *servicePackage) Actions(ctx context.Context) []*inttypes.ServicePackageAction { + return []*inttypes.ServicePackageAction{ + { + Factory: newCreateBackupAction, + TypeName: "aws_dynamodb_create_backup", + Name: "Create Backup", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } +} + func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.ServicePackageFrameworkDataSource { return []*inttypes.ServicePackageFrameworkDataSource{ { diff --git a/internal/service/dynamodb/table.go b/internal/service/dynamodb/table.go index 73d836174963..542cdc0a6064 100644 --- a/internal/service/dynamodb/table.go +++ b/internal/service/dynamodb/table.go @@ -226,6 +226,22 @@ func resourceTable() *schema.Resource { }, }, }, + "global_table_witness": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: verify.ValidRegionName, + }, + }, + }, + }, "hash_key": { Type: schema.TypeString, Optional: true, @@ -884,7 +900,7 @@ func resourceTableCreate(ctx context.Context, d *schema.ResourceData, meta any) } if v := d.Get("replica").(*schema.Set); v.Len() > 0 { - if err := createReplicas(ctx, conn, d.Id(), v.List(), true, d.Timeout(schema.TimeoutCreate)); err != nil { + if err := createReplicas(ctx, conn, d.Id(), v.List(), expandGlobalTableWitness(d.Get("global_table_witness")), true, d.Timeout(schema.TimeoutCreate)); err != nil { return create.AppendDiagError(diags, names.DynamoDB, create.ErrActionCreating, resNameTable, d.Id(), fmt.Errorf("replicas: %w", err)) } @@ -951,6 +967,10 @@ func resourceTableRead(ctx context.Context, d *schema.ResourceData, meta any) di return create.AppendDiagSettingError(diags, names.DynamoDB, resNameTable, d.Id(), "global_secondary_index", err) } + if err := d.Set("global_table_witness", flattenGlobalTableWitnesses(table.GlobalTableWitnesses)); err != nil { + return create.AppendDiagSettingError(diags, names.DynamoDB, resNameTable, d.Id(), "global_table_witness", err) + } + if err := d.Set("on_demand_throughput", flattenOnDemandThroughput(table.OnDemandThroughput)); err != nil { return create.AppendDiagSettingError(diags, names.DynamoDB, resNameTable, d.Id(), "on_demand_throughput", err) } @@ -1393,10 +1413,11 @@ func resourceTableDelete(ctx context.Context, d *schema.ResourceData, meta any) if replicas := d.Get("replica").(*schema.Set).List(); len(replicas) > 0 { log.Printf("[DEBUG] Deleting DynamoDB Table replicas: %s", d.Id()) - if err := deleteReplicas(ctx, conn, d.Id(), replicas, d.Timeout(schema.TimeoutDelete)); err != nil { + if err := deleteReplicas(ctx, conn, d.Id(), replicas, expandGlobalTableWitness(d.Get("global_table_witness")), d.Timeout(schema.TimeoutDelete)); err != nil { // ValidationException: Replica specified in the Replica Update or Replica Delete action of the request was not found. // ValidationException: Cannot add, delete, or update the local region through ReplicaUpdates. Use CreateTable, DeleteTable, or UpdateTable as required. if !tfawserr.ErrMessageContains(err, errCodeValidationException, "request was not found") && + !tfawserr.ErrMessageContains(err, errCodeValidationException, "MultiRegionConsistency must be set as STRONG when GlobalTableWitnessUpdates parameter is present") && !tfawserr.ErrMessageContains(err, errCodeValidationException, "Cannot add, delete, or update the local region through ReplicaUpdates") { return create.AppendDiagError(diags, names.DynamoDB, create.ErrActionDeleting, resNameTable, d.Id(), err) } @@ -1471,7 +1492,7 @@ func cycleStreamEnabled(ctx context.Context, conn *dynamodb.Client, id string, s return nil } -func createReplicas(ctx context.Context, conn *dynamodb.Client, tableName string, tfList []any, create bool, timeout time.Duration) error { +func createReplicas(ctx context.Context, conn *dynamodb.Client, tableName string, tfList []any, globalTableWitnessRegionName string, create bool, timeout time.Duration) error { // Duplicating this for MRSC Adoption. If using MRSC and CreateReplicationGroupMemberAction list isn't initiated for at least 2 replicas // then the update table action will fail with // "Unsupported table replica count for global tables with MultiRegionConsistency set to STRONG" @@ -1492,14 +1513,18 @@ func createReplicas(ctx context.Context, conn *dynamodb.Client, tableName string } if numReplicasMRSC > 0 { + mrscErrorMsg := "creating replicas: Using MultiRegionStrongConsistency requires exactly 2 replicas, or 1 replica and 1 witness region." if numReplicasMRSC > 0 && numReplicasMRSC != numReplicas { - return fmt.Errorf("creating replicas: Using MultiRegionStrongConsistency requires all replicas to use 'consistency_mode' set to 'STRONG' ") + return errors.New(mrscErrorMsg) + } + if numReplicasMRSC == 1 && globalTableWitnessRegionName == "" { + return fmt.Errorf("%s Only MRSC Replica count of 1 was provided but no Witness region was provided", mrscErrorMsg) } - if numReplicasMRSC == 1 { - return fmt.Errorf("creating replicas: Using MultiRegionStrongConsistency requires exactly 2 replicas. ") + if numReplicasMRSC == 2 && (numReplicasMRSC == numReplicas && globalTableWitnessRegionName != "") { + return fmt.Errorf("%s MRSC Replica count of 2 was provided and a Witness region was also provided", mrscErrorMsg) } if numReplicasMRSC > 2 { - return fmt.Errorf("creating replicas: Using MultiRegionStrongConsistency supports at most 2 replicas. ") + return fmt.Errorf("%s Too many Replicas were provided %d", mrscErrorMsg, numReplicasMRSC) } mrscInput = awstypes.MultiRegionConsistencyStrong @@ -1530,14 +1555,24 @@ func createReplicas(ctx context.Context, conn *dynamodb.Client, tableName string }) } - input := &dynamodb.UpdateTableInput{ - TableName: aws.String(tableName), - ReplicaUpdates: replicaCreates, - MultiRegionConsistency: mrscInput, + var gtgwu []awstypes.GlobalTableWitnessGroupUpdate + if globalTableWitnessRegionName != "" { + var cgtwgma = awstypes.CreateGlobalTableWitnessGroupMemberAction{ + RegionName: aws.String(globalTableWitnessRegionName), + } + gtgwu = append(gtgwu, awstypes.GlobalTableWitnessGroupUpdate{ + Create: &cgtwgma, + }) + } + input := dynamodb.UpdateTableInput{ + GlobalTableWitnessUpdates: gtgwu, + MultiRegionConsistency: mrscInput, + ReplicaUpdates: replicaCreates, + TableName: aws.String(tableName), } err := tfresource.Retry(ctx, max(replicaUpdateTimeout, timeout), func(ctx context.Context) *tfresource.RetryError { - _, err := conn.UpdateTable(ctx, input) + _, err := conn.UpdateTable(ctx, &input) if err != nil { if tfawserr.ErrCodeEquals(err, errCodeThrottlingException) { return tfresource.RetryableError(err) @@ -1655,7 +1690,7 @@ func createReplicas(ctx context.Context, conn *dynamodb.Client, tableName string // ValidationException: One or more parameter values were invalid: KMSMasterKeyId must be specified for each replica. if create && tfawserr.ErrMessageContains(err, errCodeValidationException, "already exist") { - return createReplicas(ctx, conn, tableName, tfList, false, timeout) + return createReplicas(ctx, conn, tableName, tfList, globalTableWitnessRegionName, false, timeout) } if err != nil && !tfawserr.ErrMessageContains(err, errCodeValidationException, "no actions specified") { @@ -1898,20 +1933,22 @@ func updateReplica(ctx context.Context, conn *dynamodb.Client, d *schema.Resourc } } + globalTableWitnessRegionName := expandGlobalTableWitness(d.Get("global_table_witness")) + if len(removeFirst) > 0 { // mini ForceNew, recreates replica but doesn't recreate the table - if err := deleteReplicas(ctx, conn, d.Id(), removeFirst, d.Timeout(schema.TimeoutUpdate)); err != nil { + if err := deleteReplicas(ctx, conn, d.Id(), removeFirst, globalTableWitnessRegionName, d.Timeout(schema.TimeoutUpdate)); err != nil { return fmt.Errorf("updating replicas, while deleting: %w", err) } } if len(toRemove) > 0 { - if err := deleteReplicas(ctx, conn, d.Id(), toRemove, d.Timeout(schema.TimeoutUpdate)); err != nil { + if err := deleteReplicas(ctx, conn, d.Id(), toRemove, globalTableWitnessRegionName, d.Timeout(schema.TimeoutUpdate)); err != nil { return fmt.Errorf("updating replicas, while deleting: %w", err) } } if len(toAdd) > 0 { - if err := createReplicas(ctx, conn, d.Id(), toAdd, true, d.Timeout(schema.TimeoutCreate)); err != nil { + if err := createReplicas(ctx, conn, d.Id(), toAdd, globalTableWitnessRegionName, true, d.Timeout(schema.TimeoutCreate)); err != nil { return fmt.Errorf("updating replicas, while creating: %w", err) } } @@ -2164,7 +2201,7 @@ func deleteTable(ctx context.Context, conn *dynamodb.Client, tableName string) e return err } -func deleteReplicas(ctx context.Context, conn *dynamodb.Client, tableName string, tfList []any, timeout time.Duration) error { +func deleteReplicas(ctx context.Context, conn *dynamodb.Client, tableName string, tfList []any, globalTableWitnessRegionName string, timeout time.Duration) error { var g multierror.Group var replicaDeletes []awstypes.ReplicationGroupUpdate @@ -2199,12 +2236,22 @@ func deleteReplicas(ctx context.Context, conn *dynamodb.Client, tableName string // We built an array of MultiRegionStrongConsistency replicas that need deletion. // These need to all happen concurrently if len(replicaDeletes) > 0 { - input := &dynamodb.UpdateTableInput{ - TableName: aws.String(tableName), - ReplicaUpdates: replicaDeletes, + var witnessDeletes []awstypes.GlobalTableWitnessGroupUpdate + if globalTableWitnessRegionName != "" { + witnessDeletes = append(witnessDeletes, awstypes.GlobalTableWitnessGroupUpdate{ + Delete: &awstypes.DeleteGlobalTableWitnessGroupMemberAction{ + RegionName: aws.String(globalTableWitnessRegionName), + }, + }) + } + + input := dynamodb.UpdateTableInput{ + GlobalTableWitnessUpdates: witnessDeletes, + ReplicaUpdates: replicaDeletes, + TableName: aws.String(tableName), } err := tfresource.Retry(ctx, updateTableTimeout, func(ctx context.Context) *tfresource.RetryError { - _, err := conn.UpdateTable(ctx, input) + _, err := conn.UpdateTable(ctx, &input) notFoundRetries := 0 if err != nil { if tfawserr.ErrCodeEquals(err, errCodeThrottlingException) { @@ -2694,6 +2741,24 @@ func flattenGSIWarmThroughput(apiObject *awstypes.GlobalSecondaryIndexWarmThroug return []any{m} } +func expandGlobalTableWitness(v any) string { + if v == nil || len(v.([]any)) == 0 || v.([]any)[0] == nil { + return "" + } + + return v.([]any)[0].(map[string]any)["region_name"].(string) +} + +func flattenGlobalTableWitnesses(apiObjects []awstypes.GlobalTableWitnessDescription) []any { + if len(apiObjects) != 1 { + return []any{} + } + + return []any{map[string]any{ + "region_name": aws.ToString(apiObjects[0].RegionName), + }} +} + func flattenReplicaDescription(apiObject *awstypes.ReplicaDescription) map[string]any { if apiObject == nil { return nil diff --git a/internal/service/dynamodb/table_item.go b/internal/service/dynamodb/table_item.go index e7d883cdcc30..fcf93c3c76bb 100644 --- a/internal/service/dynamodb/table_item.go +++ b/internal/service/dynamodb/table_item.go @@ -20,7 +20,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -246,7 +246,7 @@ func tableItemCreateResourceID(tableName string, hashKey string, rangeKey string if v, ok := attrs[hashKey]; ok { switch v := v.(type) { case *awstypes.AttributeValueMemberB: - id = append(id, itypes.Base64EncodeOnce(v.Value)) + id = append(id, inttypes.Base64EncodeOnce(v.Value)) case *awstypes.AttributeValueMemberN: id = append(id, v.Value) case *awstypes.AttributeValueMemberS: @@ -257,7 +257,7 @@ func tableItemCreateResourceID(tableName string, hashKey string, rangeKey string if v, ok := attrs[rangeKey]; ok && rangeKey != "" { switch v := v.(type) { case *awstypes.AttributeValueMemberB: - id = append(id, itypes.Base64EncodeOnce(v.Value)) + id = append(id, inttypes.Base64EncodeOnce(v.Value)) case *awstypes.AttributeValueMemberN: id = append(id, v.Value) case *awstypes.AttributeValueMemberS: diff --git a/internal/service/dynamodb/table_item_data_source.go b/internal/service/dynamodb/table_item_data_source.go index 9c9666e6ca3b..6f07f18827da 100644 --- a/internal/service/dynamodb/table_item_data_source.go +++ b/internal/service/dynamodb/table_item_data_source.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -104,7 +104,7 @@ func createTableItemDataSourceID(tableName string, attrs map[string]awstypes.Att for k, v := range attrs { switch v := v.(type) { case *awstypes.AttributeValueMemberB: - id = append(id, k, itypes.Base64EncodeOnce(v.Value)) + id = append(id, k, inttypes.Base64EncodeOnce(v.Value)) case *awstypes.AttributeValueMemberN: id = append(id, v.Value) case *awstypes.AttributeValueMemberS: diff --git a/internal/service/dynamodb/table_test.go b/internal/service/dynamodb/table_test.go index e4750e90f261..9c1c50609a07 100644 --- a/internal/service/dynamodb/table_test.go +++ b/internal/service/dynamodb/table_test.go @@ -1249,7 +1249,7 @@ func TestAccDynamoDBTable_onDemandThroughput(t *testing.T) { testAccCheckInitialTableExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "billing_mode", string(awstypes.BillingModePayPerRequest)), resource.TestCheckResourceAttr(resourceName, "on_demand_throughput.#", "1"), - resource.TestCheckResourceAttr(resourceName, "on_demand_throughput.0.max_read_request_units", "-1"), + resource.TestCheckResourceAttr(resourceName, "on_demand_throughput.0.max_read_request_units", "0"), resource.TestCheckResourceAttr(resourceName, "on_demand_throughput.0.max_write_request_units", "5"), ), }, @@ -3488,6 +3488,162 @@ func TestAccDynamoDBTable_Replica_MRSC_Create(t *testing.T) { }) } +func TestAccDynamoDBTable_Replica_MRSC_Create_witness(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf, replica1 awstypes.TableDescription + resourceName := "aws_dynamodb_table.test_mrsc" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), // 3 due to shared test configuration + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_MRSC_replica_witness(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica1), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + "consistency_mode": knownvalue.StringExact((string(awstypes.MultiRegionConsistencyStrong))), + }), + })), + }, + }, + }, + }) +} + +func TestAccDynamoDBTable_Replica_MRSC_Create_witness_too_many_replicas(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), // 3 due to shared test configuration + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_MRSC_replica_witness_too_many_replicas(rName), + ExpectError: regexache.MustCompile(`MRSC Replica count of 2 was provided and a Witness region was also provided`), + }, + }, + }) +} + +func TestAccDynamoDBTable_Replica_MRSC_witness_doubleAddCMK(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + kmsKeyResourceName := "aws_kms_key.test" + kmsKey1Replica1ResourceName := "aws_kms_key.awsalternate1" + kmsKey2Replica1ResourceName := "aws_kms_key.awsalternate2" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), // 3 due to shared test configuration + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_AmazonManagedKey_witness(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "server_side_encryption.0.enabled", acctest.CtTrue), + resource.TestCheckResourceAttr(resourceName, "server_side_encryption.0.kms_key_arn", ""), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrKMSKeyARN: knownvalue.StringExact(""), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_CMKUpdate_witness(rName, "awsalternate1", "awsthird1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "server_side_encryption.0.enabled", acctest.CtTrue), + resource.TestCheckResourceAttrPair(resourceName, "server_side_encryption.0.kms_key_arn", kmsKeyResourceName, names.AttrARN), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrKMSKeyARN: knownvalue.NotNull(), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + statecheck.CompareValuePairs(resourceName, tfjsonpath.New("replica").AtSliceIndex(0).AtMapKey(names.AttrKMSKeyARN), kmsKey1Replica1ResourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_CMKUpdate_witness(rName, "awsalternate2", "awsthird2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "server_side_encryption.0.enabled", acctest.CtTrue), + resource.TestCheckResourceAttrPair(resourceName, "server_side_encryption.0.kms_key_arn", kmsKeyResourceName, names.AttrARN), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrKMSKeyARN: knownvalue.NotNull(), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + statecheck.CompareValuePairs(resourceName, tfjsonpath.New("replica").AtSliceIndex(0).AtMapKey(names.AttrKMSKeyARN), kmsKey2Replica1ResourceName, tfjsonpath.New(names.AttrARN), compare.ValuesSame()), + }, + }, + }, + }) +} func TestAccDynamoDBTable_Replica_MRSC_doubleAddCMK(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -3649,6 +3805,74 @@ func TestAccDynamoDBTable_Replica_MRSC_pitr(t *testing.T) { }) } +func TestAccDynamoDBTable_Replica_MRSC_witness_pitr(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf, replica1, replica3 awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_PITR_witness(rName, false, true, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica1), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtFalse), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "point_in_time_recovery": knownvalue.Bool(true), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_PITR_witness(rName, true, false, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica3), + testAccCheckTableNotRecreated(&replica1, &replica3), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtTrue), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "point_in_time_recovery": knownvalue.Bool(false), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + }, + }, + }, + }) +} + func TestAccDynamoDBTable_Replica_MRSC_pitrKMS(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -3790,74 +4014,281 @@ func TestAccDynamoDBTable_Replica_MRSC_pitrKMS(t *testing.T) { }) } -func TestAccDynamoDBTable_Replica_MRSC_tags_updateIsPropagated_oneOfTwo(t *testing.T) { +func TestAccDynamoDBTable_Replica_MRSC_witness_pitrKMS(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") } - var conf awstypes.TableDescription + var conf, replica1, replica3 awstypes.TableDescription resourceName := "aws_dynamodb_table.test" rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resource.Test(t, resource.TestCase{ + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckMultipleRegion(t, 3) }, ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), // 3 due to shared test configuration CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_replica_MRSC_Tags(rName, "benny", "smiles", true, false), + Config: testAccTableConfig_replica_MRSC_PITRKMS_witness(rName, false, false, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), - testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ - "Name": rName, - "Pozo": "Amargo", - "benny": "smiles", - }), - testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{}), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica1), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtFalse), ), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ - knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrPropagateTags: knownvalue.Bool(true), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.ThirdRegion()), - names.AttrPropagateTags: knownvalue.Bool(false), + "point_in_time_recovery": knownvalue.Bool(false), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), }), })), }, }, { - Config: testAccTableConfig_replica_MRSC_Tags(rName, "benny", "frowns", true, false), + Config: testAccTableConfig_replica_MRSC_PITRKMS_witness(rName, false, true, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), - testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ - "Name": rName, - "Pozo": "Amargo", - "benny": "frowns", - }), - testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{}), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica3), + testAccCheckTableNotRecreated(&replica1, &replica3), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtFalse), ), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ - knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrPropagateTags: knownvalue.Bool(true), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.ThirdRegion()), - names.AttrPropagateTags: knownvalue.Bool(false), + "point_in_time_recovery": knownvalue.Bool(true), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), }), })), }, }, - }, + { + Config: testAccTableConfig_replica_MRSC_PITRKMS_witness(rName, false, true, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica1), + testAccCheckTableNotRecreated(&replica1, &replica3), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtFalse), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "point_in_time_recovery": knownvalue.Bool(true), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_PITRKMS_witness(rName, true, false, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica3), + testAccCheckTableNotRecreated(&replica1, &replica3), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtTrue), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "point_in_time_recovery": knownvalue.Bool(false), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_PITRKMS_witness(rName, false, false, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaExists(ctx, resourceName, acctest.AlternateRegion(), &replica1), + testAccCheckTableNotRecreated(&replica1, &replica3), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "point_in_time_recovery.0.enabled", acctest.CtFalse), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "point_in_time_recovery": knownvalue.Bool(false), + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + }), + })), + }, + }, + }, + }) +} +func TestAccDynamoDBTable_Replica_MRSC_tags_updateIsPropagated_oneOfTwo(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_Tags(rName, "benny", "smiles", true, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "benny": "smiles", + }), + testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{}), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + names.AttrPropagateTags: knownvalue.Bool(false), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_Tags(rName, "benny", "frowns", true, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "benny": "frowns", + }), + testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{}), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + names.AttrPropagateTags: knownvalue.Bool(false), + }), + })), + }, + }, + }, + }) +} + +func TestAccDynamoDBTable_Replica_MRSC_witness_tags_updateIsPropagated_oneOfTwo(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_Tags_witness(rName, "benny", "smiles", true, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "benny": "smiles", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_Tags_witness(rName, "benny", "frowns", true, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "benny": "frowns", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + }, }) } @@ -3940,6 +4371,77 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_updateIsPropagated_twoOfTwo(t *testi }) } +func TestAccDynamoDBTable_Replica_MRSC_witness_tags_updateIsPropagated_twoOfTwo(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_Tags_witness(rName, "Structure", "Adobe", true, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "Structure": "Adobe", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_Tags_witness(rName, "Structure", "Steel", true, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "Structure": "Steel", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + }, + }) +} + func TestAccDynamoDBTable_Replica_MRSC_tags_propagateToAddedReplica(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -3960,7 +4462,7 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_propagateToAddedReplica(t *testing.T CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_replica_MRSC_TagsNext1(rName, acctest.AlternateRegion(), true), + Config: testAccTableConfig_replica_MRSC_TagsNext1(rName, acctest.AlternateRegion(), true, acctest.ThirdRegion(), false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ @@ -3974,6 +4476,10 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_propagateToAddedReplica(t *testing.T "region_name": knownvalue.StringExact(acctest.AlternateRegion()), names.AttrPropagateTags: knownvalue.Bool(true), }), + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + names.AttrPropagateTags: knownvalue.Bool(false), + }), })), }, }, @@ -3996,10 +4502,139 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_propagateToAddedReplica(t *testing.T "region_name": knownvalue.StringExact(acctest.AlternateRegion()), names.AttrPropagateTags: knownvalue.Bool(true), }), - knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.ThirdRegion()), - names.AttrPropagateTags: knownvalue.Bool(true), - }), + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + }, + }) +} + +func TestAccDynamoDBTable_Replica_MRSC_witness_tags_propagateToAddedReplica(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_TagsNext1_witness(rName, acctest.AlternateRegion(), true, acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_TagsNext2_witness(rName, acctest.AlternateRegion(), true, acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + }, + }) +} + +func TestAccDynamoDBTable_Replica_MRSC_witness_tags_notPropagatedToAddedReplica(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_TagsNext1_witness(rName, acctest.AlternateRegion(), true, acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_TagsNext2_witness(rName, acctest.AlternateRegion(), true, acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.AlternateRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), })), }, }, @@ -4007,7 +4642,7 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_propagateToAddedReplica(t *testing.T }) } -func TestAccDynamoDBTable_Replica_MRSC_tags_notPropagatedToAddedReplica(t *testing.T) { +func TestAccDynamoDBTable_Replica_MRSC_tags_nonPropagatedTagsAreUnmanaged(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -4027,12 +4662,18 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_notPropagatedToAddedReplica(t *testi CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_replica_MRSC_TagsNext1(rName, acctest.AlternateRegion(), true), + Config: testAccTableConfig_replica_MRSC_Tags(rName, "Structure", "Adobe", true, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ - "Name": rName, - "Pozo": "Amargo", + "Name": rName, + "Pozo": "Amargo", + "Structure": "Adobe", + }), + testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "Structure": "Adobe", }), ), ConfigStateChecks: []statecheck.StateCheck{ @@ -4041,18 +4682,27 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_notPropagatedToAddedReplica(t *testi "region_name": knownvalue.StringExact(acctest.AlternateRegion()), names.AttrPropagateTags: knownvalue.Bool(true), }), + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + names.AttrPropagateTags: knownvalue.Bool(true), + }), })), }, }, { - Config: testAccTableConfig_replica_MRSC_TagsNext2(rName, acctest.AlternateRegion(), true, acctest.ThirdRegion(), false), + Config: testAccTableConfig_replica_MRSC_Tags(rName, "Structure", "Steel", true, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ - "Name": rName, - "Pozo": "Amargo", + "Name": rName, + "Pozo": "Amargo", + "Structure": "Steel", + }), + testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "Structure": "Adobe", }), - testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{}), ), ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ @@ -4071,7 +4721,7 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_notPropagatedToAddedReplica(t *testi }) } -func TestAccDynamoDBTable_Replica_MRSC_tags_nonPropagatedTagsAreUnmanaged(t *testing.T) { +func TestAccDynamoDBTable_Replica_MRSC_witness_tags_nonPropagatedTagsAreUnmanaged(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -4091,7 +4741,7 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_nonPropagatedTagsAreUnmanaged(t *tes CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_replica_MRSC_Tags(rName, "Structure", "Adobe", true, true), + Config: testAccTableConfig_replica_MRSC_Tags_witness(rName, "Structure", "Adobe", true, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ @@ -4099,27 +4749,23 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_nonPropagatedTagsAreUnmanaged(t *tes "Pozo": "Amargo", "Structure": "Adobe", }), - testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{ - "Name": rName, - "Pozo": "Amargo", - "Structure": "Adobe", - }), ), ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ knownvalue.ObjectPartial(map[string]knownvalue.Check{ "region_name": knownvalue.StringExact(acctest.AlternateRegion()), names.AttrPropagateTags: knownvalue.Bool(true), }), - knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.ThirdRegion()), - names.AttrPropagateTags: knownvalue.Bool(true), - }), })), }, }, { - Config: testAccTableConfig_replica_MRSC_Tags(rName, "Structure", "Steel", true, false), + Config: testAccTableConfig_replica_MRSC_Tags_witness(rName, "Structure", "Steel", true, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckInitialTableExists(ctx, resourceName, &conf), testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ @@ -4127,22 +4773,18 @@ func TestAccDynamoDBTable_Replica_MRSC_tags_nonPropagatedTagsAreUnmanaged(t *tes "Pozo": "Amargo", "Structure": "Steel", }), - testAccCheckReplicaTags(ctx, resourceName, acctest.ThirdRegion(), map[string]string{ - "Name": rName, - "Pozo": "Amargo", - "Structure": "Adobe", - }), ), ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("replica"), knownvalue.SetExact([]knownvalue.Check{ knownvalue.ObjectPartial(map[string]knownvalue.Check{ "region_name": knownvalue.StringExact(acctest.AlternateRegion()), names.AttrPropagateTags: knownvalue.Bool(true), }), - knownvalue.ObjectPartial(map[string]knownvalue.Check{ - "region_name": knownvalue.StringExact(acctest.ThirdRegion()), - names.AttrPropagateTags: knownvalue.Bool(false), - }), })), }, }, @@ -4302,6 +4944,141 @@ func TestAccDynamoDBTable_Replica_MRSC_tagsUpdate(t *testing.T) { }) } +func TestAccDynamoDBTable_Replica_MRSC_witness_tagsUpdate(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var conf awstypes.TableDescription + resourceName := "aws_dynamodb_table.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckMultipleRegion(t, 3) + }, + ErrorCheck: acctest.ErrorCheck(t, names.DynamoDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesMultipleRegions(ctx, t, 3), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTableConfig_replica_MRSC_TagsUpdate1_witness(rName, acctest.AlternateRegion(), acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "replica.*", map[string]string{ + "region_name": acctest.AlternateRegion(), + names.AttrPropagateTags: acctest.CtTrue, + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_TagsUpdate2_witness(rName, acctest.AlternateRegion(), acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "tyDi": "Lullaby", + "Thrill": "Seekers", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "replica.*", map[string]string{ + "region_name": acctest.AlternateRegion(), + names.AttrPropagateTags: acctest.CtTrue, + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_TagsUpdate3_witness(rName, acctest.AlternateRegion(), acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "tyDi": "Lullaby", + "Thrill": "Seekers", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "replica.*", map[string]string{ + "region_name": acctest.AlternateRegion(), + names.AttrPropagateTags: acctest.CtTrue, + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_TagsUpdate4_witness(rName, acctest.AlternateRegion(), acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + "Pozo": "Amargo", + "tyDi": "Lullaby", + "Thrill": "Seekers", + "Tristan": "Joe", + "Humming": "bird", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "replica.*", map[string]string{ + "region_name": acctest.AlternateRegion(), + names.AttrPropagateTags: acctest.CtTrue, + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + }, + }, + { + Config: testAccTableConfig_replica_MRSC_TagsUpdate5_witness(rName, acctest.AlternateRegion(), acctest.ThirdRegion()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckInitialTableExists(ctx, resourceName, &conf), + testAccCheckReplicaTags(ctx, resourceName, acctest.AlternateRegion(), map[string]string{ + "Name": rName, + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "replica.*", map[string]string{ + "region_name": acctest.AlternateRegion(), + names.AttrPropagateTags: acctest.CtTrue, + }), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("global_table_witness"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "region_name": knownvalue.StringExact(acctest.ThirdRegion()), + }), + })), + }, + }, + }, + }) +} + func TestAccDynamoDBTable_Replica_MRSC_TooManyReplicas(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -4320,7 +5097,7 @@ func TestAccDynamoDBTable_Replica_MRSC_TooManyReplicas(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccTableConfig_MRSC_replica_count3(rName), - ExpectError: regexache.MustCompile(`Using MultiRegionStrongConsistency supports at most 2 replicas`), + ExpectError: regexache.MustCompile(`Using MultiRegionStrongConsistency requires exactly 2 replicas, or 1 replica and 1 witness region. Too many Replicas were provided`), }, }, }) @@ -4368,7 +5145,7 @@ func TestAccDynamoDBTable_Replica_MRSC_MixedConsistencyModes(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccTableConfig_MRSC_replica_mixed_consistency_mode(rName), - ExpectError: regexache.MustCompile(`Using MultiRegionStrongConsistency requires all replicas to use 'consistency_mode' set to 'STRONG'`), + ExpectError: regexache.MustCompile(`Using MultiRegionStrongConsistency requires exactly 2 replicas, or 1 replica and 1 witness region`), }, }, }) @@ -6450,6 +7227,83 @@ resource "aws_dynamodb_table" "test_mrsc" { `, rName)) } +func testAccTableConfig_MRSC_replica_witness(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = "awsalternate" +} + +data "aws_region" "third" { + provider = "awsthird" +} + +resource "aws_dynamodb_table" "test_mrsc" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = data.aws_region.alternate.name + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = data.aws_region.third.name + } +} +`, rName)) +} + +func testAccTableConfig_MRSC_replica_witness_too_many_replicas(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = "awsalternate" +} + +data "aws_region" "third" { + provider = "awsthird" +} + +resource "aws_dynamodb_table" "test_mrsc" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = data.aws_region.alternate.name + consistency_mode = "STRONG" + } + + replica { + region_name = data.aws_region.third.name + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = data.aws_region.third.name + } +} +`, rName)) +} + func testAccTableConfig_replicaEncryptedDefault(rName string, sseEnabled bool) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors @@ -6625,6 +7479,52 @@ resource "aws_dynamodb_table" "test" { `, rName)) } +func testAccTableConfig_replica_MRSC_AmazonManagedKey_witness(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = "awsalternate" +} + +data "aws_region" "third" { + provider = "awsthird" +} + +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = data.aws_region.alternate.name + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = data.aws_region.third.name + } + + server_side_encryption { + enabled = true + } + + timeouts { + create = "20m" + update = "20m" + delete = "20m" + } +} +`, rName)) +} + func testAccTableConfig_replicaCMKUpdate(rName, keyReplica1, keyReplica2 string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors @@ -6786,6 +7686,83 @@ resource "aws_dynamodb_table" "test" { `, rName, keyReplica1, keyReplica2)) } +func testAccTableConfig_replica_MRSC_CMKUpdate_witness(rName, keyReplica1, keyReplica2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = "awsalternate" +} + +data "aws_region" "third" { + provider = "awsthird" +} + +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "awsalternate1" { + provider = "awsalternate" + description = "%[1]s-1" + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "awsalternate2" { + provider = "awsalternate" + description = "%[1]s-2" + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "awsthird1" { + provider = "awsthird" + description = "%[1]s-1" + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "awsthird2" { + provider = "awsthird" + description = "%[1]s-2" + deletion_window_in_days = 7 +} + +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = data.aws_region.alternate.name + kms_key_arn = aws_kms_key.%[2]s.arn + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = data.aws_region.third.name + } + + server_side_encryption { + enabled = true + kms_key_arn = aws_kms_key.test.arn + } + + timeouts { + create = "20m" + update = "20m" + delete = "20m" + } +} +`, rName, keyReplica1, keyReplica2)) +} + func testAccTableConfig_replicaPITR(rName string, mainPITR, replica1, replica2 bool) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors @@ -6870,6 +7847,47 @@ resource "aws_dynamodb_table" "test" { `, rName, mainPITR, replica1, replica2)) } +func testAccTableConfig_replica_MRSC_PITR_witness(rName string, mainPITR, replica1, replica2 bool) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), // Prevent "Provider configuration not present" errors + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = "awsalternate" +} + +data "aws_region" "third" { + provider = "awsthird" +} + +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + point_in_time_recovery { + enabled = %[2]t + } + + replica { + region_name = data.aws_region.alternate.name + point_in_time_recovery = %[3]t + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = data.aws_region.third.name + } +} +`, rName, mainPITR, replica1, replica2)) +} + func testAccTableConfig_replicaPITRKMS(rName string, mainPITR, replica1, replica2 bool) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), @@ -7005,6 +8023,70 @@ resource "aws_dynamodb_table" "test" { `, rName, mainPITR, replica1, replica2)) } +func testAccTableConfig_replica_MRSC_PITRKMS_witness(rName string, mainPITR, replica1, replica2 bool) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = awsalternate +} + +data "aws_region" "third" { + provider = awsthird +} + +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "alternate" { + provider = awsalternate + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "third" { + provider = awsthird + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + point_in_time_recovery { + enabled = %[2]t + } + + server_side_encryption { + enabled = true + kms_key_arn = aws_kms_key.test.arn + } + + replica { + region_name = data.aws_region.alternate.name + point_in_time_recovery = %[3]t + kms_key_arn = aws_kms_key.alternate.arn + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = data.aws_region.third.name + } +} +`, rName, mainPITR, replica1, replica2)) +} + func testAccTableConfig_replicaTags(rName, key, value string, propagate1, propagate2 bool) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), @@ -7035,8 +8117,53 @@ resource "aws_dynamodb_table" "test" { } replica { - region_name = data.aws_region.third.region - propagate_tags = %[5]t + region_name = data.aws_region.third.region + propagate_tags = %[5]t + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + %[2]s = %[3]q + } +} +`, rName, key, value, propagate1, propagate2)) +} + +func testAccTableConfig_replica_MRSC_Tags(rName, key, value string, propagate1, propagate2 bool) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +data "aws_region" "alternate" { + provider = "awsalternate" +} + +data "aws_region" "third" { + provider = "awsthird" +} + +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = data.aws_region.alternate.name + propagate_tags = %[4]t + consistency_mode = "STRONG" + } + + replica { + region_name = data.aws_region.third.name + propagate_tags = %[5]t + consistency_mode = "STRONG" } tags = { @@ -7048,7 +8175,7 @@ resource "aws_dynamodb_table" "test" { `, rName, key, value, propagate1, propagate2)) } -func testAccTableConfig_replica_MRSC_Tags(rName, key, value string, propagate1, propagate2 bool) string { +func testAccTableConfig_replica_MRSC_Tags_witness(rName, key, value string, propagate1, propagate2 bool) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), fmt.Sprintf(` @@ -7078,10 +8205,8 @@ resource "aws_dynamodb_table" "test" { consistency_mode = "STRONG" } - replica { - region_name = data.aws_region.third.name - propagate_tags = %[5]t - consistency_mode = "STRONG" + global_table_witness { + region_name = data.aws_region.third.name } tags = { @@ -7157,7 +8282,7 @@ resource "aws_dynamodb_table" "test" { `, rName, region1, propagate1)) } -func testAccTableConfig_replica_MRSC_TagsNext1(rName string, region1 string, propagate1 bool) string { +func testAccTableConfig_replica_MRSC_TagsNext1(rName string, region1 string, propagate1 bool, region2 string, propogate2 bool) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), fmt.Sprintf(` @@ -7174,8 +8299,15 @@ resource "aws_dynamodb_table" "test" { } replica { - region_name = %[2]q - propagate_tags = %[3]t + region_name = %[2]q + propagate_tags = %[3]t + consistency_mode = "STRONG" + } + + replica { + region_name = %[4]q + propagate_tags = %[5]t + consistency_mode = "STRONG" } tags = { @@ -7183,7 +8315,41 @@ resource "aws_dynamodb_table" "test" { Pozo = "Amargo" } } -`, rName, region1, propagate1)) +`, rName, region1, propagate1, region2, propogate2)) +} + +func testAccTableConfig_replica_MRSC_TagsNext1_witness(rName, region1 string, propagate1 bool, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = %[3]t + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = %[4]q + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + } +} +`, rName, region1, propagate1, region2)) } func testAccTableConfig_replicaTagsNext2(rName, region1 string, propagate1 bool, region2 string, propagate2 bool) string { @@ -7237,13 +8403,15 @@ resource "aws_dynamodb_table" "test" { } replica { - region_name = %[2]q - propagate_tags = %[3]t + region_name = %[2]q + propagate_tags = %[3]t + consistency_mode = "STRONG" } replica { - region_name = %[4]q - propagate_tags = %[5]t + region_name = %[4]q + propagate_tags = %[5]t + consistency_mode = "STRONG" } tags = { @@ -7254,6 +8422,40 @@ resource "aws_dynamodb_table" "test" { `, rName, region1, propagate1, region2, propagate2)) } +func testAccTableConfig_replica_MRSC_TagsNext2_witness(rName, region1 string, propagate1 bool, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = %[3]t + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = %[4]q + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + } +} +`, rName, region1, propagate1, region2)) +} + func testAccTableConfig_replicaTagsUpdate1(rName, region1 string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), @@ -7457,6 +8659,40 @@ resource "aws_dynamodb_table" "test" { `, rName, region1, region2)) } +func testAccTableConfig_replica_MRSC_TagsUpdate1_witness(rName, region1 string, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = true + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = %[3]q + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + } +} +`, rName, region1, region2)) +} + func testAccTableConfig_replica_MRSC_TagsUpdate2(rName, region1 string, region2 string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), @@ -7495,6 +8731,42 @@ resource "aws_dynamodb_table" "test" { `, rName, region1, region2)) } +func testAccTableConfig_replica_MRSC_TagsUpdate2_witness(rName, region1 string, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = true + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = %[3]q + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + tyDi = "Lullaby" + Thrill = "Seekers" + } +} +`, rName, region1, region2)) +} + func testAccTableConfig_replica_MRSC_TagsUpdate3(rName, region1 string, region2 string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), @@ -7532,6 +8804,41 @@ resource "aws_dynamodb_table" "test" { } `, rName, region1, region2)) } +func testAccTableConfig_replica_MRSC_TagsUpdate3_witness(rName, region1 string, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = true + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = %[3]q + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + tyDi = "Lullaby" + Thrill = "Seekers" + } +} +`, rName, region1, region2)) +} func testAccTableConfig_replica_MRSC_TagsUpdate4(rName, region1 string, region2 string) string { return acctest.ConfigCompose( @@ -7573,6 +8880,44 @@ resource "aws_dynamodb_table" "test" { `, rName, region1, region2)) } +func testAccTableConfig_replica_MRSC_TagsUpdate4_witness(rName, region1 string, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = true + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = %[3]q + } + + tags = { + Name = %[1]q + Pozo = "Amargo" + tyDi = "Lullaby" + Thrill = "Seekers" + Tristan = "Joe" + Humming = "bird" + } +} +`, rName, region1, region2)) +} + func testAccTableConfig_replica_MRSC_TagsUpdate5(rName, region1 string, region2 string) string { return acctest.ConfigCompose( acctest.ConfigMultipleRegionProvider(3), @@ -7608,6 +8953,39 @@ resource "aws_dynamodb_table" "test" { `, rName, region1, region2)) } +func testAccTableConfig_replica_MRSC_TagsUpdate5_witness(rName, region1 string, region2 string) string { + return acctest.ConfigCompose( + acctest.ConfigMultipleRegionProvider(3), + fmt.Sprintf(` +resource "aws_dynamodb_table" "test" { + name = %[1]q + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + global_table_witness { + region_name = %[3]q + } + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = %[2]q + propagate_tags = true + consistency_mode = "STRONG" + } + + tags = { + Name = %[1]q + } +} +`, rName, region1, region2)) +} + func testAccTableConfig_replicaStreamSpecification(rName string, streamEnabled bool, viewType string) string { if viewType != "null" { viewType = fmt.Sprintf(`"%s"`, viewType) diff --git a/internal/service/ec2/diff.go b/internal/service/ec2/diff.go index a55acdb51d8c..d8c5e18afb46 100644 --- a/internal/service/ec2/diff.go +++ b/internal/service/ec2/diff.go @@ -5,11 +5,11 @@ package ec2 import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" ) // suppressEqualCIDRBlockDiffs provides custom difference suppression for CIDR blocks // that have different string values but represent the same CIDR. func suppressEqualCIDRBlockDiffs(k, old, new string, d *schema.ResourceData) bool { - return types.CIDRBlocksEqual(old, new) + return inttypes.CIDRBlocksEqual(old, new) } diff --git a/internal/service/ec2/ec2_allowed_images_settings.go b/internal/service/ec2/ec2_allowed_images_settings.go new file mode 100644 index 000000000000..eda41506c2f9 --- /dev/null +++ b/internal/service/ec2/ec2_allowed_images_settings.go @@ -0,0 +1,278 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/service/ec2" + awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/terraform-plugin-framework-validators/int32validator" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + fwvalidators "github.com/hashicorp/terraform-provider-aws/internal/framework/validators" + "github.com/hashicorp/terraform-provider-aws/internal/smerr" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_ec2_allowed_images_settings", name="Allowed Images Settings") +func newAllowedImagesSettingsResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &allowedImagesSettingsResource{} + + return r, nil +} + +type allowedImagesSettingsResource struct { + framework.ResourceWithModel[allowedImagesSettingsResourceModel] +} + +func (r *allowedImagesSettingsResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrState: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.AllowedImagesSettingsEnabledState](), + Required: true, + }, + }, + Blocks: map[string]schema.Block{ + "image_criterion": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[imageCriterionModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(10), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "image_names": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.SizeAtMost(50), + setvalidator.ValueStringsAre( + stringvalidator.LengthBetween(1, 128), + stringvalidator.RegexMatches(regexache.MustCompile(`^[a-zA-Z0-9\-\._/\?\[\]@'\(\)\*\w]+$`), "can only contain valid characters"), + ), + }, + }, + "image_providers": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.SizeAtMost(200), + setvalidator.ValueStringsAre( + stringvalidator.Any( + stringvalidator.OneOf("amazon", "aws-marketplace", "aws-backup-vault", "none"), + fwvalidators.AWSAccountID(), + ), + ), + }, + }, + "marketplace_product_codes": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + Optional: true, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.SizeAtMost(50), + setvalidator.ValueStringsAre( + stringvalidator.LengthBetween(1, 25), + stringvalidator.RegexMatches(regexache.MustCompile(`^[a-zA-Z0-9]+$`), "must be a valid marketplace product code"), + ), + }, + }, + }, + Blocks: map[string]schema.Block{ + "creation_date_condition": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[creationDateConditionModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "maximum_days_since_created": schema.Int32Attribute{ + Optional: true, + Validators: []validator.Int32{ + int32validator.AtLeast(0), + }, + }, + }, + }, + }, + "deprecation_time_condition": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[deprecationTimeConditionModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "maximum_days_since_deprecated": schema.Int32Attribute{ + Optional: true, + Validators: []validator.Int32{ + int32validator.AtLeast(0), + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (r *allowedImagesSettingsResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data allowedImagesSettingsResourceModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.Plan.Get(ctx, &data)) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + inputE := ec2.EnableAllowedImagesSettingsInput{ + AllowedImagesSettingsState: data.State.ValueEnum(), + } + _, err := conn.EnableAllowedImagesSettings(ctx, &inputE) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + + var inputR ec2.ReplaceImageCriteriaInAllowedImagesSettingsInput + smerr.AddEnrich(ctx, &response.Diagnostics, fwflex.Expand(ctx, data, &inputR)) + if response.Diagnostics.HasError() { + return + } + + _, err = conn.ReplaceImageCriteriaInAllowedImagesSettings(ctx, &inputR) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + + smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, data)) +} + +func (r *allowedImagesSettingsResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data allowedImagesSettingsResourceModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.State.Get(ctx, &data)) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + out, err := findAllowedImagesSettings(ctx, conn) + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + return + } + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + + smerr.AddEnrich(ctx, &response.Diagnostics, fwflex.Flatten(ctx, out, &data)) + if response.Diagnostics.HasError() { + return + } + + smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, &data)) +} + +func (r *allowedImagesSettingsResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var new, old allowedImagesSettingsResourceModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.Plan.Get(ctx, &new)) + smerr.AddEnrich(ctx, &response.Diagnostics, request.State.Get(ctx, &old)) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().EC2Client(ctx) + + if !new.State.Equal(old.State) { + input := ec2.EnableAllowedImagesSettingsInput{ + AllowedImagesSettingsState: new.State.ValueEnum(), + } + _, err := conn.EnableAllowedImagesSettings(ctx, &input) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + } + + if !new.ImageCriteria.Equal(old.ImageCriteria) { + var input ec2.ReplaceImageCriteriaInAllowedImagesSettingsInput + smerr.AddEnrich(ctx, &response.Diagnostics, fwflex.Expand(ctx, new, &input)) + if response.Diagnostics.HasError() { + return + } + + _, err := conn.ReplaceImageCriteriaInAllowedImagesSettings(ctx, &input) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + } + + smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, &new)) +} + +func (r *allowedImagesSettingsResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + conn := r.Meta().EC2Client(ctx) + + var inputR ec2.ReplaceImageCriteriaInAllowedImagesSettingsInput + _, err := conn.ReplaceImageCriteriaInAllowedImagesSettings(ctx, &inputR) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + + var inputD ec2.DisableAllowedImagesSettingsInput + _, err = conn.DisableAllowedImagesSettings(ctx, &inputD) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } +} + +func (r *allowedImagesSettingsResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root(names.AttrRegion), request, response) +} + +type allowedImagesSettingsResourceModel struct { + framework.WithRegionModel + ImageCriteria fwtypes.ListNestedObjectValueOf[imageCriterionModel] `tfsdk:"image_criterion"` + State fwtypes.StringEnum[awstypes.AllowedImagesSettingsEnabledState] `tfsdk:"state"` +} + +type imageCriterionModel struct { + CreationDateCondition fwtypes.ListNestedObjectValueOf[creationDateConditionModel] `tfsdk:"creation_date_condition"` + DeprecationTimeCondition fwtypes.ListNestedObjectValueOf[deprecationTimeConditionModel] `tfsdk:"deprecation_time_condition"` + ImageNames fwtypes.SetOfString `tfsdk:"image_names"` + ImageProviders fwtypes.SetOfString `tfsdk:"image_providers"` + MarketplaceProductCodes fwtypes.SetOfString `tfsdk:"marketplace_product_codes"` +} + +type creationDateConditionModel struct { + MaximumDaysSinceCreated types.Int32 `tfsdk:"maximum_days_since_created"` +} + +type deprecationTimeConditionModel struct { + MaximumDaysSinceDeprecated types.Int32 `tfsdk:"maximum_days_since_deprecated"` +} diff --git a/internal/service/ec2/ec2_allowed_images_settings_test.go b/internal/service/ec2/ec2_allowed_images_settings_test.go new file mode 100644 index 000000000000..b6c95db82447 --- /dev/null +++ b/internal/service/ec2/ec2_allowed_images_settings_test.go @@ -0,0 +1,613 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccEC2AllowedImagesSettings_serial(t *testing.T) { + t.Parallel() + + testCases := map[string]func(*testing.T){ + acctest.CtBasic: testAccEC2AllowedImagesSettings_basic, + acctest.CtDisappears: testAccEC2AllowedImagesSettings_disappears, + "auditMode": testAccEC2AllowedImagesSettings_auditMode, + "imageCriteria": testAccEC2AllowedImagesSettings_imageCriteria, + "imageCriteriaMultiple": testAccEC2AllowedImagesSettings_imageCriteriaMultiple, + "imageCriteriaWithNames": testAccEC2AllowedImagesSettings_imageCriteriaWithNames, + "imageCriteriaWithMarketplace": testAccEC2AllowedImagesSettings_imageCriteriaWithMarketplace, + "imageCriteriaWithCreationDate": testAccEC2AllowedImagesSettings_imageCriteriaWithCreationDate, + "imageCriteriaWithDeprecationTime": testAccEC2AllowedImagesSettings_imageCriteriaWithDeprecationTime, + "imageCriteriaComplete": testAccEC2AllowedImagesSettings_imageCriteriaComplete, + "stateUpdate": testAccEC2AllowedImagesSettings_stateUpdate, + "imageCriteriaUpdate": testAccEC2AllowedImagesSettings_imageCriteriaUpdate, + } + + acctest.RunSerialTests1Level(t, testCases, 0) +} + +func testAccEC2AllowedImagesSettings_basic(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_disappears(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfec2.ResourceAllowedImagesSettings, resourceName), + ), + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_auditMode(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_auditMode(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, "audit-mode"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteria(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteria(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.image_providers.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "image_criterion.0.image_providers.*", "amazon"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaMultiple(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaMultiple(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "2"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.image_providers.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "image_criterion.0.image_providers.*", "amazon"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.1.image_providers.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "image_criterion.1.image_providers.*", "aws-marketplace"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaWithNames(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaWithNames(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.image_names.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "image_criterion.0.image_names.*", "al2023-ami-*"), + resource.TestCheckTypeSetElemAttr(resourceName, "image_criterion.0.image_names.*", "ubuntu/images/*"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaWithMarketplace(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaWithMarketplace(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.marketplace_product_codes.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "image_criterion.0.marketplace_product_codes.*", "abcdef123456"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaWithCreationDate(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaWithCreationDate(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.creation_date_condition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.creation_date_condition.0.maximum_days_since_created", "365"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaWithDeprecationTime(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaWithDeprecationTime(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.deprecation_time_condition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.deprecation_time_condition.0.maximum_days_since_deprecated", "30"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaComplete(t *testing.T) { + ctx := acctest.Context(t) + var settings ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaComplete(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.image_names.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.image_providers.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.marketplace_product_codes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.creation_date_condition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "image_criterion.0.deprecation_time_condition.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportStateId: acctest.Region(), + ImportStateVerifyIdentifierAttribute: names.AttrRegion, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_stateUpdate(t *testing.T) { + ctx := acctest.Context(t) + var settings1, settings2 ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings1), + resource.TestCheckResourceAttr(resourceName, names.AttrState, names.AttrEnabled), + ), + }, + { + Config: testAccAllowedImagesSettingsConfig_auditMode(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings2), + resource.TestCheckResourceAttr(resourceName, names.AttrState, "audit-mode"), + ), + }, + }, + }) +} + +func testAccEC2AllowedImagesSettings_imageCriteriaUpdate(t *testing.T) { + ctx := acctest.Context(t) + var settings1, settings2 ec2.GetAllowedImagesSettingsOutput + resourceName := "aws_ec2_allowed_images_settings.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAllowedImagesSettingsDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAllowedImagesSettingsConfig_imageCriteria(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings1), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "1"), + ), + }, + { + Config: testAccAllowedImagesSettingsConfig_imageCriteriaMultiple(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAllowedImagesSettingsExists(ctx, resourceName, &settings2), + resource.TestCheckResourceAttr(resourceName, "image_criterion.#", "2"), + ), + }, + }, + }) +} + +func testAccCheckAllowedImagesSettingsDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ec2_allowed_images_settings" { + continue + } + + _, err := tfec2.FindAllowedImagesSettings(ctx, conn) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return errors.New("EC2 Allowed Images Settings still exists") + } + + return nil + } +} + +func testAccCheckAllowedImagesSettingsExists(ctx context.Context, n string, v *ec2.GetAllowedImagesSettingsOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + output, err := tfec2.FindAllowedImagesSettings(ctx, conn) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccAllowedImagesSettingsConfig_basic() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" +} +` +} + +func testAccAllowedImagesSettingsConfig_auditMode() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "audit-mode" +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteria() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_providers = ["amazon"] + } +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteriaMultiple() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_providers = ["amazon"] + } + + image_criterion { + image_providers = ["aws-marketplace"] + } +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteriaWithNames() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_names = [ + "al2023-ami-*", + "ubuntu/images/*" + ] + } +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteriaWithMarketplace() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_providers = ["aws-marketplace"] + marketplace_product_codes = ["abcdef123456"] + } +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteriaWithCreationDate() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_providers = ["amazon"] + + creation_date_condition { + maximum_days_since_created = 365 + } + } +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteriaWithDeprecationTime() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_providers = ["amazon"] + + deprecation_time_condition { + maximum_days_since_deprecated = 30 + } + } +} +` +} + +func testAccAllowedImagesSettingsConfig_imageCriteriaComplete() string { + return ` +resource "aws_ec2_allowed_images_settings" "test" { + state = "enabled" + + image_criterion { + image_names = ["al2023-ami-*"] + image_providers = ["amazon"] + marketplace_product_codes = ["abc123def456"] + + creation_date_condition { + maximum_days_since_created = 180 + } + + deprecation_time_condition { + maximum_days_since_deprecated = 60 + } + } +} +` +} diff --git a/internal/service/ec2/ec2_image_block_public_access.go b/internal/service/ec2/ec2_image_block_public_access.go index 619174714a4e..a9445d0cb4c8 100644 --- a/internal/service/ec2/ec2_image_block_public_access.go +++ b/internal/service/ec2/ec2_image_block_public_access.go @@ -22,13 +22,16 @@ import ( ) // @SDKResource("aws_ec2_image_block_public_access", name="Image Block Public Access") -// @Region(global=true) // @SingletonIdentity +// @IdentityVersion(1, sdkV2IdentityUpgraders="imageBlockPublicAccessIdentityUpgradeV0") // @V60SDKv2Fix // @NoImport // @Testing(checkDestroyNoop=true) // @Testing(hasExistsFunction=false) // @Testing(generator=false) +// @Testing(identityTest=false) +// @Testing(identityVersion="0;v6.0.0") +// @Testing(identityVersion="1;v6.21.0") func resourceImageBlockPublicAccess() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceImageBlockPublicAccessPut, @@ -108,6 +111,14 @@ func resourceImageBlockPublicAccessRead(ctx context.Context, d *schema.ResourceD return diags } +var imageBlockPublicAccessIdentityUpgradeV0 = schema.IdentityUpgrader{ + Version: 0, + Upgrade: func(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + rawState[names.AttrRegion] = meta.(*conns.AWSClient).Region(ctx) + return rawState, nil + }, +} + func imageBlockPublicAccessDisabledState_Values() []string { return enum.Values[awstypes.ImageBlockPublicAccessDisabledState]() } diff --git a/internal/service/ec2/ec2_image_block_public_access_identity_gen_test.go b/internal/service/ec2/ec2_image_block_public_access_identity_test.go similarity index 50% rename from internal/service/ec2/ec2_image_block_public_access_identity_gen_test.go rename to internal/service/ec2/ec2_image_block_public_access_identity_test.go index 4b567858db27..5165b17cad9b 100644 --- a/internal/service/ec2/ec2_image_block_public_access_identity_gen_test.go +++ b/internal/service/ec2/ec2_image_block_public_access_identity_test.go @@ -1,4 +1,5 @@ -// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 package ec2_test @@ -18,6 +19,9 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) +// This code was initially generated by internal/generate/identitytests/main.go and then +// modified by hand to deal with resource identity schema migration. + func testAccEC2ImageBlockPublicAccess_IdentitySerial(t *testing.T) { t.Helper() @@ -25,6 +29,9 @@ func testAccEC2ImageBlockPublicAccess_IdentitySerial(t *testing.T) { acctest.CtBasic: testAccEC2ImageBlockPublicAccess_Identity_Basic, "ExistingResource": testAccEC2ImageBlockPublicAccess_Identity_ExistingResource, "ExistingResourceNoRefresh": testAccEC2ImageBlockPublicAccess_Identity_ExistingResource_NoRefresh_NoChange, + "RegionOverride": testAccEC2ImageBlockPublicAccess_Identity_RegionOverride, + "Upgrade": testAccEC2ImageBlockPublicAccess_Identity_Upgrade, + "UpgradeNoRefresh": testAccEC2ImageBlockPublicAccess_Identity_Upgrade_NoRefresh, } acctest.RunSerialTests1Level(t, testCases, 0) @@ -50,8 +57,43 @@ func testAccEC2ImageBlockPublicAccess_Identity_Basic(t *testing.T) { ConfigVariables: config.Variables{}, ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), tfknownvalue.AccountID()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + }, + }) +} + +func testAccEC2ImageBlockPublicAccess_Identity_RegionOverride(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_image_block_public_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/ImageBlockPublicAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), tfknownvalue.AccountID()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), }), }, }, @@ -116,6 +158,7 @@ func testAccEC2ImageBlockPublicAccess_Identity_ExistingResource(t *testing.T) { ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), }), }, }, @@ -159,3 +202,103 @@ func testAccEC2ImageBlockPublicAccess_Identity_ExistingResource_NoRefresh_NoChan }, }) } + +// Resource Identity version 1 was added in version 6.20.0 +func testAccEC2ImageBlockPublicAccess_Identity_Upgrade(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_image_block_public_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + Steps: []resource.TestStep{ + // Step 1: Create with Identity version 0 + { + ConfigDirectory: config.StaticDirectory("testdata/ImageBlockPublicAccess/basic_v6.19.0/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectHasIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ImageBlockPublicAccess/basic/"), + ConfigVariables: config.Variables{}, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + }, + }) +} + +// Resource Identity version 1 was added in version 6.20.0 +func testAccEC2ImageBlockPublicAccess_Identity_Upgrade_NoRefresh(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_image_block_public_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{ + NoRefresh: true, + }, + }, + Steps: []resource.TestStep{ + // Step 1: Create with Identity version 0 + { + ConfigDirectory: config.StaticDirectory("testdata/ImageBlockPublicAccess/basic_v6.19.0/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectHasIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ImageBlockPublicAccess/basic/"), + ConfigVariables: config.Variables{}, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + // New "region" attribute. + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + }, + }) +} diff --git a/internal/service/ec2/ec2_instance.go b/internal/service/ec2/ec2_instance.go index 0589bbd1a25e..6ca54b7b12a6 100644 --- a/internal/service/ec2/ec2_instance.go +++ b/internal/service/ec2/ec2_instance.go @@ -47,7 +47,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/provider/sdkv2/importer" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -876,7 +876,7 @@ func resourceInstance() *schema.Resource { return sdkdiag.AppendErrorf(diags, "expected type to be string") } - if _, err := itypes.Base64Decode(v); err == nil { + if _, err := inttypes.Base64Decode(v); err == nil { // value is a base46 encoded string return diag.Diagnostics{ diag.Diagnostic{ @@ -1071,7 +1071,7 @@ func throughputDiffSuppressFunc(k, old, new string, d *schema.ResourceData) bool } // @SDKListResource("aws_instance") -func instanceResourceAsListResource() itypes.ListResourceForSDK { +func instanceResourceAsListResource() inttypes.ListResourceForSDK { l := instanceListResource{} l.SetResourceSchema(resourceInstance()) @@ -1581,7 +1581,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta an if d.HasChange("user_data") { // Decode so the AWS SDK doesn't double encode. - v, err := itypes.Base64Decode(d.Get("user_data").(string)) + v, err := inttypes.Base64Decode(d.Get("user_data").(string)) if err != nil { v = []byte(d.Get("user_data").(string)) } @@ -1601,7 +1601,7 @@ func resourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, meta an if d.HasChange("user_data_base64") { // Schema validation technically ensures the data is Base64 encoded. // Decode so the AWS SDK doesn't double encode. - v, err := itypes.Base64Decode(d.Get("user_data_base64").(string)) + v, err := inttypes.Base64Decode(d.Get("user_data_base64").(string)) if err != nil { v = []byte(d.Get("user_data_base64").(string)) } @@ -3013,7 +3013,7 @@ func userDataHashSum(userData string) string { // Check whether the user_data is not Base64 encoded. // Always calculate hash of base64 decoded value since we // check against double-encoding when setting it. - v, err := itypes.Base64Decode(userData) + v, err := inttypes.Base64Decode(userData) if err != nil { v = []byte(userData) } @@ -3378,7 +3378,7 @@ func resourceInstanceFlatten(ctx context.Context, client *conns.AWSClient, insta if b64 { rd.Set("user_data_base64", attr.UserData.Value) } else { - data, err := itypes.Base64Decode(aws.ToString(attr.UserData.Value)) + data, err := inttypes.Base64Decode(aws.ToString(attr.UserData.Value)) if err != nil { return sdkdiag.AppendErrorf(diags, "decoding user_data: %s", err) } diff --git a/internal/service/ec2/ec2_instance_data_source_tags_gen_test.go b/internal/service/ec2/ec2_instance_data_source_tags_gen_test.go index de9fef100947..bbcdaef5dab5 100644 --- a/internal/service/ec2/ec2_instance_data_source_tags_gen_test.go +++ b/internal/service/ec2/ec2_instance_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -193,7 +193,7 @@ func TestAccEC2InstanceDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing } func expectFullInstanceDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, }), knownValue) } diff --git a/internal/service/ec2/ec2_instance_metadata_defaults.go b/internal/service/ec2/ec2_instance_metadata_defaults.go index 92bf42b35bbc..8347f4ee2b1c 100644 --- a/internal/service/ec2/ec2_instance_metadata_defaults.go +++ b/internal/service/ec2/ec2_instance_metadata_defaults.go @@ -22,7 +22,7 @@ import ( fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -134,7 +134,7 @@ func (r *instanceMetadataDefaultsResource) Read(ctx context.Context, request res output, err := findInstanceMetadataDefaults(ctx, conn) switch { - case err == nil && itypes.IsZero(output): + case err == nil && inttypes.IsZero(output): err = tfresource.NewEmptyResultError(nil) fallthrough case tfresource.NotFound(err): diff --git a/internal/service/ec2/ec2_instance_metadata_defaults_test.go b/internal/service/ec2/ec2_instance_metadata_defaults_test.go index dd2be053cb2b..311648d42e06 100644 --- a/internal/service/ec2/ec2_instance_metadata_defaults_test.go +++ b/internal/service/ec2/ec2_instance_metadata_defaults_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -115,7 +115,7 @@ func testAccCheckInstanceMetadataDefaultsDestroy(ctx context.Context) resource.T output, err := tfec2.FindInstanceMetadataDefaults(ctx, conn) - if tfresource.NotFound(err) || err == nil && itypes.IsZero(output) { + if tfresource.NotFound(err) || err == nil && inttypes.IsZero(output) { continue } diff --git a/internal/service/ec2/ec2_serial_console_access.go b/internal/service/ec2/ec2_serial_console_access.go index 8ec288695778..b2762e1c2453 100644 --- a/internal/service/ec2/ec2_serial_console_access.go +++ b/internal/service/ec2/ec2_serial_console_access.go @@ -5,21 +5,26 @@ package ec2 import ( "context" + "log" "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKResource("aws_ec2_serial_console_access", name="Serial Console Access") -// @Region(global=true) // @SingletonIdentity +// @IdentityVersion(1, sdkV2IdentityUpgraders="serialConsoleAccessIdentityUpgradeV0") // @V60SDKv2Fix // @Testing(hasExistsFunction=false) // @Testing(generator=false) +// @Testing(identityTest=false) +// @Testing(identityVersion="0;v6.0.0") +// @Testing(identityVersion="1;v6.21.0") func resourceSerialConsoleAccess() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceSerialConsoleAccessCreate, @@ -39,7 +44,6 @@ func resourceSerialConsoleAccess() *schema.Resource { func resourceSerialConsoleAccessCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Client(ctx) enabled := d.Get(names.AttrEnabled).(bool) @@ -47,18 +51,22 @@ func resourceSerialConsoleAccessCreate(ctx context.Context, d *schema.ResourceDa return sdkdiag.AppendErrorf(diags, "setting EC2 Serial Console Access (%t): %s", enabled, err) } - d.SetId(meta.(*conns.AWSClient).AccountID(ctx)) + d.SetId(meta.(*conns.AWSClient).Region(ctx)) return append(diags, resourceSerialConsoleAccessRead(ctx, d, meta)...) } func resourceSerialConsoleAccessRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Client(ctx) - input := ec2.GetSerialConsoleAccessStatusInput{} - output, err := conn.GetSerialConsoleAccessStatus(ctx, &input) + output, err := findSerialConsoleAccessStatus(ctx, conn) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EC2 Serial Console Access %s not found, removing from state", d.Id()) + d.SetId("") + return diags + } if err != nil { return sdkdiag.AppendErrorf(diags, "reading EC2 Serial Console Access: %s", err) @@ -71,7 +79,6 @@ func resourceSerialConsoleAccessRead(ctx context.Context, d *schema.ResourceData func resourceSerialConsoleAccessUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Client(ctx) enabled := d.Get(names.AttrEnabled).(bool) @@ -84,7 +91,6 @@ func resourceSerialConsoleAccessUpdate(ctx context.Context, d *schema.ResourceDa func resourceSerialConsoleAccessDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Client(ctx) // Removing the resource disables serial console access. @@ -99,12 +105,20 @@ func setSerialConsoleAccess(ctx context.Context, conn *ec2.Client, enabled bool) var err error if enabled { - input := ec2.EnableSerialConsoleAccessInput{} + var input ec2.EnableSerialConsoleAccessInput _, err = conn.EnableSerialConsoleAccess(ctx, &input) } else { - input := ec2.DisableSerialConsoleAccessInput{} + var input ec2.DisableSerialConsoleAccessInput _, err = conn.DisableSerialConsoleAccess(ctx, &input) } return err } + +var serialConsoleAccessIdentityUpgradeV0 = schema.IdentityUpgrader{ + Version: 0, + Upgrade: func(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + rawState[names.AttrRegion] = meta.(*conns.AWSClient).Region(ctx) + return rawState, nil + }, +} diff --git a/internal/service/ec2/ec2_serial_console_access_data_source.go b/internal/service/ec2/ec2_serial_console_access_data_source.go index 4053a5168feb..5ec4a8408179 100644 --- a/internal/service/ec2/ec2_serial_console_access_data_source.go +++ b/internal/service/ec2/ec2_serial_console_access_data_source.go @@ -7,7 +7,6 @@ import ( "context" "time" - "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -34,11 +33,9 @@ func dataSourceSerialConsoleAccess() *schema.Resource { } func dataSourceSerialConsoleAccessRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Client(ctx) - input := ec2.GetSerialConsoleAccessStatusInput{} - output, err := conn.GetSerialConsoleAccessStatus(ctx, &input) + output, err := findSerialConsoleAccessStatus(ctx, conn) if err != nil { return sdkdiag.AppendErrorf(diags, "reading EC2 Serial Console Access: %s", err) diff --git a/internal/service/ec2/ec2_serial_console_access_identity_gen_test.go b/internal/service/ec2/ec2_serial_console_access_identity_gen_test.go deleted file mode 100644 index cc61b3041477..000000000000 --- a/internal/service/ec2/ec2_serial_console_access_identity_gen_test.go +++ /dev/null @@ -1,199 +0,0 @@ -// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. - -package ec2_test - -import ( - "testing" - - "github.com/hashicorp/terraform-plugin-testing/config" - "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/knownvalue" - "github.com/hashicorp/terraform-plugin-testing/plancheck" - "github.com/hashicorp/terraform-plugin-testing/statecheck" - "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" - "github.com/hashicorp/terraform-plugin-testing/tfversion" - "github.com/hashicorp/terraform-provider-aws/internal/acctest" - tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" - tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" - "github.com/hashicorp/terraform-provider-aws/names" -) - -func testAccEC2SerialConsoleAccess_IdentitySerial(t *testing.T) { - t.Helper() - - testCases := map[string]func(t *testing.T){ - acctest.CtBasic: testAccEC2SerialConsoleAccess_Identity_Basic, - "ExistingResource": testAccEC2SerialConsoleAccess_Identity_ExistingResource, - "ExistingResourceNoRefresh": testAccEC2SerialConsoleAccess_Identity_ExistingResource_NoRefresh_NoChange, - } - - acctest.RunSerialTests1Level(t, testCases, 0) -} - -func testAccEC2SerialConsoleAccess_Identity_Basic(t *testing.T) { - ctx := acctest.Context(t) - - resourceName := "aws_ec2_serial_console_access.test" - - acctest.Test(ctx, t, resource.TestCase{ - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_12_0), - }, - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), - CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - Steps: []resource.TestStep{ - // Step 1: Setup - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), - ConfigVariables: config.Variables{}, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), tfknownvalue.AccountID()), - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - names.AttrAccountID: tfknownvalue.AccountID(), - }), - }, - }, - - // Step 2: Import command - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), - ConfigVariables: config.Variables{}, - ImportStateKind: resource.ImportCommandWithID, - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - - // Step 3: Import block with Import ID - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), - ConfigVariables: config.Variables{}, - ResourceName: resourceName, - ImportState: true, - ImportStateKind: resource.ImportBlockWithID, - ImportPlanChecks: resource.ImportPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), tfknownvalue.AccountID()), - }, - }, - }, - - // Step 4: Import block with Resource Identity - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), - ConfigVariables: config.Variables{}, - ResourceName: resourceName, - ImportState: true, - ImportStateKind: resource.ImportBlockWithResourceIdentity, - ImportPlanChecks: resource.ImportPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), tfknownvalue.AccountID()), - }, - }, - }, - }, - }) -} - -func testAccEC2SerialConsoleAccess_Identity_ExistingResource(t *testing.T) { - ctx := acctest.Context(t) - - resourceName := "aws_ec2_serial_console_access.test" - - acctest.Test(ctx, t, resource.TestCase{ - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_12_0), - }, - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), - CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), - Steps: []resource.TestStep{ - // Step 1: Create pre-Identity - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v5.100.0/"), - ConfigVariables: config.Variables{}, - ConfigStateChecks: []statecheck.StateCheck{ - tfstatecheck.ExpectNoIdentity(resourceName), - }, - }, - - // Step 2: v6.0 Identity error - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v6.0.0/"), - ConfigVariables: config.Variables{}, - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), - }, - PostApplyPostRefresh: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), - }, - }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - names.AttrAccountID: knownvalue.Null(), - }), - }, - }, - - // Step 3: Current version - { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), - ConfigVariables: config.Variables{}, - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), - }, - PostApplyPostRefresh: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), - }, - }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ - names.AttrAccountID: tfknownvalue.AccountID(), - }), - }, - }, - }, - }) -} - -func testAccEC2SerialConsoleAccess_Identity_ExistingResource_NoRefresh_NoChange(t *testing.T) { - ctx := acctest.Context(t) - - resourceName := "aws_ec2_serial_console_access.test" - - acctest.Test(ctx, t, resource.TestCase{ - TerraformVersionChecks: []tfversion.TerraformVersionCheck{ - tfversion.SkipBelow(tfversion.Version1_12_0), - }, - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), - CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), - AdditionalCLIOptions: &resource.AdditionalCLIOptions{ - Plan: resource.PlanOptions{ - NoRefresh: true, - }, - }, - Steps: []resource.TestStep{ - // Step 1: Create pre-Identity - { - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v5.100.0/"), - ConfigVariables: config.Variables{}, - ConfigStateChecks: []statecheck.StateCheck{ - tfstatecheck.ExpectNoIdentity(resourceName), - }, - }, - - // Step 2: Current version - { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), - ConfigVariables: config.Variables{}, - }, - }, - }) -} diff --git a/internal/service/ec2/ec2_serial_console_access_identity_test.go b/internal/service/ec2/ec2_serial_console_access_identity_test.go new file mode 100644 index 000000000000..4096d880a6c4 --- /dev/null +++ b/internal/service/ec2/ec2_serial_console_access_identity_test.go @@ -0,0 +1,422 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/compare" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// This code was initially generated by internal/generate/identitytests/main.go and then +// modified by hand to deal with resource identity schema migration. + +func testAccEC2SerialConsoleAccess_IdentitySerial(t *testing.T) { + t.Helper() + + testCases := map[string]func(t *testing.T){ + acctest.CtBasic: testAccEC2SerialConsoleAccess_Identity_Basic, + "ExistingResource": testAccEC2SerialConsoleAccess_Identity_ExistingResource, + "ExistingResourceNoRefresh": testAccEC2SerialConsoleAccess_Identity_ExistingResource_NoRefresh_NoChange, + "RegionOverride": testAccEC2SerialConsoleAccess_Identity_RegionOverride, + "Upgrade": testAccEC2SerialConsoleAccess_Identity_Upgrade, + "UpgradeNoRefresh": testAccEC2SerialConsoleAccess_Identity_Upgrade_NoRefresh, + } + + acctest.RunSerialTests1Level(t, testCases, 0) +} + +func testAccEC2SerialConsoleAccess_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_serial_console_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New(names.AttrRegion), compare.ValuesSame()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ImportStateKind: resource.ImportCommandWithID, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.StringExact(acctest.Region())), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.StringExact(acctest.Region())), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + }, + }, + }) +} + +func testAccEC2SerialConsoleAccess_Identity_RegionOverride(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_serial_console_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs(resourceName, tfjsonpath.New(names.AttrID), resourceName, tfjsonpath.New(names.AttrRegion), compare.ValuesSame()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), + }), + }, + }, + + // Step 2: Import command with appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.CrossRegionImportStateIdFunc(resourceName), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 3: Import command without appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + + // Step 4: Import block with Import ID and appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.CrossRegionImportStateIdFunc(resourceName), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.StringExact(acctest.AlternateRegion())), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + + // Step 5: Import block with Import ID and no appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.StringExact(acctest.AlternateRegion())), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + + // Step 6: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/region_override/"), + ConfigVariables: config.Variables{ + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.StringExact(acctest.AlternateRegion())), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + }, + }) +} + +func testAccEC2SerialConsoleAccess_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_serial_console_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v5.100.0/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: v6.0 Identity error + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v6.0.0/"), + ConfigVariables: config.Variables{}, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: knownvalue.Null(), + }), + }, + }, + + // Step 3: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + }, + }) +} + +func testAccEC2SerialConsoleAccess_Identity_ExistingResource_NoRefresh_NoChange(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_serial_console_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{ + NoRefresh: true, + }, + }, + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v5.100.0/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + }, + }, + }) +} + +// Resource Identity version 1 was added in version 6.21.0 +func testAccEC2SerialConsoleAccess_Identity_Upgrade(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_serial_console_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create with Identity version 0 + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v6.20.0/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectHasIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + }, + }) +} + +// Resource Identity version 1 was added in version 6.21.0 +func testAccEC2SerialConsoleAccess_Identity_Upgrade_NoRefresh(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_ec2_serial_console_access.test" + + acctest.Test(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: testAccCheckSerialConsoleAccessDestroy(ctx), + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{ + NoRefresh: true, + }, + }, + Steps: []resource.TestStep{ + // Step 1: Create with Identity version 0 + { + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic_v6.20.0/"), + ConfigVariables: config.Variables{}, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectHasIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SerialConsoleAccess/basic/"), + ConfigVariables: config.Variables{}, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + // New "region" attribute. + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrAccountID: tfknownvalue.AccountID(), + names.AttrRegion: knownvalue.StringExact(acctest.Region()), + }), + }, + }, + }, + }) +} diff --git a/internal/service/ec2/ec2_serial_console_access_test.go b/internal/service/ec2/ec2_serial_console_access_test.go index 4e50814d5950..8895ba94b98f 100644 --- a/internal/service/ec2/ec2_serial_console_access_test.go +++ b/internal/service/ec2/ec2_serial_console_access_test.go @@ -9,11 +9,12 @@ import ( "testing" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -70,14 +71,18 @@ func testAccCheckSerialConsoleAccessDestroy(ctx context.Context) resource.TestCh return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) - input := ec2.GetSerialConsoleAccessStatusInput{} - response, err := conn.GetSerialConsoleAccessStatus(ctx, &input) + output, err := tfec2.FindSerialConsoleAccessStatus(ctx, conn) + + if tfresource.NotFound(err) { + return nil + } + if err != nil { return err } - if aws.ToBool(response.SerialConsoleAccessEnabled) != false { - return fmt.Errorf("Serial console access not disabled on resource removal") + if aws.ToBool(output.SerialConsoleAccessEnabled) != false { + return fmt.Errorf("EC2 Serial Console Access not disabled on resource removal") } return nil @@ -86,25 +91,21 @@ func testAccCheckSerialConsoleAccessDestroy(ctx context.Context) resource.TestCh func testAccCheckSerialConsoleAccess(ctx context.Context, n string, enabled bool) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] + _, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) - input := ec2.GetSerialConsoleAccessStatusInput{} - response, err := conn.GetSerialConsoleAccessStatus(ctx, &input) + output, err := tfec2.FindSerialConsoleAccessStatus(ctx, conn) + if err != nil { return err } - if aws.ToBool(response.SerialConsoleAccessEnabled) != enabled { - return fmt.Errorf("Serial console access is not in expected state (%t)", enabled) + if aws.ToBool(output.SerialConsoleAccessEnabled) != enabled { + return fmt.Errorf("EC2 Serial Console Access is not in expected state (%t)", enabled) } return nil diff --git a/internal/service/ec2/exports_test.go b/internal/service/ec2/exports_test.go index 969489f6f977..7ce9fdfd526c 100644 --- a/internal/service/ec2/exports_test.go +++ b/internal/service/ec2/exports_test.go @@ -5,6 +5,7 @@ package ec2 // Exports for use in tests only. var ( + ResourceAllowedImagesSettings = newAllowedImagesSettingsResource ResourceAMICopy = resourceAMICopy ResourceAMIFromInstance = resourceAMIFromInstance ResourceAMILaunchPermission = resourceAMILaunchPermission @@ -140,6 +141,7 @@ var ( ErrCodeDefaultSubnetAlreadyExistsInAvailabilityZone = errCodeDefaultSubnetAlreadyExistsInAvailabilityZone ErrCodeInvalidSpotDatafeedNotFound = errCodeInvalidSpotDatafeedNotFound ExpandIPPerms = expandIPPerms + FindAllowedImagesSettings = findAllowedImagesSettings FindAvailabilityZones = findAvailabilityZones FindCapacityReservationByID = findCapacityReservationByID FindCarrierGatewayByID = findCarrierGatewayByID @@ -210,6 +212,7 @@ var ( FindSecurityGroupEgressRuleByID = findSecurityGroupEgressRuleByID FindSecurityGroupIngressRuleByID = findSecurityGroupIngressRuleByID FindSecurityGroupVPCAssociationByTwoPartKey = findSecurityGroupVPCAssociationByTwoPartKey + FindSerialConsoleAccessStatus = findSerialConsoleAccessStatus FindSnapshot = findSnapshot FindSnapshotByID = findSnapshotByID FindSpotDatafeedSubscription = findSpotDatafeedSubscription diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 15abb78a0ab9..93571aaa295e 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -19,10 +19,32 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/enum" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) +func findAllowedImagesSettings(ctx context.Context, conn *ec2.Client) (*ec2.GetAllowedImagesSettingsOutput, error) { + input := ec2.GetAllowedImagesSettingsInput{} + output, err := conn.GetAllowedImagesSettings(ctx, &input) + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + // Disabled => NotFound. + if state := aws.ToString(output.State); state == string(awstypes.AllowedImagesSettingsDisabledStateDisabled) { + return nil, &retry.NotFoundError{ + Message: state, + } + } + + return output, nil +} + func findAvailabilityZones(ctx context.Context, conn *ec2.Client, input *ec2.DescribeAvailabilityZonesInput) ([]awstypes.AvailabilityZone, error) { output, err := conn.DescribeAvailabilityZones(ctx, input) @@ -2869,7 +2891,7 @@ func findRouteByIPv4Destination(ctx context.Context, conn *ec2.Client, routeTabl } for _, route := range routeTable.Routes { - if types.CIDRBlocksEqual(aws.ToString(route.DestinationCidrBlock), destinationCidr) { + if inttypes.CIDRBlocksEqual(aws.ToString(route.DestinationCidrBlock), destinationCidr) { return &route, nil } } @@ -2889,7 +2911,7 @@ func findRouteByIPv6Destination(ctx context.Context, conn *ec2.Client, routeTabl } for _, route := range routeTable.Routes { - if types.CIDRBlocksEqual(aws.ToString(route.DestinationIpv6CidrBlock), destinationIpv6Cidr) { + if inttypes.CIDRBlocksEqual(aws.ToString(route.DestinationIpv6CidrBlock), destinationIpv6Cidr) { return &route, nil } } @@ -4614,6 +4636,21 @@ func findImageLaunchPermission(ctx context.Context, conn *ec2.Client, imageID, a return nil, &retry.NotFoundError{} } +func findSerialConsoleAccessStatus(ctx context.Context, conn *ec2.Client) (*ec2.GetSerialConsoleAccessStatusOutput, error) { + input := ec2.GetSerialConsoleAccessStatusInput{} + output, err := conn.GetSerialConsoleAccessStatus(ctx, &input) + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + func findTransitGateway(ctx context.Context, conn *ec2.Client, input *ec2.DescribeTransitGatewaysInput) (*awstypes.TransitGateway, error) { output, err := findTransitGateways(ctx, conn, input) @@ -5251,7 +5288,7 @@ func findTransitGatewayStaticRoute(ctx context.Context, conn *ec2.Client, transi } for _, route := range output { - if v := aws.ToString(route.DestinationCidrBlock); types.CIDRBlocksEqual(v, destination) { + if v := aws.ToString(route.DestinationCidrBlock); inttypes.CIDRBlocksEqual(v, destination) { if state := route.State; state == awstypes.TransitGatewayRouteStateDeleted { return nil, &retry.NotFoundError{ Message: string(state), @@ -5259,7 +5296,7 @@ func findTransitGatewayStaticRoute(ctx context.Context, conn *ec2.Client, transi } } - route.DestinationCidrBlock = aws.String(types.CanonicalCIDRBlock(v)) + route.DestinationCidrBlock = aws.String(inttypes.CanonicalCIDRBlock(v)) return &route, nil } diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 0664c667b7b0..fc613a775b81 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -93,6 +93,12 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.Ser Name: "EBS Fast Snapshot Restore", Region: unique.Make(inttypes.ResourceRegionDefault()), }, + { + Factory: newAllowedImagesSettingsResource, + TypeName: "aws_ec2_allowed_images_settings", + Name: "Allowed Images Settings", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, { Factory: newCapacityBlockReservationResource, TypeName: "aws_ec2_capacity_block_reservation", @@ -1031,9 +1037,11 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa Factory: resourceImageBlockPublicAccess, TypeName: "aws_ec2_image_block_public_access", Name: "Image Block Public Access", - Region: unique.Make(inttypes.ResourceRegionDisabled()), - Identity: inttypes.GlobalSingletonIdentity( + Region: unique.Make(inttypes.ResourceRegionDefault()), + Identity: inttypes.RegionalSingletonIdentity( inttypes.WithV6_0SDKv2Fix(), + inttypes.WithVersion(1), + inttypes.WithSDKv2IdentityUpgraders(imageBlockPublicAccessIdentityUpgradeV0), ), }, { @@ -1094,9 +1102,11 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa Factory: resourceSerialConsoleAccess, TypeName: "aws_ec2_serial_console_access", Name: "Serial Console Access", - Region: unique.Make(inttypes.ResourceRegionDisabled()), - Identity: inttypes.GlobalSingletonIdentity( + Region: unique.Make(inttypes.ResourceRegionDefault()), + Identity: inttypes.RegionalSingletonIdentity( inttypes.WithV6_0SDKv2Fix(), + inttypes.WithVersion(1), + inttypes.WithSDKv2IdentityUpgraders(serialConsoleAccessIdentityUpgradeV0), ), Import: inttypes.SDKv2Import{ WrappedImport: true, diff --git a/internal/service/ec2/testdata/ImageBlockPublicAccess/basic_v6.19.0/main_gen.tf b/internal/service/ec2/testdata/ImageBlockPublicAccess/basic_v6.19.0/main_gen.tf new file mode 100644 index 000000000000..9694ee9e7c10 --- /dev/null +++ b/internal/service/ec2/testdata/ImageBlockPublicAccess/basic_v6.19.0/main_gen.tf @@ -0,0 +1,17 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_ec2_image_block_public_access" "test" { + state = "block-new-sharing" +} + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.19.0" + } + } +} + +provider "aws" {} diff --git a/internal/service/ec2/testdata/ImageBlockPublicAccess/region_override/main_gen.tf b/internal/service/ec2/testdata/ImageBlockPublicAccess/region_override/main_gen.tf new file mode 100644 index 000000000000..504f50eeef35 --- /dev/null +++ b/internal/service/ec2/testdata/ImageBlockPublicAccess/region_override/main_gen.tf @@ -0,0 +1,15 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_ec2_image_block_public_access" "test" { + region = var.region + + state = "block-new-sharing" +} + + +variable "region" { + description = "Region to deploy resource in" + type = string + nullable = false +} diff --git a/internal/service/ec2/testdata/SerialConsoleAccess/basic_v6.20.0/main_gen.tf b/internal/service/ec2/testdata/SerialConsoleAccess/basic_v6.20.0/main_gen.tf new file mode 100644 index 000000000000..d02066ba2f54 --- /dev/null +++ b/internal/service/ec2/testdata/SerialConsoleAccess/basic_v6.20.0/main_gen.tf @@ -0,0 +1,17 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_ec2_serial_console_access" "test" { + enabled = true +} + +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.20.0" + } + } +} + +provider "aws" {} diff --git a/internal/service/ec2/testdata/SerialConsoleAccess/region_override/main_gen.tf b/internal/service/ec2/testdata/SerialConsoleAccess/region_override/main_gen.tf new file mode 100644 index 000000000000..ab68872cde47 --- /dev/null +++ b/internal/service/ec2/testdata/SerialConsoleAccess/region_override/main_gen.tf @@ -0,0 +1,15 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_ec2_serial_console_access" "test" { + region = var.region + + enabled = true +} + + +variable "region" { + description = "Region to deploy resource in" + type = string + nullable = false +} diff --git a/internal/service/ec2/testdata/tmpl/ec2_image_block_public_access_basic.gtpl b/internal/service/ec2/testdata/tmpl/ec2_image_block_public_access_basic.gtpl index 5bb6da32d5ec..6bc466e80f96 100644 --- a/internal/service/ec2/testdata/tmpl/ec2_image_block_public_access_basic.gtpl +++ b/internal/service/ec2/testdata/tmpl/ec2_image_block_public_access_basic.gtpl @@ -1,3 +1,4 @@ resource "aws_ec2_image_block_public_access" "test" { +{{- template "region" }} state = "block-new-sharing" } diff --git a/internal/service/ec2/testdata/tmpl/ec2_serial_console_access_basic.gtpl b/internal/service/ec2/testdata/tmpl/ec2_serial_console_access_basic.gtpl index 994c0ac1dec1..0d884b08d871 100644 --- a/internal/service/ec2/testdata/tmpl/ec2_serial_console_access_basic.gtpl +++ b/internal/service/ec2/testdata/tmpl/ec2_serial_console_access_basic.gtpl @@ -1,3 +1,4 @@ resource "aws_ec2_serial_console_access" "test" { +{{- template "region" }} enabled = true } diff --git a/internal/service/ec2/vpc_data_source_tags_gen_test.go b/internal/service/ec2/vpc_data_source_tags_gen_test.go index 42957019ec34..b09e983cec19 100644 --- a/internal/service/ec2/vpc_data_source_tags_gen_test.go +++ b/internal/service/ec2/vpc_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -193,7 +193,7 @@ func TestAccVPCDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { } func expectFullVPCDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, }), knownValue) } diff --git a/internal/service/ec2/vpc_route_table.go b/internal/service/ec2/vpc_route_table.go index 0620f8d0d5ba..4ce12ea18035 100644 --- a/internal/service/ec2/vpc_route_table.go +++ b/internal/service/ec2/vpc_route_table.go @@ -23,7 +23,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -391,7 +391,7 @@ func resourceRouteTableHash(v any) int { } if v, ok := m["ipv6_cidr_block"]; ok { - fmt.Fprintf(&buf, "%s-", itypes.CanonicalCIDRBlock(v.(string))) + fmt.Fprintf(&buf, "%s-", inttypes.CanonicalCIDRBlock(v.(string))) } if v, ok := m[names.AttrCIDRBlock]; ok { diff --git a/internal/service/ec2/vpc_security_group_data_source_tags_gen_test.go b/internal/service/ec2/vpc_security_group_data_source_tags_gen_test.go index 9440862299fc..f461a783c617 100644 --- a/internal/service/ec2/vpc_security_group_data_source_tags_gen_test.go +++ b/internal/service/ec2/vpc_security_group_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccVPCSecurityGroupDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *te } func expectFullSecurityGroupDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, }), knownValue) } diff --git a/internal/service/ec2/vpc_subnet.go b/internal/service/ec2/vpc_subnet.go index e088d1036e3d..068099df1a3d 100644 --- a/internal/service/ec2/vpc_subnet.go +++ b/internal/service/ec2/vpc_subnet.go @@ -32,7 +32,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/logging" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" @@ -171,7 +171,7 @@ func resourceSubnet() *schema.Resource { } // @SDKListResource("aws_subnet") -func subnetResourceAsListResource() itypes.ListResourceForSDK { +func subnetResourceAsListResource() inttypes.ListResourceForSDK { l := subnetListResource{} l.SetResourceSchema(resourceSubnet()) diff --git a/internal/service/ec2/vpc_subnet_data_source_tags_gen_test.go b/internal/service/ec2/vpc_subnet_data_source_tags_gen_test.go index eb12479efeb2..eb9de5d56cd4 100644 --- a/internal/service/ec2/vpc_subnet_data_source_tags_gen_test.go +++ b/internal/service/ec2/vpc_subnet_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -193,7 +193,7 @@ func TestAccVPCSubnetDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T } func expectFullSubnetDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfec2.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, }), knownValue) } diff --git a/internal/service/ec2/vpnsite_connection.go b/internal/service/ec2/vpnsite_connection.go index de7497f55876..73b40011996f 100644 --- a/internal/service/ec2/vpnsite_connection.go +++ b/internal/service/ec2/vpnsite_connection.go @@ -154,6 +154,15 @@ func resourceVPNConnection() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "tunnel_bandwidth": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.VpnTunnelBandwidth](), + // Not supported on VGW + ConflictsWith: []string{"vpn_gateway_id"}, + }, "tunnel_inside_ip_version": { Type: schema.TypeString, Optional: true, @@ -787,6 +796,7 @@ func resourceVPNConnectionRead(ctx context.Context, d *schema.ResourceData, meta d.Set("remote_ipv6_network_cidr", v.RemoteIpv6NetworkCidr) d.Set("static_routes_only", v.StaticRoutesOnly) d.Set("transport_transit_gateway_attachment_id", v.TransportTransitGatewayAttachmentId) + d.Set("tunnel_bandwidth", v.TunnelBandwidth) d.Set("tunnel_inside_ip_version", v.TunnelInsideIpVersion) for i, prefix := range []string{"tunnel1_", "tunnel2_"} { @@ -1019,6 +1029,10 @@ func expandVPNConnectionOptionsSpecification(d *schema.ResourceData) *awstypes.V apiObject.StaticRoutesOnly = aws.Bool(v.(bool)) } + if v, ok := d.Get("tunnel_bandwidth").(string); ok { + apiObject.TunnelBandwidth = awstypes.VpnTunnelBandwidth(v) + } + if v, ok := d.GetOk("transport_transit_gateway_attachment_id"); ok { apiObject.TransportTransitGatewayAttachmentId = aws.String(v.(string)) } diff --git a/internal/service/ec2/vpnsite_connection_test.go b/internal/service/ec2/vpnsite_connection_test.go index c0d161603949..965d13e812a8 100644 --- a/internal/service/ec2/vpnsite_connection_test.go +++ b/internal/service/ec2/vpnsite_connection_test.go @@ -1373,6 +1373,71 @@ func TestAccSiteVPNConnection_ipv6(t *testing.T) { }) } +func TestAccSiteVPNConnection_largeBandwidthTunnel_TGW(t *testing.T) { + ctx := acctest.Context(t) + var vpn awstypes.VpnConnection + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rBgpAsn := sdkacctest.RandIntRange(64512, 65534) + transitGatewayResourceName := "aws_ec2_transit_gateway.test" + resourceName := "aws_vpn_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheckTransitGateway(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPNConnectionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccSiteVPNConnectionConfig_largeBandwidth_TGW(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccVPNConnectionExists(ctx, resourceName, &vpn), + resource.TestCheckResourceAttr(resourceName, "tunnel_bandwidth", "large"), + resource.TestMatchResourceAttr(resourceName, names.AttrTransitGatewayAttachmentID, regexache.MustCompile(`tgw-attach-.+`)), + resource.TestCheckResourceAttrPair(resourceName, names.AttrTransitGatewayID, transitGatewayResourceName, names.AttrID), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"vgw_telemetry"}, + }, + }, + }) +} + +func TestAccSiteVPNConnection_largeBandwidthTunnel_withoutTGWorVGW(t *testing.T) { + ctx := acctest.Context(t) + var vpn awstypes.VpnConnection + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rBgpAsn := sdkacctest.RandIntRange(64512, 65534) + resourceName := "aws_vpn_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheckTransitGateway(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPNConnectionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccSiteVPNConnectionConfig_largeBandwidth_WithoutTGWorVGW(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccVPNConnectionExists(ctx, resourceName, &vpn), + resource.TestCheckResourceAttr(resourceName, "tunnel_bandwidth", "large"), + resource.TestCheckResourceAttr(resourceName, "core_network_arn", ""), + resource.TestCheckResourceAttr(resourceName, "core_network_attachment_arn", ""), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"vgw_telemetry"}, + }, + }, + }) +} + func TestAccSiteVPNConnection_tags(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -2844,3 +2909,48 @@ const testAccVPNTunnelInfoXML = ` ` + +func testAccSiteVPNConnectionConfig_largeBandwidth_TGW(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d + ip_address = "198.51.100.1" + type = "ipsec.1" + + tags = { + Name = %[1]q + } +} + +resource "aws_ec2_transit_gateway" "test" { + description = %[1]q +} + +resource "aws_vpn_connection" "test" { + customer_gateway_id = aws_customer_gateway.test.id + transit_gateway_id = aws_ec2_transit_gateway.test.id + tunnel_bandwidth = "large" + type = "ipsec.1" +} +`, rName, rBgpAsn) +} + +func testAccSiteVPNConnectionConfig_largeBandwidth_WithoutTGWorVGW(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_customer_gateway" "test" { + bgp_asn = %[2]d + ip_address = "198.51.100.2" + type = "ipsec.1" + + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_connection" "test" { + customer_gateway_id = aws_customer_gateway.test.id + tunnel_bandwidth = "large" + type = "ipsec.1" +} +`, rName, rBgpAsn) +} diff --git a/internal/service/ecr/authorization_token_data_source.go b/internal/service/ecr/authorization_token_data_source.go index a935695ccf55..0c601365cf12 100644 --- a/internal/service/ecr/authorization_token_data_source.go +++ b/internal/service/ecr/authorization_token_data_source.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -68,7 +68,7 @@ func dataSourceAuthorizationTokenRead(ctx context.Context, d *schema.ResourceDat authorizationToken := aws.ToString(authorizationData.AuthorizationToken) expiresAt := aws.ToTime(authorizationData.ExpiresAt).Format(time.RFC3339) proxyEndpoint := aws.ToString(authorizationData.ProxyEndpoint) - authBytes, err := itypes.Base64Decode(authorizationToken) + authBytes, err := inttypes.Base64Decode(authorizationToken) if err != nil { d.SetId("") return sdkdiag.AppendErrorf(diags, "decoding ECR authorization token: %s", err) diff --git a/internal/service/ecr/authorization_token_ephemeral.go b/internal/service/ecr/authorization_token_ephemeral.go new file mode 100644 index 000000000000..343985cec543 --- /dev/null +++ b/internal/service/ecr/authorization_token_ephemeral.go @@ -0,0 +1,113 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ecr + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecr" + "github.com/hashicorp/terraform-plugin-framework/ephemeral" + "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/smerr" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @EphemeralResource(aws_ecr_authorization_token, name="AuthorizationToken") +func newAuthorizationTokenEphemeralResource(_ context.Context) (ephemeral.EphemeralResourceWithConfigure, error) { + return &authorizationTokenEphemeralResource{}, nil +} + +type authorizationTokenEphemeralResource struct { + framework.EphemeralResourceWithModel[authorizationTokenEphemeralResourceModel] +} + +func (e *authorizationTokenEphemeralResource) Schema(ctx context.Context, _ ephemeral.SchemaRequest, response *ephemeral.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "authorization_token": schema.StringAttribute{ + Computed: true, + Sensitive: true, + }, + "expires_at": schema.StringAttribute{ + Computed: true, + }, + names.AttrPassword: schema.StringAttribute{ + Computed: true, + Sensitive: true, + }, + "proxy_endpoint": schema.StringAttribute{ + Computed: true, + }, + names.AttrUserName: schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +func (e *authorizationTokenEphemeralResource) Open(ctx context.Context, request ephemeral.OpenRequest, response *ephemeral.OpenResponse) { + conn := e.Meta().ECRClient(ctx) + data := authorizationTokenEphemeralResourceModel{} + + smerr.AddEnrich(ctx, &response.Diagnostics, request.Config.Get(ctx, &data)) + if response.Diagnostics.HasError() { + return + } + + input := ecr.GetAuthorizationTokenInput{} + + out, err := conn.GetAuthorizationToken(ctx, &input) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err) + return + } + + if len(out.AuthorizationData) == 0 { + smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("no authorization data returned")) + return + } + + authorizationData := out.AuthorizationData[0] + authorizationToken := aws.ToString(authorizationData.AuthorizationToken) + expiresAt := aws.ToTime(authorizationData.ExpiresAt).Format(time.RFC3339) + proxyEndpoint := aws.ToString(authorizationData.ProxyEndpoint) + authBytes, err := inttypes.Base64Decode(authorizationToken) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("decoding ECR authorization token: %w", err)) + return + } + + basicAuthorization := strings.Split(string(authBytes), ":") + if len(basicAuthorization) != 2 { + smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("unknown ECR authorization token format")) + return + } + + userName := basicAuthorization[0] + password := basicAuthorization[1] + + data.AuthorizationToken = types.StringValue(authorizationToken) + data.ProxyEndpoint = types.StringValue(proxyEndpoint) + data.ExpiresAt = types.StringValue(expiresAt) + data.UserName = types.StringValue(userName) + data.Password = types.StringValue(password) + + smerr.AddEnrich(ctx, &response.Diagnostics, response.Result.Set(ctx, &data)) +} + +type authorizationTokenEphemeralResourceModel struct { + framework.WithRegionModel + AuthorizationToken types.String `tfsdk:"authorization_token"` + ExpiresAt types.String `tfsdk:"expires_at"` + Password types.String `tfsdk:"password"` + ProxyEndpoint types.String `tfsdk:"proxy_endpoint"` + UserName types.String `tfsdk:"user_name"` +} diff --git a/internal/service/ecr/authorization_token_ephemeral_test.go b/internal/service/ecr/authorization_token_ephemeral_test.go new file mode 100644 index 000000000000..b4ee0ad99a4c --- /dev/null +++ b/internal/service/ecr/authorization_token_ephemeral_test.go @@ -0,0 +1,53 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ecr_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccECRAuthorizationTokenEphemeral_basic(t *testing.T) { + ctx := acctest.Context(t) + echoResourceName := "echo.test" + dataPath := tfjsonpath.New("data") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECRServiceID), + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_10_0), + }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories(ctx, acctest.ProviderNameEcho), + CheckDestroy: acctest.CheckDestroyNoop, + Steps: []resource.TestStep{ + { + Config: testAccAuthorizationTokenEphemeralResourceConfig_basic(), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("authorization_token"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("proxy_endpoint"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("expires_at"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey(names.AttrUserName), knownvalue.NotNull()), + statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey(names.AttrPassword), knownvalue.NotNull()), + }, + }, + }, + }) +} + +func testAccAuthorizationTokenEphemeralResourceConfig_basic() string { + return acctest.ConfigCompose( + acctest.ConfigWithEchoProvider("ephemeral.aws_ecr_authorization_token.test"), + ` +ephemeral "aws_ecr_authorization_token" "test" {} +`) +} diff --git a/internal/service/ecr/service_package_gen.go b/internal/service/ecr/service_package_gen.go index 51a11009b9c7..683531a1889b 100644 --- a/internal/service/ecr/service_package_gen.go +++ b/internal/service/ecr/service_package_gen.go @@ -17,6 +17,17 @@ import ( type servicePackage struct{} +func (p *servicePackage) EphemeralResources(ctx context.Context) []*inttypes.ServicePackageEphemeralResource { + return []*inttypes.ServicePackageEphemeralResource{ + { + Factory: newAuthorizationTokenEphemeralResource, + TypeName: "aws_ecr_authorization_token", + Name: "AuthorizationToken", + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } +} + func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.ServicePackageFrameworkDataSource { return []*inttypes.ServicePackageFrameworkDataSource{ { diff --git a/internal/service/ecrpublic/authorization_token_data_source.go b/internal/service/ecrpublic/authorization_token_data_source.go index 19fc27a25a6c..fcbaf2dd200b 100644 --- a/internal/service/ecrpublic/authorization_token_data_source.go +++ b/internal/service/ecrpublic/authorization_token_data_source.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -60,7 +60,7 @@ func dataSourceAuthorizationTokenRead(ctx context.Context, d *schema.ResourceDat authorizationData := out.AuthorizationData authorizationToken := aws.ToString(authorizationData.AuthorizationToken) expiresAt := aws.ToTime(authorizationData.ExpiresAt).Format(time.RFC3339) - authBytes, err := itypes.Base64Decode(authorizationToken) + authBytes, err := inttypes.Base64Decode(authorizationToken) if err != nil { return sdkdiag.AppendErrorf(diags, "decoding ECR Public authorization token: %s", err) diff --git a/internal/service/ecrpublic/repository.go b/internal/service/ecrpublic/repository.go index b76a38103662..4c2990c71089 100644 --- a/internal/service/ecrpublic/repository.go +++ b/internal/service/ecrpublic/repository.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -352,7 +352,7 @@ func expandRepositoryCatalogData(tfMap map[string]any) *awstypes.RepositoryCatal } if v, ok := tfMap["logo_image_blob"].(string); ok && len(v) > 0 { - repositoryCatalogDataInput.LogoImageBlob = itypes.MustBase64Decode(v) + repositoryCatalogDataInput.LogoImageBlob = inttypes.MustBase64Decode(v) } if v, ok := tfMap["operating_systems"].(*schema.Set); ok { diff --git a/internal/service/ecs/container_definitions.go b/internal/service/ecs/container_definitions.go index 344b860d84da..9dbd5e4a9378 100644 --- a/internal/service/ecs/container_definitions.go +++ b/internal/service/ecs/container_definitions.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/enum" tfjson "github.com/hashicorp/terraform-provider-aws/internal/json" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" ) func containerDefinitionsAreEquivalent(def1, def2 string, isAWSVPC bool) (bool, error) { @@ -192,7 +192,7 @@ func compactArray[S ~[]E, E any](s S) S { } return tfslices.Filter(s, func(e E) bool { - return !itypes.IsZero(&e) + return !inttypes.IsZero(&e) }) } @@ -221,7 +221,7 @@ func expandContainerDefinitions(tfString string) ([]awstypes.ContainerDefinition } for i, apiObject := range apiObjects { - if itypes.IsZero(&apiObject) { + if inttypes.IsZero(&apiObject) { return nil, fmt.Errorf("invalid container definition supplied at index (%d)", i) } if !isValidVersionConsistency(apiObject) { diff --git a/internal/service/ecs/service.go b/internal/service/ecs/service.go index 7af6037fac96..bdd71882a55c 100644 --- a/internal/service/ecs/service.go +++ b/internal/service/ecs/service.go @@ -629,6 +629,50 @@ func resourceService() *schema.Resource { Computed: true, ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 1440), }, + "linear_configuration": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "step_bake_time_in_minutes": { + Type: nullable.TypeNullableInt, + Optional: true, + Computed: true, + ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 1440), + }, + "step_percent": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + ValidateFunc: validation.FloatBetween(3.0, 100.0), + }, + }, + }, + }, + "canary_configuration": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "canary_bake_time_in_minutes": { + Type: nullable.TypeNullableInt, + Optional: true, + Computed: true, + ValidateFunc: nullable.ValidateTypeStringNullableIntBetween(0, 1440), + }, + "canary_percent": { + Type: schema.TypeFloat, + Optional: true, + Computed: true, + ValidateFunc: validation.FloatBetween(0.1, 100.0), + }, + }, + }, + }, "lifecycle_hook": { Type: schema.TypeSet, Optional: true, @@ -1346,18 +1390,44 @@ func resourceServiceCreate(ctx context.Context, d *schema.ResourceData, meta any if strategy, ok := config["strategy"].(string); ok && strategy != "" { input.DeploymentConfiguration.Strategy = awstypes.DeploymentStrategy(strategy) - if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyBlueGreen { - if v, ok := config["bake_time_in_minutes"].(string); ok { - bakeTime := nullable.Int(v) - if !bakeTime.IsNull() { - value, _, err := bakeTime.ValueInt32() + if v, ok := config["bake_time_in_minutes"].(string); ok { + bt, err := expandBakeTimeInMinutes(v) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + input.DeploymentConfiguration.BakeTimeInMinutes = bt + } + + if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyLinear { + if v, ok := config["linear_configuration"].([]any); ok && len(v) > 0 { + if linearConfig, ok := v[0].(map[string]any); ok { + sp, sbtm, err := expandLinearConfiguration(linearConfig) if err != nil { return sdkdiag.AppendFromErr(diags, err) } - input.DeploymentConfiguration.BakeTimeInMinutes = aws.Int32(value) + input.DeploymentConfiguration.LinearConfiguration = &awstypes.LinearConfiguration{ + StepPercent: sp, + StepBakeTimeInMinutes: sbtm, + } } } } + + if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyCanary { + if v, ok := config["canary_configuration"].([]any); ok && len(v) > 0 { + if canaryConfig, ok := v[0].(map[string]any); ok { + cp, cbtm, err := expandCanaryConfiguration(canaryConfig) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + input.DeploymentConfiguration.CanaryConfiguration = &awstypes.CanaryConfiguration{ + CanaryPercent: cp, + CanaryBakeTimeInMinutes: cbtm, + } + } + } + } + if hooks := config["lifecycle_hook"].(*schema.Set).List(); len(hooks) > 0 { input.DeploymentConfiguration.LifecycleHooks = expandLifecycleHooks(hooks) } @@ -1646,15 +1716,40 @@ func resourceServiceUpdate(ctx context.Context, d *schema.ResourceData, meta any if strategy, ok := config["strategy"].(string); ok && strategy != "" { input.DeploymentConfiguration.Strategy = awstypes.DeploymentStrategy(strategy) - if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyBlueGreen { - if v, ok := config["bake_time_in_minutes"].(string); ok { - bakeTime := nullable.Int(v) - if !bakeTime.IsNull() { - value, _, err := bakeTime.ValueInt32() + if v, ok := config["bake_time_in_minutes"].(string); ok { + bt, err := expandBakeTimeInMinutes(v) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + input.DeploymentConfiguration.BakeTimeInMinutes = bt + } + + if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyLinear { + if v, ok := config["linear_configuration"].([]any); ok && len(v) > 0 { + if linearConfig, ok := v[0].(map[string]any); ok { + sp, sbtm, err := expandLinearConfiguration(linearConfig) if err != nil { return sdkdiag.AppendFromErr(diags, err) } - input.DeploymentConfiguration.BakeTimeInMinutes = aws.Int32(value) + input.DeploymentConfiguration.LinearConfiguration = &awstypes.LinearConfiguration{ + StepPercent: sp, + StepBakeTimeInMinutes: sbtm, + } + } + } + } + + if awstypes.DeploymentStrategy(strategy) == awstypes.DeploymentStrategyCanary { + if v, ok := config["canary_configuration"].([]any); ok && len(v) > 0 { + if canaryConfig, ok := v[0].(map[string]any); ok { + cp, cbtm, err := expandCanaryConfiguration(canaryConfig) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + input.DeploymentConfiguration.CanaryConfiguration = &awstypes.CanaryConfiguration{ + CanaryPercent: cp, + CanaryBakeTimeInMinutes: cbtm, + } } } } @@ -2539,6 +2634,14 @@ func flattenDeploymentConfiguration(apiObject *awstypes.DeploymentConfiguration) tfMap["bake_time_in_minutes"] = flex.Int32ToStringValue(v) } + if v := apiObject.CanaryConfiguration; v != nil { + tfMap["canary_configuration"] = flattenCanaryConfiguration(v) + } + + if v := apiObject.LinearConfiguration; v != nil { + tfMap["linear_configuration"] = flattenLinearConfiguration(v) + } + if v := apiObject.LifecycleHooks; len(v) > 0 { tfMap["lifecycle_hook"] = flattenLifecycleHooks(v) } @@ -2592,6 +2695,30 @@ func flattenLifecycleHooks(apiObjects []awstypes.DeploymentLifecycleHook) []any return tfList } +func flattenCanaryConfiguration(apiObject *awstypes.CanaryConfiguration) []map[string]any { + tfMap := map[string]any{} + + if v := apiObject.CanaryBakeTimeInMinutes; v != nil { + tfMap["canary_bake_time_in_minutes"] = flex.Int32ToStringValue(v) + } + + tfMap["canary_percent"] = aws.ToFloat64(apiObject.CanaryPercent) + + return []map[string]any{tfMap} +} + +func flattenLinearConfiguration(apiObject *awstypes.LinearConfiguration) []map[string]any { + tfMap := map[string]any{} + + if v := apiObject.StepBakeTimeInMinutes; v != nil { + tfMap["step_bake_time_in_minutes"] = flex.Int32ToStringValue(v) + } + + tfMap["step_percent"] = aws.ToFloat64(apiObject.StepPercent) + + return []map[string]any{tfMap} +} + func expandLifecycleHooks(tfList []any) []awstypes.DeploymentLifecycleHook { apiObject := make([]awstypes.DeploymentLifecycleHook, 0, len(tfList)) @@ -2635,6 +2762,63 @@ func expandLifecycleHooks(tfList []any) []awstypes.DeploymentLifecycleHook { return apiObject } +func expandBakeTimeInMinutes(bakeTimeStr string) (*int32, error) { + var ptrBakeTimeRet *int32 + + bakeTime := nullable.Int(bakeTimeStr) + if !bakeTime.IsNull() { + value, _, err := bakeTime.ValueInt32() + if err != nil { + return nil, err + } + ptrBakeTimeRet = aws.Int32(value) + } + + return ptrBakeTimeRet, nil +} + +func expandCanaryConfiguration(canaryConfig map[string]any) (*float64, *int32, error) { + var canaryPercentRet *float64 + var ptrCanaryBakeTimeRet *int32 + + if cp, ok := canaryConfig["canary_percent"].(float64); ok { + canaryPercentRet = aws.Float64(cp) + } else { + return nil, nil, fmt.Errorf("canary_percent is required for canary deployment configuration") + } + if cbtm, ok := canaryConfig["canary_bake_time_in_minutes"].(string); ok { + canaryBakeTimeInMinutes := nullable.Int(cbtm) + value, _, err := canaryBakeTimeInMinutes.ValueInt32() + if err != nil { + return nil, nil, err + } + ptrCanaryBakeTimeRet = aws.Int32(value) + } + + return canaryPercentRet, ptrCanaryBakeTimeRet, nil +} + +func expandLinearConfiguration(linearConfig map[string]any) (*float64, *int32, error) { + var stepPercentRet *float64 + var ptrStepBakeTimeRet *int32 + + if sp, ok := linearConfig["step_percent"].(float64); ok { + stepPercentRet = aws.Float64(sp) + } else { + return nil, nil, fmt.Errorf("step_percent is required for linear deployment configuration") + } + if sbtm, ok := linearConfig["step_bake_time_in_minutes"].(string); ok { + stepBakeTimeInMinutes := nullable.Int(sbtm) + value, _, err := stepBakeTimeInMinutes.ValueInt32() + if err != nil { + return nil, nil, err + } + ptrStepBakeTimeRet = aws.Int32(value) + } + + return stepPercentRet, ptrStepBakeTimeRet, nil +} + func flattenNetworkConfiguration(nc *awstypes.NetworkConfiguration) []any { if nc == nil { return nil diff --git a/internal/service/ecs/service_data_source.go b/internal/service/ecs/service_data_source.go index a996df9271ed..4d81f36a0da3 100644 --- a/internal/service/ecs/service_data_source.go +++ b/internal/service/ecs/service_data_source.go @@ -5,12 +5,15 @@ package ecs import ( "context" + "time" "github.com/aws/aws-sdk-go-v2/aws" + awstypes "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" @@ -31,18 +34,274 @@ func dataSourceService() *schema.Resource { Type: schema.TypeString, Computed: true, }, + names.AttrCapacityProviderStrategy: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "base": { + Type: schema.TypeInt, + Computed: true, + }, + "capacity_provider": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrWeight: { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, "cluster_arn": { Type: schema.TypeString, Required: true, }, + names.AttrCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + "created_by": { + Type: schema.TypeString, + Computed: true, + }, + "deployment_configuration": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarms": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarm_names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "enable": { + Type: schema.TypeBool, + Computed: true, + }, + "rollback": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "bake_time_in_minutes": { + Type: schema.TypeString, + Computed: true, + }, + "canary_configuration": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "canary_bake_time_in_minutes": { + Type: schema.TypeString, + Computed: true, + }, + "canary_percent": { + Type: schema.TypeFloat, + Computed: true, + }, + }, + }, + }, + "deployment_circuit_breaker": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable": { + Type: schema.TypeBool, + Computed: true, + }, + "rollback": { + Type: schema.TypeBool, + Computed: true, + }, + }, + }, + }, + "linear_configuration": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "step_bake_time_in_minutes": { + Type: schema.TypeString, + Computed: true, + }, + "step_percent": { + Type: schema.TypeFloat, + Computed: true, + }, + }, + }, + }, + "lifecycle_hook": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hook_details": { + Type: schema.TypeString, + Computed: true, + }, + "hook_target_arn": { + Type: schema.TypeString, + Computed: true, + }, + "lifecycle_stages": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "maximum_percent": { + Type: schema.TypeInt, + Computed: true, + }, + "minimum_healthy_percent": { + Type: schema.TypeInt, + Computed: true, + }, + "strategy": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "deployment_controller": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrType: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "deployments": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + "desired_count": { + Type: schema.TypeInt, + Computed: true, + }, + names.AttrID: { + Type: schema.TypeString, + Computed: true, + }, + "pending_count": { + Type: schema.TypeInt, + Computed: true, + }, + "running_count": { + Type: schema.TypeInt, + Computed: true, + }, + names.AttrStatus: { + Type: schema.TypeString, + Computed: true, + }, + "task_definition": { + Type: schema.TypeString, + Computed: true, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "desired_count": { Type: schema.TypeInt, Computed: true, }, + "enable_ecs_managed_tags": { + Type: schema.TypeBool, + Computed: true, + }, + "enable_execute_command": { + Type: schema.TypeBool, + Computed: true, + }, + "events": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrID: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrMessage: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "health_check_grace_period_seconds": { + Type: schema.TypeInt, + Computed: true, + }, + "iam_role": { + Type: schema.TypeString, + Computed: true, + }, "launch_type": { Type: schema.TypeString, Computed: true, }, + names.AttrNetworkConfiguration: { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "assign_public_ip": { + Type: schema.TypeBool, + Computed: true, + }, + names.AttrSecurityGroups: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + names.AttrSubnets: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, "load_balancer": { Type: schema.TypeSet, Computed: true, @@ -91,10 +350,90 @@ func dataSourceService() *schema.Resource { }, }, }, + "ordered_placement_strategy": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrField: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrType: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "placement_constraints": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrExpression: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrType: { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "platform_version": { + Type: schema.TypeString, + Computed: true, + }, + "pending_count": { + Type: schema.TypeInt, + Computed: true, + }, + "platform_family": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrPropagateTags: { + Type: schema.TypeString, + Computed: true, + }, + "running_count": { + Type: schema.TypeInt, + Computed: true, + }, "scheduling_strategy": { Type: schema.TypeString, Computed: true, }, + "service_registries": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "container_name": { + Type: schema.TypeString, + Computed: true, + }, + "container_port": { + Type: schema.TypeInt, + Computed: true, + }, + names.AttrPort: { + Type: schema.TypeInt, + Computed: true, + }, + "registry_arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + names.AttrStatus: { + Type: schema.TypeString, + Computed: true, + }, names.AttrServiceName: { Type: schema.TypeString, Required: true, @@ -103,6 +442,50 @@ func dataSourceService() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "task_sets": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrARN: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrCreatedAt: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrID: { + Type: schema.TypeString, + Computed: true, + }, + "pending_count": { + Type: schema.TypeInt, + Computed: true, + }, + "running_count": { + Type: schema.TypeInt, + Computed: true, + }, + "stability_status": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrStatus: { + Type: schema.TypeString, + Computed: true, + }, + "task_definition": { + Type: schema.TypeString, + Computed: true, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, names.AttrTags: tftags.TagsSchemaComputed(), }, } @@ -122,19 +505,205 @@ func dataSourceServiceRead(ctx context.Context, d *schema.ResourceData, meta any d.SetId(arn) d.Set(names.AttrARN, arn) d.Set("availability_zone_rebalancing", service.AvailabilityZoneRebalancing) + if err := d.Set(names.AttrCapacityProviderStrategy, flattenCapacityProviderStrategyItems(service.CapacityProviderStrategy)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting capacity_provider_strategy: %s", err) + } d.Set("cluster_arn", service.ClusterArn) + if service.CreatedAt != nil { + d.Set(names.AttrCreatedAt, service.CreatedAt.Format(time.RFC3339)) + } + d.Set("created_by", service.CreatedBy) + if service.DeploymentConfiguration != nil { + if err := d.Set("deployment_configuration", flattenDeploymentConfigurationForDataSource(service.DeploymentConfiguration)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting deployment_configuration: %s", err) + } + } + if err := d.Set("deployment_controller", flattenDeploymentController(service.DeploymentController)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting deployment_controller: %s", err) + } + if err := d.Set("deployments", flattenDeployments(service.Deployments)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting deployments: %s", err) + } d.Set("desired_count", service.DesiredCount) + d.Set("enable_ecs_managed_tags", service.EnableECSManagedTags) + d.Set("enable_execute_command", service.EnableExecuteCommand) + if err := d.Set("events", flattenServiceEvents(service.Events)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting events: %s", err) + } + d.Set("health_check_grace_period_seconds", service.HealthCheckGracePeriodSeconds) + d.Set("iam_role", service.RoleArn) d.Set("launch_type", service.LaunchType) if service.LoadBalancers != nil { if err := d.Set("load_balancer", flattenServiceLoadBalancers(service.LoadBalancers)); err != nil { return sdkdiag.AppendErrorf(diags, "setting load_balancer: %s", err) } } + if err := d.Set(names.AttrNetworkConfiguration, flattenNetworkConfiguration(service.NetworkConfiguration)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting network_configuration: %s", err) + } + if err := d.Set("ordered_placement_strategy", flattenPlacementStrategy(service.PlacementStrategy)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting ordered_placement_strategy: %s", err) + } + if err := d.Set("placement_constraints", flattenServicePlacementConstraints(service.PlacementConstraints)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting placement_constraints: %s", err) + } + d.Set("platform_version", service.PlatformVersion) + d.Set("pending_count", service.PendingCount) + d.Set("platform_family", service.PlatformFamily) + d.Set(names.AttrPropagateTags, service.PropagateTags) + d.Set("running_count", service.RunningCount) d.Set("scheduling_strategy", service.SchedulingStrategy) + if err := d.Set("service_registries", flattenServiceRegistries(service.ServiceRegistries)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting service_registries: %s", err) + } + d.Set(names.AttrStatus, service.Status) d.Set(names.AttrServiceName, service.ServiceName) d.Set("task_definition", service.TaskDefinition) + if err := d.Set("task_sets", flattenTaskSets(service.TaskSets)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting task_sets: %s", err) + } setTagsOut(ctx, service.Tags) return diags } + +// flattenDeploymentConfigurationForDataSource flattens DeploymentConfiguration for the data source +// which includes all fields from the API, unlike the resource which has some fields at the top level +func flattenDeploymentConfigurationForDataSource(apiObject *awstypes.DeploymentConfiguration) []map[string]any { + if apiObject == nil { + return nil + } + + tfMap := map[string]any{} + + if v := apiObject.Alarms; v != nil { + tfMap["alarms"] = []map[string]any{flattenAlarmsForDataSource(v)} + } + + if v := apiObject.BakeTimeInMinutes; v != nil { + tfMap["bake_time_in_minutes"] = flex.Int32ToStringValue(v) + } + + if v := apiObject.CanaryConfiguration; v != nil { + tfMap["canary_configuration"] = flattenCanaryConfiguration(v) + } + + if v := apiObject.DeploymentCircuitBreaker; v != nil { + tfMap["deployment_circuit_breaker"] = []map[string]any{flattenDeploymentCircuitBreakerForDataSource(v)} + } + + if v := apiObject.LinearConfiguration; v != nil { + tfMap["linear_configuration"] = flattenLinearConfiguration(v) + } + + if v := apiObject.LifecycleHooks; len(v) > 0 { + tfMap["lifecycle_hook"] = flattenLifecycleHooks(v) + } + + if v := apiObject.MaximumPercent; v != nil { + tfMap["maximum_percent"] = aws.ToInt32(v) + } + + if v := apiObject.MinimumHealthyPercent; v != nil { + tfMap["minimum_healthy_percent"] = aws.ToInt32(v) + } + + if v := apiObject.Strategy; v != "" { + tfMap["strategy"] = string(v) + } + + return []map[string]any{tfMap} +} + +func flattenAlarmsForDataSource(apiObject *awstypes.DeploymentAlarms) map[string]any { + tfMap := map[string]any{ + "enable": apiObject.Enable, + "rollback": apiObject.Rollback, + } + + if v := apiObject.AlarmNames; len(v) > 0 { + tfMap["alarm_names"] = v + } + + return tfMap +} + +func flattenDeploymentCircuitBreakerForDataSource(apiObject *awstypes.DeploymentCircuitBreaker) map[string]any { + return map[string]any{ + "enable": apiObject.Enable, + "rollback": apiObject.Rollback, + } +} + +func flattenDeployments(apiObjects []awstypes.Deployment) []map[string]any { + if len(apiObjects) == 0 { + return nil + } + + var tfList []map[string]any + for _, apiObject := range apiObjects { + tfMap := map[string]any{ + "desired_count": apiObject.DesiredCount, + names.AttrID: aws.ToString(apiObject.Id), + "pending_count": apiObject.PendingCount, + "running_count": apiObject.RunningCount, + names.AttrStatus: aws.ToString(apiObject.Status), + "task_definition": aws.ToString(apiObject.TaskDefinition), + } + if apiObject.CreatedAt != nil { + tfMap[names.AttrCreatedAt] = apiObject.CreatedAt.Format(time.RFC3339) + } + if apiObject.UpdatedAt != nil { + tfMap["updated_at"] = apiObject.UpdatedAt.Format(time.RFC3339) + } + tfList = append(tfList, tfMap) + } + return tfList +} + +func flattenServiceEvents(apiObjects []awstypes.ServiceEvent) []map[string]any { + if len(apiObjects) == 0 { + return nil + } + + var tfList []map[string]any + for _, apiObject := range apiObjects { + tfMap := map[string]any{ + names.AttrID: aws.ToString(apiObject.Id), + names.AttrMessage: aws.ToString(apiObject.Message), + } + if apiObject.CreatedAt != nil { + tfMap[names.AttrCreatedAt] = apiObject.CreatedAt.Format(time.RFC3339) + } + tfList = append(tfList, tfMap) + } + return tfList +} + +func flattenTaskSets(apiObjects []awstypes.TaskSet) []map[string]any { + if len(apiObjects) == 0 { + return nil + } + + var tfList []map[string]any + for _, apiObject := range apiObjects { + tfMap := map[string]any{ + names.AttrARN: aws.ToString(apiObject.TaskSetArn), + names.AttrID: aws.ToString(apiObject.Id), + "pending_count": apiObject.PendingCount, + "running_count": apiObject.RunningCount, + "stability_status": string(apiObject.StabilityStatus), + names.AttrStatus: aws.ToString(apiObject.Status), + "task_definition": aws.ToString(apiObject.TaskDefinition), + } + if apiObject.CreatedAt != nil { + tfMap[names.AttrCreatedAt] = apiObject.CreatedAt.Format(time.RFC3339) + } + if apiObject.UpdatedAt != nil { + tfMap["updated_at"] = apiObject.UpdatedAt.Format(time.RFC3339) + } + tfList = append(tfList, tfMap) + } + return tfList +} diff --git a/internal/service/ecs/service_data_source_test.go b/internal/service/ecs/service_data_source_test.go index a3e4c009ed58..ebbed094f795 100644 --- a/internal/service/ecs/service_data_source_test.go +++ b/internal/service/ecs/service_data_source_test.go @@ -71,6 +71,102 @@ func TestAccECSServiceDataSource_loadBalancer(t *testing.T) { }) } +func TestAccECSServiceDataSource_deploymentConfiguration(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_ecs_service.test" + resourceName := "aws_ecs_service.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccServiceDataSourceConfig_linearDeployment(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, names.AttrID, dataSourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.#", dataSourceName, "deployment_configuration.#"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.strategy", dataSourceName, "deployment_configuration.0.strategy"), + resource.TestCheckResourceAttr(dataSourceName, "deployment_configuration.0.strategy", "LINEAR"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.bake_time_in_minutes", dataSourceName, "deployment_configuration.0.bake_time_in_minutes"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.linear_configuration.#", dataSourceName, "deployment_configuration.0.linear_configuration.#"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.linear_configuration.0.step_percent", dataSourceName, "deployment_configuration.0.linear_configuration.0.step_percent"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.linear_configuration.0.step_bake_time_in_minutes", dataSourceName, "deployment_configuration.0.linear_configuration.0.step_bake_time_in_minutes"), + // Resource has these at top level, data source has them in deployment_configuration + resource.TestCheckResourceAttrPair(resourceName, "deployment_maximum_percent", dataSourceName, "deployment_configuration.0.maximum_percent"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_minimum_healthy_percent", dataSourceName, "deployment_configuration.0.minimum_healthy_percent"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_circuit_breaker.#", dataSourceName, "deployment_configuration.0.deployment_circuit_breaker.#"), + resource.TestCheckResourceAttrSet(dataSourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttrSet(dataSourceName, "created_by"), + resource.TestCheckResourceAttrSet(dataSourceName, "pending_count"), + resource.TestCheckResourceAttrSet(dataSourceName, "running_count"), + resource.TestCheckResourceAttrSet(dataSourceName, names.AttrStatus), + ), + }, + }, + }) +} + +func TestAccECSServiceDataSource_canaryDeployment(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_ecs_service.test" + resourceName := "aws_ecs_service.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccServiceDataSourceConfig_canaryDeployment(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, names.AttrID, dataSourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.#", dataSourceName, "deployment_configuration.#"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.strategy", dataSourceName, "deployment_configuration.0.strategy"), + resource.TestCheckResourceAttr(dataSourceName, "deployment_configuration.0.strategy", "CANARY"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.bake_time_in_minutes", dataSourceName, "deployment_configuration.0.bake_time_in_minutes"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.canary_configuration.#", dataSourceName, "deployment_configuration.0.canary_configuration.#"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.canary_configuration.0.canary_percent", dataSourceName, "deployment_configuration.0.canary_configuration.0.canary_percent"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_configuration.0.canary_configuration.0.canary_bake_time_in_minutes", dataSourceName, "deployment_configuration.0.canary_configuration.0.canary_bake_time_in_minutes"), + ), + }, + }, + }) +} + +func TestAccECSServiceDataSource_fullConfiguration(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_ecs_service.test" + resourceName := "aws_ecs_service.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccServiceDataSourceConfig_fullConfiguration(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, names.AttrID, dataSourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(resourceName, "deployment_controller.#", dataSourceName, "deployment_controller.#"), + resource.TestCheckResourceAttrPair(resourceName, "enable_ecs_managed_tags", dataSourceName, "enable_ecs_managed_tags"), + resource.TestCheckResourceAttrPair(resourceName, "platform_version", dataSourceName, "platform_version"), + resource.TestCheckResourceAttrPair(resourceName, names.AttrPropagateTags, dataSourceName, names.AttrPropagateTags), + // Resource has these at top level, data source has them in deployment_configuration + resource.TestCheckResourceAttrPair(resourceName, "deployment_maximum_percent", dataSourceName, "deployment_configuration.0.maximum_percent"), + resource.TestCheckResourceAttrPair(resourceName, "deployment_minimum_healthy_percent", dataSourceName, "deployment_configuration.0.minimum_healthy_percent"), + resource.TestCheckResourceAttrSet(dataSourceName, "deployments.#"), + resource.TestCheckResourceAttrSet(dataSourceName, "events.#"), + resource.TestCheckResourceAttrSet(dataSourceName, "platform_family"), + ), + }, + }, + }) +} + func testAccServiceDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "test" { @@ -121,3 +217,63 @@ data "aws_ecs_service" "test" { } `) } + +func testAccServiceDataSourceConfig_linearDeployment(rName string) string { + return acctest.ConfigCompose( + testAccServiceConfig_linearDeployment_basic(rName, false), + ` +data "aws_ecs_service" "test" { + service_name = aws_ecs_service.test.name + cluster_arn = aws_ecs_cluster.main.arn +} +`) +} + +func testAccServiceDataSourceConfig_canaryDeployment(rName string) string { + return acctest.ConfigCompose( + testAccServiceConfig_canaryDeployment_basic(rName, false), + ` +data "aws_ecs_service" "test" { + service_name = aws_ecs_service.test.name + cluster_arn = aws_ecs_cluster.main.arn +} +`) +} + +func testAccServiceDataSourceConfig_fullConfiguration(rName string) string { + return acctest.ConfigCompose(testAccServiceConfig_launchTypeFargateBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.test.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + launch_type = "FARGATE" + platform_version = "LATEST" + + enable_ecs_managed_tags = true + propagate_tags = "SERVICE" + + deployment_maximum_percent = 200 + deployment_minimum_healthy_percent = 100 + + deployment_controller { + type = "ECS" + } + + network_configuration { + security_groups = aws_security_group.test[*].id + subnets = aws_subnet.test[*].id + assign_public_ip = true + } + + tags = { + Name = %[1]q + } +} + +data "aws_ecs_service" "test" { + service_name = aws_ecs_service.test.name + cluster_arn = aws_ecs_cluster.test.arn +} +`, rName)) +} diff --git a/internal/service/ecs/service_test.go b/internal/service/ecs/service_test.go index 6da4125b1eea..3e02b6e41be5 100644 --- a/internal/service/ecs/service_test.go +++ b/internal/service/ecs/service_test.go @@ -2781,6 +2781,416 @@ func TestAccECSService_AvailabilityZoneRebalancing(t *testing.T) { }) } +// Linear and Canary Deployment Strategy Tests + +func TestAccECSService_LinearDeployment_basic(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.bake_time_in_minutes", "2"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.linear_configuration.0.step_percent", "50"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.linear_configuration.0.step_bake_time_in_minutes", "1"), + ), + }, + { + Config: testAccServiceConfig_linearDeployment_updated(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.bake_time_in_minutes", "3"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.linear_configuration.0.step_percent", "25"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.linear_configuration.0.step_bake_time_in_minutes", "2"), + ), + }, + }, + }) +} + +func TestAccECSService_LinearDeployment_outOfBandRemoval(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + testAccCheckServiceRemoveLinearDeploymentConfigurations(ctx, &service), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccServiceConfig_linearDeployment_basic(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + ), + }, + }, + }) +} + +func TestAccECSService_LinearDeployment_createFailure(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_withFailure(rName, true), + ExpectError: regexache.MustCompile(`No rollback candidate was found`), + }, + }, + }) +} + +func TestAccECSService_LinearDeployment_changeStrategy(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_zeroBakeTime(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + ), + }, + { + Config: testAccServiceConfig_linearDeployment_switchToRolling(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "ROLLING"), + ), + }, + { + Config: testAccServiceConfig_linearDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + ), + }, + }, + }) +} + +func TestAccECSService_LinearDeployment_updateFailure(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + ), + }, + { + Config: testAccServiceConfig_linearDeployment_withFailure(rName, true), + ExpectError: regexache.MustCompile(`Service deployment rolled back`), + }, + }, + }) +} + +func TestAccECSService_LinearDeployment_updateInPlace(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + resource.TestCheckResourceAttr(resourceName, "desired_count", "1"), + ), + }, + { + Config: testAccServiceConfig_linearDeployment_zeroBakeTime(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + resource.TestCheckResourceAttr(resourceName, "desired_count", "2"), + ), + }, + }, + }) +} + +func TestAccECSService_LinearDeployment_waitServiceActive(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_linearDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "LINEAR"), + ), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_basic(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.bake_time_in_minutes", "2"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.canary_configuration.0.canary_percent", "20"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.canary_configuration.0.canary_bake_time_in_minutes", "1"), + ), + }, + { + Config: testAccServiceConfig_canaryDeployment_updated(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.bake_time_in_minutes", "3"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.canary_configuration.0.canary_percent", "10"), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.canary_configuration.0.canary_bake_time_in_minutes", "2"), + ), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_outOfBandRemoval(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + testAccCheckServiceRemoveCanaryDeploymentConfigurations(ctx, &service), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + ), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_createFailure(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_withFailure(rName, true), + ExpectError: regexache.MustCompile(`No rollback candidate was found`), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_changeStrategy(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_zeroBakeTime(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + ), + }, + { + Config: testAccServiceConfig_canaryDeployment_switchToRolling(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "ROLLING"), + ), + }, + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + ), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_updateFailure(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + ), + }, + { + Config: testAccServiceConfig_canaryDeployment_withFailure(rName, true), + ExpectError: regexache.MustCompile(`Service deployment rolled back`), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_updateInPlace(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + resource.TestCheckResourceAttr(resourceName, "desired_count", "1"), + ), + }, + { + Config: testAccServiceConfig_canaryDeployment_zeroBakeTime(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + resource.TestCheckResourceAttr(resourceName, "desired_count", "2"), + ), + }, + }, + }) +} + +func TestAccECSService_CanaryDeployment_waitServiceActive(t *testing.T) { + ctx := acctest.Context(t) + var service awstypes.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)[:16] + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ECSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServiceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServiceConfig_canaryDeployment_basic(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(ctx, resourceName, &service), + resource.TestCheckResourceAttr(resourceName, "deployment_configuration.0.strategy", "CANARY"), + ), + }, + }, + }) +} + func testAccCheckServiceDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).ECSClient(ctx) @@ -2881,6 +3291,40 @@ func testAccCheckServiceRemoveBlueGreenDeploymentConfigurations(ctx context.Cont } } +func testAccCheckServiceRemoveLinearDeploymentConfigurations(ctx context.Context, service *awstypes.Service) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ECSClient(ctx) + + input := &ecs.UpdateServiceInput{ + Cluster: service.ClusterArn, + Service: service.ServiceArn, + DeploymentConfiguration: &awstypes.DeploymentConfiguration{ + Strategy: awstypes.DeploymentStrategyRolling, + }, + } + + _, err := conn.UpdateService(ctx, input) + return err + } +} + +func testAccCheckServiceRemoveCanaryDeploymentConfigurations(ctx context.Context, service *awstypes.Service) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ECSClient(ctx) + + input := &ecs.UpdateServiceInput{ + Cluster: service.ClusterArn, + Service: service.ServiceArn, + DeploymentConfiguration: &awstypes.DeploymentConfiguration{ + Strategy: awstypes.DeploymentStrategyRolling, + }, + } + + _, err := conn.UpdateService(ctx, input) + return err + } +} + func testAccServiceConfig_basic(rName, clusterName string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "test" { @@ -3254,215 +3698,480 @@ resource "aws_security_group" "alb" { } } -resource "aws_lb" "main" { - name = %[1]q - internal = false - load_balancer_type = "application" - security_groups = [aws_security_group.alb.id] - subnets = aws_subnet.test[*].id +resource "aws_lb" "main" { + name = %[1]q + internal = false + load_balancer_type = "application" + security_groups = [aws_security_group.alb.id] + subnets = aws_subnet.test[*].id + + enable_deletion_protection = false + + tags = { + Name = "%[1]s-alb" + } +} + +resource "aws_lb_target_group" "primary" { + name = "%[1]s-prim" + port = 80 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + target_type = "ip" + + health_check { + path = "/" + healthy_threshold = 2 + unhealthy_threshold = 5 + timeout = 5 + interval = 30 + } +} + +resource "aws_lb_target_group" "alternate" { + name = "%[1]s-alt" + port = 80 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + target_type = "ip" + + health_check { + path = "/" + healthy_threshold = 2 + unhealthy_threshold = 5 + timeout = 5 + interval = 30 + } +} + +resource "aws_lb_listener" "http" { + load_balancer_arn = aws_lb.main.arn + port = "80" + protocol = "HTTP" + + default_action { + type = "fixed-response" + + fixed_response { + content_type = "text/plain" + message_body = "404: Page not found" + status_code = 404 + } + } +} + +resource "aws_lb_listener_rule" "production" { + listener_arn = aws_lb_listener.http.arn + priority = 1 + + action { + type = "forward" + forward { + dynamic "target_group" { + for_each = { + primary = aws_lb_target_group.primary.arn + alternate = aws_lb_target_group.alternate.arn + } + content { + arn = target_group.value + weight = target_group.key == "primary" ? 100 : 0 + } + } + } + } + + condition { + path_pattern { + values = ["/*"] + } + } + + lifecycle { + ignore_changes = [ + action[0].forward[0].target_group + ] + } +} + +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.http.arn + priority = 2 # Make sure this is different from the production rule priority + + action { + type = "forward" + forward { + target_group { + arn = aws_lb_target_group.alternate.arn + weight = 100 + } + } + } + + condition { + path_pattern { + values = ["/*"] + } + } + + lifecycle { + ignore_changes = [ + action[0].forward[0].target_group + ] + } +} + +resource "aws_iam_role" "global" { + name = "%[1]s-global" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = [ + "lambda.amazonaws.com", + "ecs-tasks.amazonaws.com", + "elasticloadbalancing.amazonaws.com", + "ecs.amazonaws.com", + ] + } + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "global_admin_attach" { + role = aws_iam_role.global.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AdministratorAccess" +} + +resource "aws_iam_role_policy" "ecs_elb_permissions" { + name = "${aws_iam_role.global.name}-elb-permissions" + role = aws_iam_role.global.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "elasticloadbalancing:DeregisterTargets", + "elasticloadbalancing:RegisterTargets" + ] + Resource = "*" + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "ecs_service_role" { + role = aws_iam_role.global.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole" +} + +resource "aws_iam_role" "lambda_role" { + name = "%[1]s-hook-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "lambda.amazonaws.com" + } + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "lambda_basic_execution" { + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + role = aws_iam_role.lambda_role.name +} + +resource "aws_service_discovery_http_namespace" "test" { + name = %[1]q +} - enable_deletion_protection = false +resource "aws_ecs_cluster" "main" { + name = %[1]q - tags = { - Name = "%[1]s-alb" + service_connect_defaults { + namespace = aws_service_discovery_http_namespace.test.arn } } -resource "aws_lb_target_group" "primary" { - name = "%[1]s-prim" - port = 80 - protocol = "HTTP" - vpc_id = aws_vpc.test.id - target_type = "ip" - - health_check { - path = "/" - healthy_threshold = 2 - unhealthy_threshold = 5 - timeout = 5 - interval = 30 +resource "aws_ecs_task_definition" "test" { + family = %[1]q + requires_compatibilities = ["FARGATE"] + network_mode = "awsvpc" + cpu = 256 + memory = 512 + lifecycle { + create_before_destroy = true } + + container_definitions = jsonencode([ + { + name = "test" + image = "nginx:latest" + cpu = 256 + memory = 512 + essential = true + environment = [ + { + name = "test_name" + value = "test_val" + } + ] + portMappings = [ + { + containerPort = 80 + hostPort = 80 + protocol = "tcp" + name = "http" + appProtocol = "http" + } + ] + } + ]) } -resource "aws_lb_target_group" "alternate" { - name = "%[1]s-alt" - port = 80 - protocol = "HTTP" - vpc_id = aws_vpc.test.id - target_type = "ip" +resource "aws_lambda_function" "hook_success" { + filename = "test-fixtures/success_lambda_func.zip" + function_name = "%[1]s-hook-success" + role = aws_iam_role.lambda_role.arn + handler = "index.handler" + runtime = "nodejs20.x" + source_code_hash = filebase64sha256("test-fixtures/success_lambda_func.zip") +} - health_check { - path = "/" - healthy_threshold = 2 - unhealthy_threshold = 5 - timeout = 5 - interval = 30 - } +resource "aws_lambda_function" "hook_failure" { + filename = "test-fixtures/failure_lambda_func.zip" + function_name = "%[1]s-hook-failure" + role = aws_iam_role.lambda_role.arn + handler = "index.handler" + runtime = "nodejs20.x" + source_code_hash = filebase64sha256("test-fixtures/failure_lambda_func.zip") +} +`, rName)) } -resource "aws_lb_listener" "http" { - load_balancer_arn = aws_lb.main.arn - port = "80" - protocol = "HTTP" +func testAccServiceConfig_blueGreenDeployment_basic(rName string, waitSteadyState bool) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + launch_type = "FARGATE" - default_action { - type = "fixed-response" + deployment_configuration { + strategy = "BLUE_GREEN" + bake_time_in_minutes = 2 - fixed_response { - content_type = "text/plain" - message_body = "404: Page not found" - status_code = 404 + lifecycle_hook { + hook_target_arn = aws_lambda_function.hook_success.arn + role_arn = aws_iam_role.global.arn + lifecycle_stages = ["POST_SCALE_UP", "POST_TEST_TRAFFIC_SHIFT"] + hook_details = jsonencode([1, "2", true]) + } + + lifecycle_hook { + hook_target_arn = aws_lambda_function.hook_success.arn + role_arn = aws_iam_role.global.arn + lifecycle_stages = ["TEST_TRAFFIC_SHIFT", "POST_PRODUCTION_TRAFFIC_SHIFT"] + hook_details = "3.14" } } -} -resource "aws_lb_listener_rule" "production" { - listener_arn = aws_lb_listener.http.arn - priority = 1 + service_connect_configuration { + enabled = true + namespace = aws_service_discovery_http_namespace.test.arn - action { - type = "forward" - forward { - dynamic "target_group" { - for_each = { - primary = aws_lb_target_group.primary.arn - alternate = aws_lb_target_group.alternate.arn - } - content { - arn = target_group.value - weight = target_group.key == "primary" ? 100 : 0 + service { + client_alias { + dns_name = "test-service.local" + port = 8080 + + test_traffic_rules { + header { + name = "x-test-header" + value { + exact = "test-value" + } + } } } + discovery_name = "test-service" + port_name = "http" } } - condition { - path_pattern { - values = ["/*"] + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } + + load_balancer { + target_group_arn = aws_lb_target_group.primary.arn + container_name = "test" + container_port = 80 + + advanced_configuration { + alternate_target_group_arn = aws_lb_target_group.alternate.arn + production_listener_rule = aws_lb_listener_rule.production.arn + test_listener_rule = aws_lb_listener_rule.test.arn + role_arn = aws_iam_role.global.arn } } + wait_for_steady_state = %[2]t + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, waitSteadyState)) +} + +func testAccServiceConfig_blueGreenDeployment_withCircuitBreaker(rName string) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_task_definition" "should_fail" { + family = "%[1]s-should-fail" + requires_compatibilities = ["FARGATE"] + network_mode = "awsvpc" + cpu = 256 + memory = 512 lifecycle { - ignore_changes = [ - action[0].forward[0].target_group - ] + create_before_destroy = true } + + container_definitions = jsonencode([ + { + name = "should_fail" + image = "nginx:latest" + cpu = 256 + memory = 512 + essential = true, + command = [ + "/bin/sh -c \"while true; do /bin/date > /var/www/my-vol/date; sleep 1; done\"" + ] + environment = [ + { + name = "test_name" + value = "test_val" + } + ] + portMappings = [ + { + containerPort = 80 + hostPort = 80 + protocol = "tcp" + name = "http" + appProtocol = "http" + } + ] + } + ]) } -resource "aws_lb_listener_rule" "test" { - listener_arn = aws_lb_listener.http.arn - priority = 2 # Make sure this is different from the production rule priority - action { - type = "forward" - forward { - target_group { - arn = aws_lb_target_group.alternate.arn - weight = 100 - } - } - } +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.should_fail.arn + desired_count = 1 + launch_type = "FARGATE" - condition { - path_pattern { - values = ["/*"] + deployment_configuration { + strategy = "BLUE_GREEN" + bake_time_in_minutes = 1 + + lifecycle_hook { + hook_target_arn = aws_lambda_function.hook_success.arn + role_arn = aws_iam_role.global.arn + lifecycle_stages = ["PRE_SCALE_UP"] } } - lifecycle { - ignore_changes = [ - action[0].forward[0].target_group - ] + deployment_circuit_breaker { + enable = true + rollback = true } -} -resource "aws_iam_role" "global" { - name = "%[1]s-global" + service_connect_configuration { + enabled = true + namespace = aws_service_discovery_http_namespace.test.arn - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = [ - "lambda.amazonaws.com", - "ecs-tasks.amazonaws.com", - "elasticloadbalancing.amazonaws.com", - "ecs.amazonaws.com", - ] + service { + client_alias { + dns_name = "test-service.local" + port = 8080 + + test_traffic_rules { + header { + name = "x-test-header-2" + value { + exact = "test-value-2" + } + } } } - ] - }) -} - -resource "aws_iam_role_policy_attachment" "global_admin_attach" { - role = aws_iam_role.global.name - policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AdministratorAccess" -} - -resource "aws_iam_role_policy" "ecs_elb_permissions" { - name = "${aws_iam_role.global.name}-elb-permissions" - role = aws_iam_role.global.id + discovery_name = "test-service" + port_name = "http" + } + } - policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Effect = "Allow" - Action = [ - "elasticloadbalancing:DeregisterTargets", - "elasticloadbalancing:RegisterTargets" - ] - Resource = "*" - } - ] - }) -} + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } -resource "aws_iam_role_policy_attachment" "ecs_service_role" { - role = aws_iam_role.global.name - policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole" -} + load_balancer { + target_group_arn = aws_lb_target_group.primary.arn + container_name = "should_fail" + container_port = 80 -resource "aws_iam_role" "lambda_role" { - name = "%[1]s-hook-role" + advanced_configuration { + alternate_target_group_arn = aws_lb_target_group.alternate.arn + production_listener_rule = aws_lb_listener_rule.production.arn + test_listener_rule = aws_lb_listener_rule.test.arn + role_arn = aws_iam_role.global.arn + } + } - assume_role_policy = jsonencode({ - Version = "2012-10-17" - Statement = [ - { - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = "lambda.amazonaws.com" - } - } - ] - }) -} + wait_for_steady_state = true -resource "aws_iam_role_policy_attachment" "lambda_basic_execution" { - policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - role = aws_iam_role.lambda_role.name + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] } - -resource "aws_service_discovery_http_namespace" "test" { - name = %[1]q +`, rName)) } -resource "aws_ecs_cluster" "main" { - name = %[1]q +func testAccServiceConfig_blueGreenDeployment_withHookBehavior(rName string, shouldFail bool) string { + var hookTargetArn string + if shouldFail { + hookTargetArn = "aws_lambda_function.hook_failure.arn" + } else { + hookTargetArn = "aws_lambda_function.hook_success.arn" + } - service_connect_defaults { - namespace = aws_service_discovery_http_namespace.test.arn - } -} + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` -resource "aws_ecs_task_definition" "test" { - family = %[1]q +resource "aws_ecs_task_definition" "test2" { + family = "%[1]s-test2" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 256 @@ -3480,8 +4189,8 @@ resource "aws_ecs_task_definition" "test" { essential = true environment = [ { - name = "test_name" - value = "test_val" + name = "test_name_2" + value = "test_val_2" } ] portMappings = [ @@ -3492,56 +4201,179 @@ resource "aws_ecs_task_definition" "test" { name = "http" appProtocol = "http" } - ] + ] + } + ]) +} + +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test2.arn + desired_count = 1 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "BLUE_GREEN" + bake_time_in_minutes = 3 + + lifecycle_hook { + hook_target_arn = %[2]s + role_arn = aws_iam_role.global.arn + lifecycle_stages = ["PRE_SCALE_UP"] + hook_details = jsonencode({ "bool_key" : true, "string_key" : "string_val", "int_key" : 10, "list_key" : [1, "2", true], "object_key" : { + "bool_key" : true, + "string_key" : "string_val", + "int_key" : 10, + "list_key" : [1, "2", true] + } }) + } + } + + service_connect_configuration { + enabled = true + namespace = aws_service_discovery_http_namespace.test.arn + + service { + client_alias { + dns_name = "test-service.local" + port = 8080 + + test_traffic_rules { + header { + name = "x-test-header-2" + value { + exact = "test-value-2" + } + } + } + } + discovery_name = "test-service" + port_name = "http" + } + } + + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } + + load_balancer { + target_group_arn = aws_lb_target_group.primary.arn + container_name = "test" + container_port = 80 + + advanced_configuration { + alternate_target_group_arn = aws_lb_target_group.alternate.arn + production_listener_rule = aws_lb_listener_rule.production.arn + test_listener_rule = aws_lb_listener_rule.test.arn + role_arn = aws_iam_role.global.arn + } + } + + sigint_rollback = true + wait_for_steady_state = true + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, hookTargetArn)) +} + +func testAccServiceConfig_blueGreenDeployment_switchToRolling(rName string) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "ROLLING" + + lifecycle_hook { + hook_target_arn = aws_lambda_function.hook_success.arn + role_arn = aws_iam_role.global.arn + lifecycle_stages = ["PRE_SCALE_UP"] + } + } + + service_connect_configuration { + enabled = true + namespace = aws_service_discovery_http_namespace.test.arn + + service { + client_alias { + dns_name = "test-service.local" + port = 8080 + + test_traffic_rules { + header { + name = "x-test-header" + value { + exact = "test-value" + } + } + } + } + discovery_name = "test-service" + port_name = "http" } - ]) -} + } -resource "aws_lambda_function" "hook_success" { - filename = "test-fixtures/success_lambda_func.zip" - function_name = "%[1]s-hook-success" - role = aws_iam_role.lambda_role.arn - handler = "index.handler" - runtime = "nodejs20.x" - source_code_hash = filebase64sha256("test-fixtures/success_lambda_func.zip") -} + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } -resource "aws_lambda_function" "hook_failure" { - filename = "test-fixtures/failure_lambda_func.zip" - function_name = "%[1]s-hook-failure" - role = aws_iam_role.lambda_role.arn - handler = "index.handler" - runtime = "nodejs20.x" - source_code_hash = filebase64sha256("test-fixtures/failure_lambda_func.zip") + load_balancer { + target_group_arn = aws_lb_target_group.alternate.arn + container_name = "test" + container_port = 80 + } + + wait_for_steady_state = true + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] } `, rName)) } -func testAccServiceConfig_blueGreenDeployment_basic(rName string, waitSteadyState bool) string { +func testAccServiceConfig_blueGreenDeployment_zeroBakeTime(rName string, waitSteadyState bool) string { return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` resource "aws_ecs_service" "test" { name = %[1]q cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.test.arn - desired_count = 1 + desired_count = 2 launch_type = "FARGATE" deployment_configuration { strategy = "BLUE_GREEN" - bake_time_in_minutes = 2 + bake_time_in_minutes = 0 lifecycle_hook { hook_target_arn = aws_lambda_function.hook_success.arn role_arn = aws_iam_role.global.arn lifecycle_stages = ["POST_SCALE_UP", "POST_TEST_TRAFFIC_SHIFT"] - hook_details = jsonencode([1, "2", true]) + hook_details = "true" } lifecycle_hook { hook_target_arn = aws_lambda_function.hook_success.arn role_arn = aws_iam_role.global.arn lifecycle_stages = ["TEST_TRAFFIC_SHIFT", "POST_PRODUCTION_TRAFFIC_SHIFT"] - hook_details = "3.14" + hook_details = jsonencode("Test string") } } @@ -3598,69 +4430,30 @@ resource "aws_ecs_service" "test" { `, rName, waitSteadyState)) } -func testAccServiceConfig_blueGreenDeployment_withCircuitBreaker(rName string) string { +func testAccServiceConfig_blueGreenDeployment_withoutTestListenerRule(rName string, waitSteadyState bool) string { return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` -resource "aws_ecs_task_definition" "should_fail" { - family = "%[1]s-should-fail" - requires_compatibilities = ["FARGATE"] - network_mode = "awsvpc" - cpu = 256 - memory = 512 - lifecycle { - create_before_destroy = true - } - - container_definitions = jsonencode([ - { - name = "should_fail" - image = "nginx:latest" - cpu = 256 - memory = 512 - essential = true, - command = [ - "/bin/sh -c \"while true; do /bin/date > /var/www/my-vol/date; sleep 1; done\"" - ] - environment = [ - { - name = "test_name" - value = "test_val" - } - ] - portMappings = [ - { - containerPort = 80 - hostPort = 80 - protocol = "tcp" - name = "http" - appProtocol = "http" - } - ] - } - ]) -} - - resource "aws_ecs_service" "test" { name = %[1]q cluster = aws_ecs_cluster.main.id - task_definition = aws_ecs_task_definition.should_fail.arn + task_definition = aws_ecs_task_definition.test.arn desired_count = 1 launch_type = "FARGATE" deployment_configuration { strategy = "BLUE_GREEN" - bake_time_in_minutes = 1 + bake_time_in_minutes = 2 lifecycle_hook { hook_target_arn = aws_lambda_function.hook_success.arn role_arn = aws_iam_role.global.arn - lifecycle_stages = ["PRE_SCALE_UP"] + lifecycle_stages = ["POST_SCALE_UP", "POST_TEST_TRAFFIC_SHIFT"] } - } - deployment_circuit_breaker { - enable = true - rollback = true + lifecycle_hook { + hook_target_arn = aws_lambda_function.hook_success.arn + role_arn = aws_iam_role.global.arn + lifecycle_stages = ["TEST_TRAFFIC_SHIFT", "POST_PRODUCTION_TRAFFIC_SHIFT"] + } } service_connect_configuration { @@ -3674,9 +4467,9 @@ resource "aws_ecs_service" "test" { test_traffic_rules { header { - name = "x-test-header-2" + name = "x-test-header" value { - exact = "test-value-2" + exact = "test-value" } } } @@ -3694,18 +4487,153 @@ resource "aws_ecs_service" "test" { load_balancer { target_group_arn = aws_lb_target_group.primary.arn - container_name = "should_fail" + container_name = "test" container_port = 80 advanced_configuration { alternate_target_group_arn = aws_lb_target_group.alternate.arn production_listener_rule = aws_lb_listener_rule.production.arn - test_listener_rule = aws_lb_listener_rule.test.arn role_arn = aws_iam_role.global.arn } } - wait_for_steady_state = true + wait_for_steady_state = %[2]t + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, waitSteadyState)) +} + +func testAccServiceConfig_linearDeployment_basic(rName string, waitSteadyState bool) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "LINEAR" + bake_time_in_minutes = 2 + + linear_configuration { + step_percent = 50 + step_bake_time_in_minutes = 1 + } + } + + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } + + wait_for_steady_state = %[2]t + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, waitSteadyState)) +} + +func testAccServiceConfig_linearDeployment_updated(rName string, waitSteadyState bool) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "LINEAR" + bake_time_in_minutes = 3 + + linear_configuration { + step_percent = 25 + step_bake_time_in_minutes = 2 + } + } + + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } + + wait_for_steady_state = %[2]t + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, waitSteadyState)) +} + +func testAccServiceConfig_linearDeployment_zeroBakeTime(rName string, waitSteadyState bool) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 2 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "LINEAR" + bake_time_in_minutes = 0 + + linear_configuration { + step_percent = 100 + step_bake_time_in_minutes = 0 + } + } + + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } + + wait_for_steady_state = %[2]t + + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, waitSteadyState)) +} + +func testAccServiceConfig_linearDeployment_switchToRolling(rName string) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 2 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "ROLLING" + } + + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } depends_on = [ aws_iam_role_policy_attachment.global_admin_attach, @@ -3716,46 +4644,32 @@ resource "aws_ecs_service" "test" { `, rName)) } -func testAccServiceConfig_blueGreenDeployment_withHookBehavior(rName string, shouldFail bool) string { - var hookTargetArn string +func testAccServiceConfig_linearDeployment_withFailure(rName string, shouldFail bool) string { + var taskDef string if shouldFail { - hookTargetArn = "aws_lambda_function.hook_failure.arn" + taskDef = "aws_ecs_task_definition.should_fail.arn" } else { - hookTargetArn = "aws_lambda_function.hook_success.arn" + taskDef = "aws_ecs_task_definition.test.arn" } return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` - -resource "aws_ecs_task_definition" "test2" { - family = "%[1]s-test2" - requires_compatibilities = ["FARGATE"] - network_mode = "awsvpc" - cpu = 256 - memory = 512 - lifecycle { - create_before_destroy = true - } +resource "aws_ecs_task_definition" "should_fail" { + family = "%[1]s-should-fail" + requires_compatibilities = ["FARGATE"] + network_mode = "awsvpc" + cpu = "256" + memory = "512" + execution_role_arn = aws_iam_role.global.arn container_definitions = jsonencode([ { name = "test" - image = "nginx:latest" - cpu = 256 - memory = 512 + image = "nginx:invalid-tag" essential = true - environment = [ - { - name = "test_name_2" - value = "test_val_2" - } - ] portMappings = [ { containerPort = 80 - hostPort = 80 protocol = "tcp" - name = "http" - appProtocol = "http" } ] } @@ -3765,48 +4679,23 @@ resource "aws_ecs_task_definition" "test2" { resource "aws_ecs_service" "test" { name = %[1]q cluster = aws_ecs_cluster.main.id - task_definition = aws_ecs_task_definition.test2.arn + task_definition = %[2]s desired_count = 1 launch_type = "FARGATE" deployment_configuration { - strategy = "BLUE_GREEN" - bake_time_in_minutes = 3 + strategy = "LINEAR" + bake_time_in_minutes = 1 - lifecycle_hook { - hook_target_arn = %[2]s - role_arn = aws_iam_role.global.arn - lifecycle_stages = ["PRE_SCALE_UP"] - hook_details = jsonencode({ "bool_key" : true, "string_key" : "string_val", "int_key" : 10, "list_key" : [1, "2", true], "object_key" : { - "bool_key" : true, - "string_key" : "string_val", - "int_key" : 10, - "list_key" : [1, "2", true] - } }) + linear_configuration { + step_percent = 50 + step_bake_time_in_minutes = 1 } } - service_connect_configuration { - enabled = true - namespace = aws_service_discovery_http_namespace.test.arn - - service { - client_alias { - dns_name = "test-service.local" - port = 8080 - - test_traffic_rules { - header { - name = "x-test-header-2" - value { - exact = "test-value-2" - } - } - } - } - discovery_name = "test-service" - port_name = "http" - } + deployment_circuit_breaker { + enable = true + rollback = true } network_configuration { @@ -3828,7 +4717,6 @@ resource "aws_ecs_service" "test" { } } - sigint_rollback = true wait_for_steady_state = true depends_on = [ @@ -3837,10 +4725,10 @@ resource "aws_ecs_service" "test" { aws_iam_role_policy_attachment.ecs_service_role ] } -`, rName, hookTargetArn)) +`, rName, taskDef)) } -func testAccServiceConfig_blueGreenDeployment_switchToRolling(rName string) string { +func testAccServiceConfig_canaryDeployment_basic(rName string, waitSteadyState bool) string { return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` resource "aws_ecs_service" "test" { name = %[1]q @@ -3850,35 +4738,48 @@ resource "aws_ecs_service" "test" { launch_type = "FARGATE" deployment_configuration { - strategy = "ROLLING" + strategy = "CANARY" + bake_time_in_minutes = 2 - lifecycle_hook { - hook_target_arn = aws_lambda_function.hook_success.arn - role_arn = aws_iam_role.global.arn - lifecycle_stages = ["PRE_SCALE_UP"] + canary_configuration { + canary_percent = 20 + canary_bake_time_in_minutes = 1 } } - service_connect_configuration { - enabled = true - namespace = aws_service_discovery_http_namespace.test.arn + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true + } - service { - client_alias { - dns_name = "test-service.local" - port = 8080 + wait_for_steady_state = %[2]t - test_traffic_rules { - header { - name = "x-test-header" - value { - exact = "test-value" - } - } - } - } - discovery_name = "test-service" - port_name = "http" + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName, waitSteadyState)) +} + +func testAccServiceConfig_canaryDeployment_updated(rName string, waitSteadyState bool) string { + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "CANARY" + bake_time_in_minutes = 3 + + canary_configuration { + canary_percent = 10 + canary_bake_time_in_minutes = 2 } } @@ -3888,13 +4789,7 @@ resource "aws_ecs_service" "test" { assign_public_ip = true } - load_balancer { - target_group_arn = aws_lb_target_group.alternate.arn - container_name = "test" - container_port = 80 - } - - wait_for_steady_state = true + wait_for_steady_state = %[2]t depends_on = [ aws_iam_role_policy_attachment.global_admin_attach, @@ -3902,10 +4797,10 @@ resource "aws_ecs_service" "test" { aws_iam_role_policy_attachment.ecs_service_role ] } -`, rName)) +`, rName, waitSteadyState)) } -func testAccServiceConfig_blueGreenDeployment_zeroBakeTime(rName string, waitSteadyState bool) string { +func testAccServiceConfig_canaryDeployment_zeroBakeTime(rName string, waitSteadyState bool) string { return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` resource "aws_ecs_service" "test" { name = %[1]q @@ -3915,44 +4810,12 @@ resource "aws_ecs_service" "test" { launch_type = "FARGATE" deployment_configuration { - strategy = "BLUE_GREEN" + strategy = "CANARY" bake_time_in_minutes = 0 - lifecycle_hook { - hook_target_arn = aws_lambda_function.hook_success.arn - role_arn = aws_iam_role.global.arn - lifecycle_stages = ["POST_SCALE_UP", "POST_TEST_TRAFFIC_SHIFT"] - hook_details = "true" - } - - lifecycle_hook { - hook_target_arn = aws_lambda_function.hook_success.arn - role_arn = aws_iam_role.global.arn - lifecycle_stages = ["TEST_TRAFFIC_SHIFT", "POST_PRODUCTION_TRAFFIC_SHIFT"] - hook_details = jsonencode("Test string") - } - } - - service_connect_configuration { - enabled = true - namespace = aws_service_discovery_http_namespace.test.arn - - service { - client_alias { - dns_name = "test-service.local" - port = 8080 - - test_traffic_rules { - header { - name = "x-test-header" - value { - exact = "test-value" - } - } - } - } - discovery_name = "test-service" - port_name = "http" + canary_configuration { + canary_percent = 100 + canary_bake_time_in_minutes = 0 } } @@ -3962,19 +4825,6 @@ resource "aws_ecs_service" "test" { assign_public_ip = true } - load_balancer { - target_group_arn = aws_lb_target_group.primary.arn - container_name = "test" - container_port = 80 - - advanced_configuration { - alternate_target_group_arn = aws_lb_target_group.alternate.arn - production_listener_rule = aws_lb_listener_rule.production.arn - test_listener_rule = aws_lb_listener_rule.test.arn - role_arn = aws_iam_role.global.arn - } - } - wait_for_steady_state = %[2]t depends_on = [ @@ -3986,55 +4836,88 @@ resource "aws_ecs_service" "test" { `, rName, waitSteadyState)) } -func testAccServiceConfig_blueGreenDeployment_withoutTestListenerRule(rName string, waitSteadyState bool) string { +func testAccServiceConfig_canaryDeployment_switchToRolling(rName string) string { return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` resource "aws_ecs_service" "test" { name = %[1]q cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.test.arn - desired_count = 1 + desired_count = 2 launch_type = "FARGATE" deployment_configuration { - strategy = "BLUE_GREEN" - bake_time_in_minutes = 2 - - lifecycle_hook { - hook_target_arn = aws_lambda_function.hook_success.arn - role_arn = aws_iam_role.global.arn - lifecycle_stages = ["POST_SCALE_UP", "POST_TEST_TRAFFIC_SHIFT"] - } + strategy = "ROLLING" + } - lifecycle_hook { - hook_target_arn = aws_lambda_function.hook_success.arn - role_arn = aws_iam_role.global.arn - lifecycle_stages = ["TEST_TRAFFIC_SHIFT", "POST_PRODUCTION_TRAFFIC_SHIFT"] - } + network_configuration { + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + assign_public_ip = true } - service_connect_configuration { - enabled = true - namespace = aws_service_discovery_http_namespace.test.arn + depends_on = [ + aws_iam_role_policy_attachment.global_admin_attach, + aws_iam_role_policy.ecs_elb_permissions, + aws_iam_role_policy_attachment.ecs_service_role + ] +} +`, rName)) +} - service { - client_alias { - dns_name = "test-service.local" - port = 8080 +func testAccServiceConfig_canaryDeployment_withFailure(rName string, shouldFail bool) string { + var taskDef string + if shouldFail { + taskDef = "aws_ecs_task_definition.should_fail.arn" + } else { + taskDef = "aws_ecs_task_definition.test.arn" + } - test_traffic_rules { - header { - name = "x-test-header" - value { - exact = "test-value" - } - } + return acctest.ConfigCompose(testAccServiceConfig_blueGreenDeploymentBase(rName), fmt.Sprintf(` +resource "aws_ecs_task_definition" "should_fail" { + family = "%[1]s-should-fail" + requires_compatibilities = ["FARGATE"] + network_mode = "awsvpc" + cpu = "256" + memory = "512" + execution_role_arn = aws_iam_role.global.arn + + container_definitions = jsonencode([ + { + name = "test" + image = "nginx:invalid-tag" + essential = true + portMappings = [ + { + containerPort = 80 + protocol = "tcp" } - } - discovery_name = "test-service" - port_name = "http" + ] + } + ]) +} + +resource "aws_ecs_service" "test" { + name = %[1]q + cluster = aws_ecs_cluster.main.id + task_definition = %[2]s + desired_count = 1 + launch_type = "FARGATE" + + deployment_configuration { + strategy = "CANARY" + bake_time_in_minutes = 1 + + canary_configuration { + canary_percent = 20 + canary_bake_time_in_minutes = 1 } } + deployment_circuit_breaker { + enable = true + rollback = true + } + network_configuration { security_groups = [aws_security_group.test.id] subnets = aws_subnet.test[*].id @@ -4049,11 +4932,12 @@ resource "aws_ecs_service" "test" { advanced_configuration { alternate_target_group_arn = aws_lb_target_group.alternate.arn production_listener_rule = aws_lb_listener_rule.production.arn + test_listener_rule = aws_lb_listener_rule.test.arn role_arn = aws_iam_role.global.arn } } - wait_for_steady_state = %[2]t + wait_for_steady_state = true depends_on = [ aws_iam_role_policy_attachment.global_admin_attach, @@ -4061,7 +4945,7 @@ resource "aws_ecs_service" "test" { aws_iam_role_policy_attachment.ecs_service_role ] } -`, rName, waitSteadyState)) +`, rName, taskDef)) } func testAccServiceConfig_deploymentConfiguration_strategy(rName string, strategy string) string { diff --git a/internal/service/elasticbeanstalk/configuration_template.go b/internal/service/elasticbeanstalk/configuration_template.go index d6ba3823c39d..e716753742a0 100644 --- a/internal/service/elasticbeanstalk/configuration_template.go +++ b/internal/service/elasticbeanstalk/configuration_template.go @@ -158,12 +158,44 @@ func resourceConfigurationTemplateUpdate(ctx context.Context, d *schema.Resource // conflict. Here we loop through all the initial removables from the set // difference, and we build up a slice of settings not found in the "add" // set + + defaultResourceName := func(ns *string) *string { + switch aws.ToString(ns) { + case "aws:autoscaling:asg": + return aws.String("AWSEBAutoScalingGroup") + case "aws:autoscaling:launchconfiguration": + return aws.String("AWSEBAutoScalingLaunchConfiguration") + default: + return nil + } + } + ensureResourceName := func(s *awstypes.ConfigurationOptionSetting) { + if s.ResourceName == nil || aws.ToString(s.ResourceName) == "" { + if rn := defaultResourceName(s.Namespace); rn != nil { + s.ResourceName = rn + } + } + } + + for i := range add { + ensureResourceName(&add[i]) + } + for i := range del { + ensureResourceName(&del[i]) + } + + key := func(ns, on, rn *string) string { + return aws.ToString(ns) + "|" + aws.ToString(on) + "|" + aws.ToString(rn) + } + + addKeys := make(map[string]struct{}, len(add)) + for _, a := range add { + addKeys[key(a.Namespace, a.OptionName, a.ResourceName)] = struct{}{} + } + var remove []awstypes.ConfigurationOptionSetting for _, r := range del { - for _, a := range add { - if aws.ToString(r.Namespace) == aws.ToString(a.Namespace) && aws.ToString(r.OptionName) == aws.ToString(a.OptionName) { - continue - } + if _, exists := addKeys[key(r.Namespace, r.OptionName, r.ResourceName)]; !exists { remove = append(remove, r) } } @@ -176,8 +208,9 @@ func resourceConfigurationTemplateUpdate(ctx context.Context, d *schema.Resource for _, v := range remove { input.OptionsToRemove = append(input.OptionsToRemove, awstypes.OptionSpecification{ - Namespace: v.Namespace, - OptionName: v.OptionName, + Namespace: v.Namespace, + OptionName: v.OptionName, + ResourceName: v.ResourceName, }) } diff --git a/internal/service/elbv2/const.go b/internal/service/elbv2/const.go index a536f3f2d40f..561d053315a3 100644 --- a/internal/service/elbv2/const.go +++ b/internal/service/elbv2/const.go @@ -201,8 +201,8 @@ const ( healthCheckPortTrafficPort = "traffic-port" ) -func healthCheckProtocolEnumValues() []string { - return enum.Slice( +func healthCheckProtocolEnumValues() []awstypes.ProtocolEnum { + return enum.EnumSlice( awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps, awstypes.ProtocolEnumTcp, diff --git a/internal/service/elbv2/listener.go b/internal/service/elbv2/listener.go index d8e20f9233a3..5f51b70a8dce 100644 --- a/internal/service/elbv2/listener.go +++ b/internal/service/elbv2/listener.go @@ -269,6 +269,53 @@ func resourceListener() *schema.Resource { }, }, }, + "jwt_validation": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: suppressIfActionTypeNot(awstypes.ActionTypeEnumJwtValidation), + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrIssuer: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "jwks_endpoint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "additional_claim": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrFormat: { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.JwtValidationActionAdditionalClaimFormatEnum](), + }, + names.AttrName: { + Type: schema.TypeString, + Required: true, + }, + names.AttrValues: { + Type: schema.TypeSet, + Required: true, + MaxItems: 10, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + }, + }, + }, + }, + }, + }, + }, "order": { Type: schema.TypeInt, Optional: true, @@ -1162,6 +1209,11 @@ func expandListenerAction(actionPath cty.Path, i int, tfMap map[string]any, diag if v, ok := tfMap["authenticate_oidc"].([]any); ok { action.AuthenticateOidcConfig = expandAuthenticateOIDCConfig(v) } + + case awstypes.ActionTypeEnumJwtValidation: + if v, ok := tfMap["jwt_validation"].([]any); ok && len(v) > 0 { + action.JwtValidationConfig = expandListenerActionJWTValidationConfig(v) + } } listenerActionRuntimeValidate(actionPath, tfMap, diags) @@ -1271,6 +1323,57 @@ func expandListenerFixedResponseConfig(l []any) *awstypes.FixedResponseActionCon return fr } +func expandListenerActionJWTValidationConfig(l []any) *awstypes.JwtValidationActionConfig { + if len(l) == 0 || l[0] == nil { + return nil + } + + tfMap, ok := l[0].(map[string]any) + + if !ok { + return nil + } + + jwt := &awstypes.JwtValidationActionConfig{ + Issuer: aws.String(tfMap[names.AttrIssuer].(string)), + JwksEndpoint: aws.String(tfMap["jwks_endpoint"].(string)), + } + + if v, ok := tfMap["additional_claim"].(*schema.Set); ok && v.Len() > 0 { + jwt.AdditionalClaims = expandJwtValidationActionAdditionalClaim(tfMap["additional_claim"].(*schema.Set).List()) + } + + return jwt +} + +func expandJwtValidationActionAdditionalClaim(l []any) []awstypes.JwtValidationActionAdditionalClaim { + if len(l) == 0 { + return nil + } + + var claims []awstypes.JwtValidationActionAdditionalClaim + + for _, tfMapRaw := range l { + tfMap, ok := tfMapRaw.(map[string]any) + if !ok { + continue + } + + claim := awstypes.JwtValidationActionAdditionalClaim{ + Format: awstypes.JwtValidationActionAdditionalClaimFormatEnum(tfMap[names.AttrFormat].(string)), + Name: aws.String(tfMap[names.AttrName].(string)), + } + + if v, ok := tfMap[names.AttrValues].(*schema.Set); ok && v.Len() > 0 { + claim.Values = flex.ExpandStringValueSet(v) + } + + claims = append(claims, claim) + } + + return claims +} + func expandListenerRedirectActionConfig(l []any) *awstypes.RedirectActionConfig { if len(l) == 0 || l[0] == nil { return nil @@ -1443,6 +1546,9 @@ func flattenListenerActions(d *schema.ResourceData, attrName string, apiObjects } tfMap["authenticate_oidc"] = flattenAuthenticateOIDCActionConfig(apiObject.AuthenticateOidcConfig, clientSecret) + + case awstypes.ActionTypeEnumJwtValidation: + tfMap["jwt_validation"] = flattenListenerActionJWTValidationConfig(apiObject.JwtValidationConfig) } tfList = append(tfList, tfMap) @@ -1688,6 +1794,41 @@ func flattenListenerActionForwardConfigTargetGroupStickinessConfig(config *awsty return []any{m} } +func flattenListenerActionJWTValidationConfig(apiObject *awstypes.JwtValidationActionConfig) []any { + if apiObject == nil { + return []any{} + } + + tfMap := map[string]any{ + names.AttrIssuer: apiObject.Issuer, + "jwks_endpoint": apiObject.JwksEndpoint, + } + if len(apiObject.AdditionalClaims) > 0 { + tfMap["additional_claim"] = flattenJwtValidationActionAdditionalClaims(apiObject.AdditionalClaims) + } + + return []any{tfMap} +} + +func flattenJwtValidationActionAdditionalClaims(claims []awstypes.JwtValidationActionAdditionalClaim) []any { + if len(claims) == 0 { + return []any{} + } + + var tfList []any + + for _, claim := range claims { + tfMap := map[string]any{ + names.AttrFormat: claim.Format, + names.AttrName: claim.Name, + names.AttrValues: flex.FlattenStringValueSet(claim.Values), + } + tfList = append(tfList, tfMap) + } + + return tfList +} + func flattenListenerActionRedirectConfig(apiObject *awstypes.RedirectActionConfig) []any { if apiObject == nil { return []any{} @@ -1870,6 +2011,15 @@ func listenerActionPlantimeValidate(actionPath cty.Path, action cty.Value, diags string(actionType), )) } + + case awstypes.ActionTypeEnumJwtValidation: + if jv := action.GetAttr("jwt_validation"); jv.IsNull() || jv.LengthInt() == 0 { + *diags = append(*diags, errs.NewAttributeRequiredWhenError( + actionPath.GetAttr("jwt_validation"), + actionPath.GetAttr(names.AttrType), + string(actionType), + )) + } } } } @@ -1927,6 +2077,16 @@ func listenerActionRuntimeValidate(actionPath cty.Path, action map[string]any, d } } + if v, ok := action["jwt_validation"].([]any); ok && len(v) > 0 { + if actionType != awstypes.ActionTypeEnumJwtValidation { + *diags = append(*diags, errs.NewAttributeConflictsWhenWillBeError( + actionPath.GetAttr("jwt_validation"), + actionPath.GetAttr(names.AttrType), + string(actionType), + )) + } + } + if v, ok := action["redirect"].([]any); ok && len(v) > 0 { if actionType != awstypes.ActionTypeEnumRedirect { *diags = append(*diags, errs.NewAttributeConflictsWhenWillBeError( diff --git a/internal/service/elbv2/listener_data_source.go b/internal/service/elbv2/listener_data_source.go index 40afcbf58630..9768da1d4709 100644 --- a/internal/service/elbv2/listener_data_source.go +++ b/internal/service/elbv2/listener_data_source.go @@ -206,6 +206,45 @@ func dataSourceListener() *schema.Resource { }, }, }, + "jwt_validation": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrIssuer: { + Type: schema.TypeString, + Computed: true, + }, + "jwks_endpoint": { + Type: schema.TypeString, + Computed: true, + }, + "additional_claim": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrFormat: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrName: { + Type: schema.TypeString, + Computed: true, + }, + names.AttrValues: { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, "order": { Type: schema.TypeInt, Computed: true, diff --git a/internal/service/elbv2/listener_rule.go b/internal/service/elbv2/listener_rule.go index 58f6918aa5d4..c73975ba954d 100644 --- a/internal/service/elbv2/listener_rule.go +++ b/internal/service/elbv2/listener_rule.go @@ -263,6 +263,53 @@ func resourceListenerRule() *schema.Resource { }, }, }, + "jwt_validation": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: suppressIfActionTypeNot(awstypes.ActionTypeEnumJwtValidation), + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrIssuer: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "jwks_endpoint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "additional_claim": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrFormat: { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.JwtValidationActionAdditionalClaimFormatEnum](), + }, + names.AttrName: { + Type: schema.TypeString, + Required: true, + }, + names.AttrValues: { + Type: schema.TypeSet, + Required: true, + MaxItems: 10, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + }, + }, + }, + }, + }, + }, + }, "order": { Type: schema.TypeInt, Optional: true, diff --git a/internal/service/elbv2/listener_rule_data_source.go b/internal/service/elbv2/listener_rule_data_source.go index a49ac76f511f..a88abcf0bdd0 100644 --- a/internal/service/elbv2/listener_rule_data_source.go +++ b/internal/service/elbv2/listener_rule_data_source.go @@ -188,6 +188,38 @@ func (d *listenerRuleDataSource) Schema(ctx context.Context, req datasource.Sche }, }, }, + "jwt_validation": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[jwtValidationConfigModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrIssuer: schema.StringAttribute{ + Computed: true, + }, + "jwks_endpoint": schema.StringAttribute{ + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "additional_claim": schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[additionalClaimsModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrFormat: schema.StringAttribute{ + Computed: true, + }, + names.AttrName: schema.StringAttribute{ + Computed: true, + }, + names.AttrValues: schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + }, + }, + }, + }, "redirect": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[redirectActionConfigModel](ctx), NestedObject: schema.NestedBlockObject{ @@ -453,6 +485,7 @@ type actionModel struct { AuthenticateOidcConfig fwtypes.ListNestedObjectValueOf[authenticateOIDCActionConfigModel] `tfsdk:"authenticate_oidc"` FixedResponseConfig fwtypes.ListNestedObjectValueOf[fixedResponseActionConfigModel] `tfsdk:"fixed_response"` ForwardConfig fwtypes.ListNestedObjectValueOf[forwardActionConfigModel] `tfsdk:"forward"` + JWTValidationConfig fwtypes.ListNestedObjectValueOf[jwtValidationConfigModel] `tfsdk:"jwt_validation"` Order types.Int32 `tfsdk:"order"` RedirectConfig fwtypes.ListNestedObjectValueOf[redirectActionConfigModel] `tfsdk:"redirect"` } @@ -571,3 +604,15 @@ type rewriteConfigModel struct { Regex types.String `tfsdk:"regex"` Replace types.String `tfsdk:"replace"` } + +type jwtValidationConfigModel struct { + Issuer types.String `tfsdk:"issuer"` + JwksEndpoint types.String `tfsdk:"jwks_endpoint"` + AdditionalClaims fwtypes.SetNestedObjectValueOf[additionalClaimsModel] `tfsdk:"additional_claim"` +} + +type additionalClaimsModel struct { + Format types.String `tfsdk:"format"` + Name types.String `tfsdk:"name"` + Values fwtypes.SetValueOf[types.String] `tfsdk:"values"` +} diff --git a/internal/service/elbv2/listener_rule_data_source_test.go b/internal/service/elbv2/listener_rule_data_source_test.go index b30adb5c2c68..454f39c2c672 100644 --- a/internal/service/elbv2/listener_rule_data_source_test.go +++ b/internal/service/elbv2/listener_rule_data_source_test.go @@ -51,6 +51,7 @@ func TestAccELBV2ListenerRuleDataSource_byARN(t *testing.T) { "authenticate_oidc": knownvalue.ListExact([]knownvalue.Check{}), "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), "forward": knownvalue.NotNull(), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.ListExact([]knownvalue.Check{}), names.AttrType: knownvalue.NotNull(), @@ -142,6 +143,7 @@ func TestAccELBV2ListenerRuleDataSource_byListenerAndPriority(t *testing.T) { "authenticate_oidc": knownvalue.ListExact([]knownvalue.Check{}), "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), "forward": knownvalue.NotNull(), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.ListExact([]knownvalue.Check{}), names.AttrType: knownvalue.NotNull(), @@ -234,6 +236,7 @@ func TestAccELBV2ListenerRuleDataSource_actionAuthenticateCognito(t *testing.T) "authenticate_oidc": knownvalue.ListExact([]knownvalue.Check{}), "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), "forward": knownvalue.ListExact([]knownvalue.Check{}), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.ListExact([]knownvalue.Check{}), names.AttrType: knownvalue.NotNull(), @@ -298,6 +301,7 @@ func TestAccELBV2ListenerRuleDataSource_actionAuthenticateOIDC(t *testing.T) { "authenticate_oidc": knownvalue.NotNull(), "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), "forward": knownvalue.ListExact([]knownvalue.Check{}), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.ListExact([]knownvalue.Check{}), names.AttrType: knownvalue.NotNull(), @@ -373,6 +377,98 @@ func TestAccELBV2ListenerRuleDataSource_actionAuthenticateOIDC(t *testing.T) { }) } +func TestAccELBV2ListenerRuleDataSource_actionAuthenticateJWTValidation(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var listenerRule awstypes.Rule + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + dataSourceName := "data.aws_lb_listener_rule.test" + resourceName := "aws_lb_listener_rule.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleDataSourceConfig_actionAuthenticateJWTValidation(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, dataSourceName, &listenerRule), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrARN, resourceName, names.AttrARN), + resource.TestCheckResourceAttrPair(dataSourceName, "listener_arn", resourceName, "listener_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrPriority, resourceName, names.AttrPriority), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "authenticate_cognito": knownvalue.ListExact([]knownvalue.Check{}), + "authenticate_oidc": knownvalue.NotNull(), + "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), + "forward": knownvalue.ListExact([]knownvalue.Check{}), + "jwt_validation": knownvalue.NotNull(), + "order": knownvalue.NotNull(), + "redirect": knownvalue.ListExact([]knownvalue.Check{}), + names.AttrType: knownvalue.NotNull(), + }), + knownvalue.NotNull(), + })), + + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("order"), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey(names.AttrType), + compare.ValuesSame(), + ), + + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0), knownvalue.NotNull()), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0).AtMapKey(names.AttrIssuer), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0).AtMapKey(names.AttrIssuer), + compare.ValuesSame(), + ), + statecheck.CompareValuePairs( + dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0).AtMapKey("jwks_endpoint"), + resourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0).AtMapKey("jwks_endpoint"), + compare.ValuesSame(), + ), + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0).AtMapKey("additional_claim"), knownvalue.NotNull()), + statecheck.ExpectKnownValue( + dataSourceName, + tfjsonpath.New(names.AttrAction).AtSliceIndex(0).AtMapKey("jwt_validation").AtSliceIndex(0).AtMapKey("additional_claim"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrFormat: knownvalue.StringExact("string-array"), + names.AttrName: knownvalue.StringExact("claim_name1"), + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact(acctest.CtValue1), + knownvalue.StringExact(acctest.CtValue2), + }), + }), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrFormat: knownvalue.StringExact("single-string"), + names.AttrName: knownvalue.StringExact("claim_name2"), + names.AttrValues: knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact(acctest.CtValue1), + }), + }), + }), + ), + }, + }, + }, + }) +} + func TestAccELBV2ListenerRuleDataSource_actionFixedResponse(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -405,6 +501,7 @@ func TestAccELBV2ListenerRuleDataSource_actionFixedResponse(t *testing.T) { "authenticate_oidc": knownvalue.ListExact([]knownvalue.Check{}), "fixed_response": knownvalue.NotNull(), "forward": knownvalue.ListExact([]knownvalue.Check{}), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.ListExact([]knownvalue.Check{}), names.AttrType: knownvalue.NotNull(), @@ -467,6 +564,7 @@ func TestAccELBV2ListenerRuleDataSource_actionForwardWeightedStickiness(t *testi "authenticate_oidc": knownvalue.ListExact([]knownvalue.Check{}), "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), "forward": knownvalue.NotNull(), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.ListExact([]knownvalue.Check{}), names.AttrType: knownvalue.NotNull(), @@ -536,6 +634,7 @@ func TestAccELBV2ListenerRuleDataSource_actionRedirect(t *testing.T) { "authenticate_oidc": knownvalue.ListExact([]knownvalue.Check{}), "fixed_response": knownvalue.ListExact([]knownvalue.Check{}), "forward": knownvalue.ListExact([]knownvalue.Check{}), + "jwt_validation": knownvalue.ListExact([]knownvalue.Check{}), "order": knownvalue.NotNull(), "redirect": knownvalue.NotNull(), names.AttrType: knownvalue.NotNull(), @@ -1164,6 +1263,55 @@ resource "aws_cognito_user_pool_domain" "test" { `, rName)) } +func testAccListenerRuleDataSourceConfig_actionAuthenticateJWTValidation(rName, key, certificate string) string { + return acctest.ConfigCompose( + testAccListenerRuleConfig_baseWithHTTPSListener(rName, key, certificate), + fmt.Sprintf(` +data "aws_lb_listener_rule" "test" { + arn = aws_lb_listener_rule.test.arn +} + +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "jwt-validation" + + jwt_validation { + issuer = "https://example.com" + jwks_endpoint = "https://example.com/.well-known/jwks.json" + additional_claim { + format = "string-array" + name = "claim_name1" + values = ["value1", "value2"] + } + additional_claim { + format = "single-string" + name = "claim_name2" + values = ["value1"] + } + } + } + + action { + type = "forward" + target_group_arn = aws_lb_target_group.test.arn + } + + condition { + path_pattern { + values = ["/static/*"] + } + } + + tags = { + Name = %[1]q + } +} +`, rName)) +} + func testAccListenerRuleDataSourceConfig_actionFixedResponse(rName string) string { return acctest.ConfigCompose(testAccListenerRuleConfig_baseWithHTTPListener(rName), ` data "aws_lb_listener_rule" "test" { diff --git a/internal/service/elbv2/listener_rule_test.go b/internal/service/elbv2/listener_rule_test.go index a5d9d3425a20..cf5e3b966a77 100644 --- a/internal/service/elbv2/listener_rule_test.go +++ b/internal/service/elbv2/listener_rule_test.go @@ -1278,6 +1278,57 @@ func TestAccELBV2ListenerRule_oidc(t *testing.T) { }) } +func TestAccELBV2ListenerRule_jwtValidation(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Rule + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lb_listener_rule.test" + listenerResourceName := "aws_lb_listener.test" + targetGroupResourceName := "aws_lb_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerRuleDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerRuleConfig_jwtValidation(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerRuleExists(ctx, resourceName, &conf), + acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "elasticloadbalancing", regexache.MustCompile(fmt.Sprintf(`listener-rule/app/%s/.+$`, rName))), + resource.TestCheckResourceAttrPair(resourceName, "listener_arn", listenerResourceName, names.AttrARN), + resource.TestCheckResourceAttr(resourceName, names.AttrPriority, "100"), + resource.TestCheckResourceAttr(resourceName, "action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.order", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.type", "jwt-validation"), + resource.TestCheckResourceAttr(resourceName, "action.0.jwt_validation.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.jwt_validation.0.issuer", "https://example.com"), + resource.TestCheckResourceAttr(resourceName, "action.0.jwt_validation.0.jwks_endpoint", "https://example.com/.well-known/jwks.json"), + resource.TestCheckResourceAttr(resourceName, "action.0.jwt_validation.0.additional_claim.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "action.0.jwt_validation.0.additional_claim.*", map[string]string{ + names.AttrFormat: "string-array", + names.AttrName: "claim_name1", + "values.#": "2", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "action.0.jwt_validation.0.additional_claim.*", map[string]string{ + names.AttrFormat: "single-string", + names.AttrName: "claim_name2", + "values.#": "1", + "values.0": acctest.CtValue1, + }), + resource.TestCheckResourceAttr(resourceName, "action.1.order", "2"), + resource.TestCheckResourceAttr(resourceName, "action.1.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "action.1.target_group_arn", targetGroupResourceName, names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "condition.#", "1"), + ), + }, + }, + }) +} + func TestAccELBV2ListenerRule_Action_defaultOrder(t *testing.T) { ctx := acctest.Context(t) var rule awstypes.Rule @@ -4002,6 +4053,68 @@ resource "aws_lb_listener" "test" { `, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } +func testAccListenerRuleConfig_jwtValidation(rName, key, certificate string) string { + return acctest.ConfigCompose(testAccListenerRuleConfig_base(rName), fmt.Sprintf(` +resource "aws_lb_listener_rule" "test" { + listener_arn = aws_lb_listener.test.arn + priority = 100 + + action { + type = "jwt-validation" + + jwt_validation { + issuer = "https://example.com" + jwks_endpoint = "https://example.com/.well-known/jwks.json" + additional_claim { + format = "string-array" + name = "claim_name1" + values = ["value1", "value2"] + } + additional_claim { + format = "single-string" + name = "claim_name2" + values = ["value1"] + } + } + } + + action { + type = "forward" + target_group_arn = aws_lb_target_group.test.arn + } + + condition { + path_pattern { + values = ["/static/*"] + } + } + + tags = { + Name = %[1]q + } +} + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) +} + func testAccListenerRuleConfig_action_defaultOrder(rName, key, certificate string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { diff --git a/internal/service/elbv2/listener_test.go b/internal/service/elbv2/listener_test.go index 475c5c2c1150..4ff27cd0efe4 100644 --- a/internal/service/elbv2/listener_test.go +++ b/internal/service/elbv2/listener_test.go @@ -1971,6 +1971,63 @@ func TestAccELBV2Listener_oidc(t *testing.T) { }) } +func TestAccELBV2Listener_jwtValidation(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.Listener + key := acctest.TLSRSAPrivateKeyPEM(t, 2048) + resourceName := "aws_lb_listener.test" + certificate := acctest.TLSRSAX509SelfSignedCertificatePEM(t, key, "example.com") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.ELBV2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckListenerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccListenerConfig_jwtValidation(rName, key, certificate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckListenerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttrPair(resourceName, "load_balancer_arn", "aws_lb.test", names.AttrARN), + acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "elasticloadbalancing", regexache.MustCompile("listener/.+$")), + resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, "HTTPS"), + resource.TestCheckResourceAttr(resourceName, names.AttrPort, "443"), + resource.TestCheckResourceAttr(resourceName, "default_action.#", "2"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.type", "jwt-validation"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.jwt_validation.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.jwt_validation.0.issuer", "https://example.com"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.jwt_validation.0.jwks_endpoint", "https://example.com/.well-known/jwks.json"), + resource.TestCheckResourceAttr(resourceName, "default_action.0.jwt_validation.0.additional_claim.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "default_action.0.jwt_validation.0.additional_claim.*", map[string]string{ + names.AttrFormat: "string-array", + names.AttrName: "claim_name1", + "values.#": "2", + }), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "default_action.0.jwt_validation.0.additional_claim.*", map[string]string{ + names.AttrFormat: "single-string", + names.AttrName: "claim_name2", + "values.#": "1", + "values.0": acctest.CtValue1, + }), + resource.TestCheckResourceAttr(resourceName, "default_action.1.type", "forward"), + resource.TestCheckResourceAttrPair(resourceName, "default_action.1.target_group_arn", "aws_lb_target_group.test", names.AttrARN), + resource.TestCheckResourceAttrPair(resourceName, names.AttrCertificateARN, "aws_iam_server_certificate.test", names.AttrARN), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "default_action.0.authenticate_oidc.0.client_secret", + "default_action.1.forward", + }, + }, + }, + }) +} + func TestAccELBV2Listener_DefaultAction_defaultOrder(t *testing.T) { ctx := acctest.Context(t) var listener awstypes.Listener @@ -4579,6 +4636,90 @@ resource "aws_lb_listener" "test" { `, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) } +func testAccListenerConfig_jwtValidation(rName, key, certificate string) string { + return acctest.ConfigCompose(testAccListenerConfig_base(rName), fmt.Sprintf(` +resource "aws_lb" "test" { + name = %[1]q + internal = false + security_groups = [aws_security_group.test.id] + subnets = aws_subnet.test[*].id + enable_deletion_protection = false + + tags = { + Name = %[1]q + } +} + +resource "aws_lb_target_group" "test" { + name = %[1]q + port = 8080 + protocol = "HTTP" + vpc_id = aws_vpc.test.id + + health_check { + path = "/health" + interval = 60 + port = 8081 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "200-299" + } + + tags = { + Name = %[1]q + } +} + +resource "aws_internet_gateway" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_iam_server_certificate" "test" { + name = %[1]q + certificate_body = "%[2]s" + private_key = "%[3]s" +} + +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn + + default_action { + type = "jwt-validation" + + jwt_validation { + issuer = "https://example.com" + jwks_endpoint = "https://example.com/.well-known/jwks.json" + additional_claim { + format = "string-array" + name = "claim_name1" + values = ["value1", "value2"] + } + additional_claim { + format = "single-string" + name = "claim_name2" + values = ["value1"] + } + } + } + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} +`, rName, acctest.TLSPEMEscapeNewlines(certificate), acctest.TLSPEMEscapeNewlines(key))) +} + func testAccListenerConfig_DefaultAction_defaultOrder(rName, key, certificate string) string { return acctest.ConfigCompose( testAccListenerConfig_base(rName), fmt.Sprintf(` diff --git a/internal/service/elbv2/target_group.go b/internal/service/elbv2/target_group.go index d5b051f0e2d5..b5b46900e744 100644 --- a/internal/service/elbv2/target_group.go +++ b/internal/service/elbv2/target_group.go @@ -129,7 +129,7 @@ func resourceTargetGroup() *schema.Resource { StateFunc: func(v any) string { return strings.ToUpper(v.(string)) }, - ValidateFunc: validation.StringInSlice(healthCheckProtocolEnumValues(), true), + ValidateFunc: validation.StringInSlice(enum.Slice(healthCheckProtocolEnumValues()...), true), DiffSuppressFunc: suppressIfTargetType(awstypes.TargetTypeEnumLambda), }, names.AttrTimeout: { diff --git a/internal/service/elbv2/target_group_test.go b/internal/service/elbv2/target_group_test.go index a49782d5eb01..893a5baec2dc 100644 --- a/internal/service/elbv2/target_group_test.go +++ b/internal/service/elbv2/target_group_test.go @@ -2713,105 +2713,139 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_defaults(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]map[string]struct { + testcases := map[awstypes.ProtocolEnum]map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool expectedMatcher string expectedPath string expectedTimeout string }{ - string(awstypes.ProtocolEnumHttp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200", expectedPath: "/", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200", expectedPath: "/", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidHealthCheckProtocol: true, }, }, - string(awstypes.ProtocolEnumHttps): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttps: { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200", expectedPath: "/", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200", expectedPath: "/", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidHealthCheckProtocol: true, }, }, - string(awstypes.ProtocolEnumTcp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcp: { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "6", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "10", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { expectedMatcher: "", expectedPath: "", expectedTimeout: "10", }, }, - string(awstypes.ProtocolEnumTls): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTls: { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "6", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "10", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { expectedMatcher: "", expectedPath: "", expectedTimeout: "10", }, }, - string(awstypes.ProtocolEnumUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumUdp: { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "6", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "10", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { expectedMatcher: "", expectedPath: "", expectedTimeout: "10", }, }, - string(awstypes.ProtocolEnumTcpUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcpUdp: { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "6", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "10", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { + expectedMatcher: "", + expectedPath: "", + expectedTimeout: "10", + }, + }, + awstypes.ProtocolEnumQuic: { + awstypes.ProtocolEnumHttp: { + expectedMatcher: "200-399", + expectedPath: "/", + expectedTimeout: "6", + }, + awstypes.ProtocolEnumHttps: { + expectedMatcher: "200-399", + expectedPath: "/", + expectedTimeout: "10", + }, + awstypes.ProtocolEnumTcp: { + expectedMatcher: "", + expectedPath: "", + expectedTimeout: "10", + }, + }, + awstypes.ProtocolEnumTcpQuic: { + awstypes.ProtocolEnumHttp: { + expectedMatcher: "200-399", + expectedPath: "/", + expectedTimeout: "6", + }, + awstypes.ProtocolEnumHttps: { + expectedMatcher: "200-399", + expectedPath: "/", + expectedTimeout: "10", + }, + awstypes.ProtocolEnumTcp: { expectedMatcher: "", expectedPath: "", expectedTimeout: "10", @@ -2823,9 +2857,8 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_defaults(t *testing.T) { if protocol == awstypes.ProtocolEnumGeneve { continue } - protocol := string(protocol) - t.Run(protocol, func(t *testing.T) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() protocolCase := testcases[protocol] @@ -2834,7 +2867,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_defaults(t *testing.T) { } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := protocolCase[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -2852,7 +2885,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_defaults(t *testing.T) { step.Check = resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), resource.TestCheckResourceAttr(resourceName, "target_type", string(awstypes.TargetTypeEnumInstance)), - resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, protocol), + resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, string(protocol)), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.enabled", acctest.CtTrue), resource.TestCheckResourceAttr(resourceName, "health_check.0.healthy_threshold", "3"), @@ -2860,7 +2893,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_defaults(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", tc.expectedMatcher), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", tc.expectedPath), resource.TestCheckResourceAttr(resourceName, "health_check.0.port", "traffic-port"), - resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", healthCheckProtocol), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", string(healthCheckProtocol)), resource.TestCheckResourceAttr(resourceName, "health_check.0.timeout", tc.expectedTimeout), resource.TestCheckResourceAttr(resourceName, "health_check.0.unhealthy_threshold", "3"), ) @@ -2885,79 +2918,103 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_matcher(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]map[string]struct { + testcases := map[awstypes.ProtocolEnum]map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool invalidConfig bool matcher string }{ - string(awstypes.ProtocolEnumHttp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { + awstypes.ProtocolEnumHttp: { matcher: "200", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "200", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "200", }, }, - string(awstypes.ProtocolEnumHttps): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttps: { + awstypes.ProtocolEnumHttp: { matcher: "200", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "200", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "200", }, }, - string(awstypes.ProtocolEnumTcp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcp: { + awstypes.ProtocolEnumHttp: { matcher: "200", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "200", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "200", }, }, - string(awstypes.ProtocolEnumTls): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTls: { + awstypes.ProtocolEnumHttp: { matcher: "200", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "200", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "200", }, }, - string(awstypes.ProtocolEnumUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumUdp: { + awstypes.ProtocolEnumHttp: { matcher: "200", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "200", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "200", }, }, - string(awstypes.ProtocolEnumTcpUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcpUdp: { + awstypes.ProtocolEnumHttp: { matcher: "200", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "200", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { + invalidConfig: true, + matcher: "200", + }, + }, + awstypes.ProtocolEnumQuic: { + awstypes.ProtocolEnumHttp: { + matcher: "200", + }, + awstypes.ProtocolEnumHttps: { + matcher: "200", + }, + awstypes.ProtocolEnumTcp: { + invalidConfig: true, + matcher: "200", + }, + }, + awstypes.ProtocolEnumTcpQuic: { + awstypes.ProtocolEnumHttp: { + matcher: "200", + }, + awstypes.ProtocolEnumHttps: { + matcher: "200", + }, + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "200", }, @@ -2968,9 +3025,8 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_matcher(t *testing.T) { if protocol == awstypes.ProtocolEnumGeneve { continue } - protocol := string(protocol) - t.Run(protocol, func(t *testing.T) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() protocolCase := testcases[protocol] @@ -2979,7 +3035,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_matcher(t *testing.T) { } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := protocolCase[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -2998,11 +3054,11 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_matcher(t *testing.T) { } else { step.Check = resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, protocol), + resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, string(protocol)), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.enabled", acctest.CtTrue), resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", tc.matcher), - resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", healthCheckProtocol), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", string(healthCheckProtocol)), ) } resource.ParallelTest(t, resource.TestCase{ @@ -3025,79 +3081,103 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_path(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]map[string]struct { + testcases := map[awstypes.ProtocolEnum]map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool invalidConfig bool path string }{ - string(awstypes.ProtocolEnumHttp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, }, - string(awstypes.ProtocolEnumHttps): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttps: { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, }, - string(awstypes.ProtocolEnumTcp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcp: { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, }, - string(awstypes.ProtocolEnumTls): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTls: { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, }, - string(awstypes.ProtocolEnumUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumUdp: { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, }, - string(awstypes.ProtocolEnumTcpUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcpUdp: { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { + invalidConfig: true, + path: "/path", + }, + }, + awstypes.ProtocolEnumQuic: { + awstypes.ProtocolEnumHttp: { + path: "/path", + }, + awstypes.ProtocolEnumHttps: { + path: "/path", + }, + awstypes.ProtocolEnumTcp: { + invalidConfig: true, + path: "/path", + }, + }, + awstypes.ProtocolEnumTcpQuic: { + awstypes.ProtocolEnumHttp: { + path: "/path", + }, + awstypes.ProtocolEnumHttps: { + path: "/path", + }, + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, @@ -3108,9 +3188,8 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_path(t *testing.T) { if protocol == awstypes.ProtocolEnumGeneve { continue } - protocol := string(protocol) - t.Run(protocol, func(t *testing.T) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() protocolCase := testcases[protocol] @@ -3119,7 +3198,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_path(t *testing.T) { } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := protocolCase[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -3138,11 +3217,11 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_path(t *testing.T) { } else { step.Check = resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, protocol), + resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, string(protocol)), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.enabled", acctest.CtTrue), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", tc.path), - resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", healthCheckProtocol), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", string(healthCheckProtocol)), ) } resource.ParallelTest(t, resource.TestCase{ @@ -3163,92 +3242,120 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_path(t *testing.T) { func TestAccELBV2TargetGroup_Instance_HealthCheck_matcherOutOfRange(t *testing.T) { t.Parallel() - testcases := map[string]map[string]struct { + testcases := map[awstypes.ProtocolEnum]map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool invalidConfig bool matcher string validRange string }{ - string(awstypes.ProtocolEnumHttp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { + awstypes.ProtocolEnumHttp: { matcher: "500", validRange: "200-499", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "500", validRange: "200-499", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "500", }, }, - string(awstypes.ProtocolEnumHttps): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttps: { + awstypes.ProtocolEnumHttp: { matcher: "500", validRange: "200-499", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "500", validRange: "200-499", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "500", }, }, - string(awstypes.ProtocolEnumTcp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcp: { + awstypes.ProtocolEnumHttp: { + matcher: "600", + validRange: "200-599", + }, + awstypes.ProtocolEnumHttps: { + matcher: "600", + validRange: "200-599", + }, + awstypes.ProtocolEnumTcp: { + invalidConfig: true, + matcher: "600", + }, + }, + awstypes.ProtocolEnumTls: { + awstypes.ProtocolEnumHttp: { + matcher: "600", + validRange: "200-599", + }, + awstypes.ProtocolEnumHttps: { + matcher: "600", + validRange: "200-599", + }, + awstypes.ProtocolEnumTcp: { + invalidConfig: true, + matcher: "600", + }, + }, + awstypes.ProtocolEnumUdp: { + awstypes.ProtocolEnumHttp: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "600", }, }, - string(awstypes.ProtocolEnumTls): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcpUdp: { + awstypes.ProtocolEnumHttp: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "600", }, }, - string(awstypes.ProtocolEnumUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumQuic: { + awstypes.ProtocolEnumHttp: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "600", }, }, - string(awstypes.ProtocolEnumTcpUdp): { - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumTcpQuic: { + awstypes.ProtocolEnumHttp: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "600", validRange: "200-599", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, matcher: "600", }, @@ -3259,9 +3366,8 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_matcherOutOfRange(t *testing.T if protocol == awstypes.ProtocolEnumGeneve { continue } - protocol := string(protocol) - t.Run(protocol, func(t *testing.T) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() protocolCase := testcases[protocol] @@ -3270,7 +3376,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheck_matcherOutOfRange(t *testing.T } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := protocolCase[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -3308,22 +3414,22 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGeneve_defaults(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { expectedMatcher string expectedPath string expectedTimeout string }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "200-399", expectedPath: "/", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { expectedMatcher: "", expectedPath: "", expectedTimeout: "5", @@ -3331,7 +3437,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGeneve_defaults(t *testing.T) { } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { //nolint:paralleltest // false positive - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := testcases[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -3358,7 +3464,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGeneve_defaults(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", tc.expectedMatcher), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", tc.expectedPath), resource.TestCheckResourceAttr(resourceName, "health_check.0.port", "traffic-port"), // Should be 80 - resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", healthCheckProtocol), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", string(healthCheckProtocol)), resource.TestCheckResourceAttr(resourceName, "health_check.0.timeout", tc.expectedTimeout), resource.TestCheckResourceAttr(resourceName, "health_check.0.unhealthy_threshold", "3"), ), @@ -3374,33 +3480,33 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_defaults(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool expectedMatcher string expectedPath string expectedTimeout string }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { expectedMatcher: "12", expectedPath: "/AWS.ALB/healthcheck", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { expectedMatcher: "12", expectedPath: "/AWS.ALB/healthcheck", expectedTimeout: "5", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidHealthCheckProtocol: true, }, } - for _, protocol := range enum.Slice(awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps) { - t.Run(protocol, func(t *testing.T) { + for _, protocol := range enum.EnumSlice(awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := testcases[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -3417,7 +3523,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_defaults(t *testing.T) { } else { step.Check = resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, protocol), + resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, string(protocol)), resource.TestCheckResourceAttr(resourceName, "protocol_version", "GRPC"), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.enabled", acctest.CtTrue), @@ -3426,7 +3532,7 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_defaults(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", tc.expectedMatcher), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", tc.expectedPath), resource.TestCheckResourceAttr(resourceName, "health_check.0.port", "traffic-port"), - resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", healthCheckProtocol), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", string(healthCheckProtocol)), resource.TestCheckResourceAttr(resourceName, "health_check.0.timeout", tc.expectedTimeout), resource.TestCheckResourceAttr(resourceName, "health_check.0.unhealthy_threshold", "3"), ) @@ -3451,29 +3557,29 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_path(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool invalidConfig bool path string }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { path: "/path", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { path: "/path", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidConfig: true, path: "/path", }, } - for _, protocol := range enum.Slice(awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps) { - t.Run(protocol, func(t *testing.T) { + for _, protocol := range enum.EnumSlice(awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := testcases[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -3492,11 +3598,11 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_path(t *testing.T) { } else { step.Check = resource.ComposeAggregateTestCheckFunc( testAccCheckTargetGroupExists(ctx, resourceName, &targetGroup), - resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, protocol), + resource.TestCheckResourceAttr(resourceName, names.AttrProtocol, string(protocol)), resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), resource.TestCheckResourceAttr(resourceName, "health_check.0.enabled", acctest.CtTrue), resource.TestCheckResourceAttr(resourceName, "health_check.0.path", tc.path), - resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", healthCheckProtocol), + resource.TestCheckResourceAttr(resourceName, "health_check.0.protocol", string(healthCheckProtocol)), ) } resource.ParallelTest(t, resource.TestCase{ @@ -3517,27 +3623,27 @@ func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_path(t *testing.T) { func TestAccELBV2TargetGroup_Instance_HealthCheckGRPC_matcherOutOfRange(t *testing.T) { t.Parallel() - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool matcher string }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { matcher: "101", }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { matcher: "101", }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidHealthCheckProtocol: true, }, } - for _, protocol := range enum.Slice(awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps) { - t.Run(protocol, func(t *testing.T) { + for _, protocol := range enum.EnumSlice(awstypes.ProtocolEnumHttp, awstypes.ProtocolEnumHttps) { + t.Run(string(protocol), func(t *testing.T) { t.Parallel() for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := testcases[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -3573,25 +3679,31 @@ func TestAccELBV2TargetGroup_Instance_protocolVersion(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { validConfig bool }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { validConfig: true, }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { validConfig: true, }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { + validConfig: false, + }, + awstypes.ProtocolEnumTls: { validConfig: false, }, - string(awstypes.ProtocolEnumTls): { + awstypes.ProtocolEnumUdp: { validConfig: false, }, - string(awstypes.ProtocolEnumUdp): { + awstypes.ProtocolEnumTcpUdp: { validConfig: false, }, - string(awstypes.ProtocolEnumTcpUdp): { + awstypes.ProtocolEnumQuic: { + validConfig: false, + }, + awstypes.ProtocolEnumTcpQuic: { validConfig: false, }, } @@ -3600,9 +3712,8 @@ func TestAccELBV2TargetGroup_Instance_protocolVersion(t *testing.T) { if protocol == awstypes.ProtocolEnumGeneve { continue } - protocol := string(protocol) - t.Run(protocol, func(t *testing.T) { + t.Run(string(protocol), func(t *testing.T) { protocolCase, ok := testcases[protocol] if !ok { t.Fatalf("missing case for target protocol %q", protocol) @@ -3646,25 +3757,31 @@ func TestAccELBV2TargetGroup_Instance_protocolVersion_MigrateV0(t *testing.T) { const resourceName = "aws_lb_target_group.test" - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { validConfig bool }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { validConfig: true, }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { validConfig: true, }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { + validConfig: false, + }, + awstypes.ProtocolEnumTls: { validConfig: false, }, - string(awstypes.ProtocolEnumTls): { + awstypes.ProtocolEnumUdp: { validConfig: false, }, - string(awstypes.ProtocolEnumUdp): { + awstypes.ProtocolEnumTcpUdp: { validConfig: false, }, - string(awstypes.ProtocolEnumTcpUdp): { + awstypes.ProtocolEnumQuic: { + validConfig: false, + }, + awstypes.ProtocolEnumTcpQuic: { validConfig: false, }, } @@ -3673,9 +3790,8 @@ func TestAccELBV2TargetGroup_Instance_protocolVersion_MigrateV0(t *testing.T) { if protocol == awstypes.ProtocolEnumGeneve { continue } - protocol := string(protocol) - t.Run(protocol, func(t *testing.T) { + t.Run(string(protocol), func(t *testing.T) { protocolCase, ok := testcases[protocol] if !ok { t.Fatalf("missing case for target protocol %q", protocol) @@ -4103,23 +4219,23 @@ func TestAccELBV2TargetGroup_Lambda_HealthCheck_protocol(t *testing.T) { t.Parallel() - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool warning bool }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { warning: true, }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { warning: true, }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidHealthCheckProtocol: true, }, } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { //nolint:paralleltest // false positive - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := testcases[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -4161,23 +4277,23 @@ func TestAccELBV2TargetGroup_Lambda_HealthCheck_protocol_MigrateV0(t *testing.T) t.Parallel() - testcases := map[string]struct { + testcases := map[awstypes.ProtocolEnum]struct { invalidHealthCheckProtocol bool warning bool }{ - string(awstypes.ProtocolEnumHttp): { + awstypes.ProtocolEnumHttp: { warning: true, }, - string(awstypes.ProtocolEnumHttps): { + awstypes.ProtocolEnumHttps: { warning: true, }, - string(awstypes.ProtocolEnumTcp): { + awstypes.ProtocolEnumTcp: { invalidHealthCheckProtocol: true, }, } for _, healthCheckProtocol := range tfelbv2.HealthCheckProtocolEnumValues() { //nolint:paralleltest // false positive - t.Run(healthCheckProtocol, func(t *testing.T) { + t.Run(string(healthCheckProtocol), func(t *testing.T) { tc, ok := testcases[healthCheckProtocol] if !ok { t.Fatalf("missing case for health check protocol %q", healthCheckProtocol) @@ -6012,7 +6128,7 @@ resource "aws_vpc" "test" { }`, rName) } -func testAccTargetGroupConfig_Instance_HealthCheck_basic(protocol, healthCheckProtocol string) string { +func testAccTargetGroupConfig_Instance_HealthCheck_basic(protocol, healthCheckProtocol awstypes.ProtocolEnum) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 443 @@ -6032,7 +6148,7 @@ resource "aws_vpc" "test" { `, protocol, healthCheckProtocol) } -func testAccTargetGroupConfig_Instance_HealthCheck_matcher(protocol, healthCheckProtocol, matcher string) string { +func testAccTargetGroupConfig_Instance_HealthCheck_matcher(protocol, healthCheckProtocol awstypes.ProtocolEnum, matcher string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 443 @@ -6053,7 +6169,7 @@ resource "aws_vpc" "test" { `, protocol, healthCheckProtocol, matcher) } -func testAccTargetGroupConfig_Instance_HealthCheck_path(protocol, healthCheckProtocol, matcher string) string { +func testAccTargetGroupConfig_Instance_HealthCheck_path(protocol, healthCheckProtocol awstypes.ProtocolEnum, matcher string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 443 @@ -6074,7 +6190,7 @@ resource "aws_vpc" "test" { `, protocol, healthCheckProtocol, matcher) } -func testAccTargetGroupConfig_Instance_HealthCheckGeneve_basic(healthCheckProtocol string) string { +func testAccTargetGroupConfig_Instance_HealthCheckGeneve_basic(healthCheckProtocol awstypes.ProtocolEnum) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 6081 @@ -6094,7 +6210,7 @@ resource "aws_vpc" "test" { `, healthCheckProtocol) } -func testAccTargetGroupConfig_Instance_HealhCheckGRPC_basic(protocol, healthCheckProtocol string) string { +func testAccTargetGroupConfig_Instance_HealhCheckGRPC_basic(protocol, healthCheckProtocol awstypes.ProtocolEnum) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 443 @@ -6115,7 +6231,7 @@ resource "aws_vpc" "test" { `, protocol, healthCheckProtocol) } -func testAccTargetGroupConfig_Instance_HealhCheckGRPC_path(protocol, healthCheckProtocol, path string) string { +func testAccTargetGroupConfig_Instance_HealhCheckGRPC_path(protocol, healthCheckProtocol awstypes.ProtocolEnum, path string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 443 @@ -6137,7 +6253,7 @@ resource "aws_vpc" "test" { `, protocol, healthCheckProtocol, path) } -func testAccTargetGroupConfig_Instance_HealhCheckGRPC_matcher(protocol, healthCheckProtocol, matcher string) string { +func testAccTargetGroupConfig_Instance_HealhCheckGRPC_matcher(protocol, healthCheckProtocol awstypes.ProtocolEnum, matcher string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { port = 443 @@ -6159,7 +6275,7 @@ resource "aws_vpc" "test" { `, protocol, healthCheckProtocol, matcher) } -func testAccTargetGroupConfig_Instance_protocolVersion(protocol, protocolVersion string) string { +func testAccTargetGroupConfig_Instance_protocolVersion(protocol awstypes.ProtocolEnum, protocolVersion string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { target_type = "instance" @@ -6241,7 +6357,7 @@ resource "aws_lb_target_group" "test" { ` } -func testAccTargetGroupConfig_Lambda_HealthCheck_protocol(healthCheckProtocol string) string { +func testAccTargetGroupConfig_Lambda_HealthCheck_protocol(healthCheckProtocol awstypes.ProtocolEnum) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { target_type = "lambda" diff --git a/internal/service/emr/managed_scaling_policy.go b/internal/service/emr/managed_scaling_policy.go index 7d835ca9182c..61f6ddd85885 100644 --- a/internal/service/emr/managed_scaling_policy.go +++ b/internal/service/emr/managed_scaling_policy.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs" @@ -73,6 +74,18 @@ func resourceManagedScalingPolicy() *schema.Resource { }, }, }, + "scaling_strategy": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.ScalingStrategy](), + }, + "utilization_performance_index": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntInSlice([]int{1, 25, 50, 75, 100}), + }, }, } } @@ -82,6 +95,9 @@ func resourceManagedScalingPolicyCreate(ctx context.Context, d *schema.ResourceD conn := meta.(*conns.AWSClient).EMRClient(ctx) clusterID := d.Get("cluster_id").(string) + input := &emr.PutManagedScalingPolicyInput{ + ClusterId: aws.String(clusterID), + } if v := d.Get("compute_limits").(*schema.Set).List(); len(v) > 0 && v[0] != nil { tfMap := v[0].(map[string]any) computeLimits := &awstypes.ComputeLimits{ @@ -98,18 +114,22 @@ func resourceManagedScalingPolicyCreate(ctx context.Context, d *schema.ResourceD } else if v, ok := tfMap["maximum_ondemand_capacity_units"].(int); ok && v >= 0 { computeLimits.MaximumOnDemandCapacityUnits = aws.Int32(int32(v)) } - input := &emr.PutManagedScalingPolicyInput{ - ClusterId: aws.String(clusterID), - ManagedScalingPolicy: &awstypes.ManagedScalingPolicy{ - ComputeLimits: computeLimits, - }, + input.ManagedScalingPolicy = &awstypes.ManagedScalingPolicy{ + ComputeLimits: computeLimits, } + } + if v, ok := d.GetOk("scaling_strategy"); ok { + input.ManagedScalingPolicy.ScalingStrategy = awstypes.ScalingStrategy(v.(string)) + } - _, err := conn.PutManagedScalingPolicy(ctx, input) + if v, ok := d.GetOk("utilization_performance_index"); ok { + input.ManagedScalingPolicy.UtilizationPerformanceIndex = aws.Int32(int32(v.(int))) + } - if err != nil { - return sdkdiag.AppendErrorf(diags, "putting EMR Managed Scaling Policy: %s", err) - } + _, err := conn.PutManagedScalingPolicy(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "putting EMR Managed Scaling Policy: %s", err) } d.SetId(clusterID) @@ -138,6 +158,10 @@ func resourceManagedScalingPolicyRead(ctx context.Context, d *schema.ResourceDat return sdkdiag.AppendErrorf(diags, "setting compute_limits: %s", err) } + if managedScalingPolicy.ScalingStrategy != "" { + d.Set("scaling_strategy", managedScalingPolicy.ScalingStrategy) + d.Set("utilization_performance_index", managedScalingPolicy.UtilizationPerformanceIndex) + } return diags } diff --git a/internal/service/emr/managed_scaling_policy_test.go b/internal/service/emr/managed_scaling_policy_test.go index a5e5cf2e8b62..40a746bce523 100644 --- a/internal/service/emr/managed_scaling_policy_test.go +++ b/internal/service/emr/managed_scaling_policy_test.go @@ -8,6 +8,7 @@ import ( "fmt" "testing" + awstypes "github.com/aws/aws-sdk-go-v2/service/emr/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -174,6 +175,38 @@ func TestAccEMRManagedScalingPolicy_ComputeLimits_maximumOnDemandCapacityUnitsSp }) } +func TestAccEMRManagedScalingPolicy_advancedScaling(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_emr_managed_scaling_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EMRServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckManagedScalingPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccManagedScalingPolicyConfig_advancedScaling(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckManagedScalingPolicyExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "scaling_strategy", string(awstypes.ScalingStrategyAdvanced)), + resource.TestCheckResourceAttr(resourceName, "utilization_performance_index", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "compute_limits.0.maximum_core_capacity_units", + "compute_limits.0.maximum_ondemand_capacity_units", + }, + }, + }, + }) +} + func testAccCheckManagedScalingPolicyExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -215,7 +248,7 @@ func testAccCheckManagedScalingPolicyDestroy(ctx context.Context) resource.TestC } } -func testAccManagedScalingPolicyConfig_base(rName string) string { +func testAccManagedScalingPolicyConfig_base(rName, releaseLabel, instanceType string) string { return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptInDefaultExclude(), fmt.Sprintf(` resource "aws_vpc" "test" { cidr_block = "10.0.0.0/16" @@ -455,16 +488,16 @@ resource "aws_emr_cluster" "test" { keep_job_flow_alive_when_no_steps = true log_uri = "s3n://terraform/testlog/" name = %[1]q - release_label = "emr-5.30.1" + release_label = %[2]q service_role = aws_iam_role.emr_service.arn master_instance_group { - instance_type = "c4.large" + instance_type = %[3]q } core_instance_group { instance_count = 1 - instance_type = "c4.large" + instance_type = %[3]q } depends_on = [ @@ -479,13 +512,15 @@ resource "aws_emr_cluster" "test" { emr_managed_slave_security_group = aws_security_group.test.id instance_profile = aws_iam_instance_profile.emr_instance_profile.arn } - + lifecycle { + ignore_changes = ["os_release_label"] + } } -`, rName)) +`, rName, releaseLabel, instanceType)) } func testAccManagedScalingPolicyConfig_basic(rName string) string { - return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName), ` + return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName, "emr-5.30.1", "c4.large"), ` resource "aws_emr_managed_scaling_policy" "test" { cluster_id = aws_emr_cluster.test.id compute_limits { @@ -498,7 +533,7 @@ resource "aws_emr_managed_scaling_policy" "test" { } func testAccManagedScalingPolicyConfig_computeLimitsMaximumCoreCapacityUnits(rName string, maximumCoreCapacityUnits int) string { - return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName, "emr-5.30.1", "c4.large"), fmt.Sprintf(` resource "aws_emr_managed_scaling_policy" "test" { cluster_id = aws_emr_cluster.test.id compute_limits { @@ -512,7 +547,7 @@ resource "aws_emr_managed_scaling_policy" "test" { } func testAccManagedScalingPolicyConfig_computeLimitsMaximumOnDemandCapacityUnits(rName string, maximumOnDemandCapacityUnits int) string { - return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName, "emr-5.30.1", "c4.large"), fmt.Sprintf(` resource "aws_emr_managed_scaling_policy" "test" { cluster_id = aws_emr_cluster.test.id compute_limits { @@ -524,3 +559,18 @@ resource "aws_emr_managed_scaling_policy" "test" { } `, maximumOnDemandCapacityUnits)) } + +func testAccManagedScalingPolicyConfig_advancedScaling(rName string) string { + return acctest.ConfigCompose(testAccManagedScalingPolicyConfig_base(rName, "emr-7.12.0", "r8g.xlarge"), ` +resource "aws_emr_managed_scaling_policy" "test" { + cluster_id = aws_emr_cluster.test.id + compute_limits { + unit_type = "Instances" + minimum_capacity_units = 1 + maximum_capacity_units = 2 + } + scaling_strategy = "ADVANCED" + utilization_performance_index = 1 +} +`) +} diff --git a/internal/service/emrcontainers/job_template.go b/internal/service/emrcontainers/job_template.go index b37cf7351b93..da99dbdfebd8 100644 --- a/internal/service/emrcontainers/job_template.go +++ b/internal/service/emrcontainers/job_template.go @@ -135,6 +135,7 @@ func resourceJobTemplate() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, ValidateDiagFunc: enum.Validate[awstypes.PersistentAppUI](), }, "s3_monitoring_configuration": { @@ -499,7 +500,7 @@ func expandCloudWatchMonitoringConfiguration(tfMap map[string]any) *awstypes.Par apiObject := &awstypes.ParametricCloudWatchMonitoringConfiguration{} - if v, ok := tfMap["log_group_mame"].(string); ok && v != "" { + if v, ok := tfMap[names.AttrLogGroupName].(string); ok && v != "" { apiObject.LogGroupName = aws.String(v) } @@ -620,7 +621,7 @@ func flattenConfigurationOverrides(apiObject *awstypes.ParametricConfigurationOv tfMap := map[string]any{} if v := apiObject.ApplicationConfiguration; v != nil { - tfMap["application_configuration"] = []any{flattenConfigurations(v)} + tfMap["application_configuration"] = flattenConfigurations(v) } if v := apiObject.MonitoringConfiguration; v != nil { diff --git a/internal/service/emrcontainers/job_template_test.go b/internal/service/emrcontainers/job_template_test.go index 24d7d0111da0..14f46393aea1 100644 --- a/internal/service/emrcontainers/job_template_test.go +++ b/internal/service/emrcontainers/job_template_test.go @@ -56,6 +56,53 @@ func TestAccEMRContainersJobTemplate_basic(t *testing.T) { }) } +func TestAccEMRContainersJobTemplate_configurationOverrides(t *testing.T) { + ctx := acctest.Context(t) + var v awstypes.JobTemplate + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_emrcontainers_job_template.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EMRContainersServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckJobTemplateDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccJobTemplateConfig_configurationOverrides(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckJobTemplateExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "job_template_data.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "job_template_data.0.execution_role_arn", "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.job_driver.#", "1"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.job_driver.0.spark_sql_job_driver.#", "1"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.job_driver.0.spark_sql_job_driver.0.entry_point", "default"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.release_label", "emr-6.10.0-latest"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.#", "1"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.application_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.application_configuration.0.classification", "spark-defaults"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.application_configuration.0.properties.%", "2"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.application_configuration.0.properties.spark.executor.memory", "4G"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.application_configuration.0.properties.spark.driver.memory", "2G"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.monitoring_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.monitoring_configuration.0.cloud_watch_monitoring_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.monitoring_configuration.0.cloud_watch_monitoring_configuration.0.log_group_name", "/emr/"+rName), + resource.TestCheckResourceAttr(resourceName, "job_template_data.0.configuration_overrides.0.monitoring_configuration.0.cloud_watch_monitoring_configuration.0.log_stream_name_prefix", "spark-job-logs"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccEMRContainersJobTemplate_disappears(t *testing.T) { ctx := acctest.Context(t) var v awstypes.JobTemplate @@ -164,7 +211,7 @@ func testAccCheckJobTemplateDestroy(ctx context.Context) resource.TestCheckFunc } } -func testAccJobTemplateConfig_basic(rName string) string { +func testAccJobTemplateConfig_base(rName string) string { return fmt.Sprintf(` data "aws_partition" "current" {} @@ -185,7 +232,13 @@ resource "aws_iam_role" "test" { Version = "2012-10-17" }) } +`, rName) +} +func testAccJobTemplateConfig_basic(rName string) string { + return acctest.ConfigCompose( + testAccJobTemplateConfig_base(rName), + fmt.Sprintf(` resource "aws_emrcontainers_job_template" "test" { job_template_data { execution_role_arn = aws_iam_role.test.arn @@ -200,31 +253,49 @@ resource "aws_emrcontainers_job_template" "test" { name = %[1]q } -`, rName) +`, rName)) } -func testAccJobTemplateConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -data "aws_partition" "current" {} - -resource "aws_iam_role" "test" { - name = %[1]q +func testAccJobTemplateConfig_configurationOverrides(rName string) string { + return acctest.ConfigCompose( + testAccJobTemplateConfig_base(rName), + fmt.Sprintf(` +resource "aws_emrcontainers_job_template" "test" { + job_template_data { + execution_role_arn = aws_iam_role.test.arn + release_label = "emr-6.10.0-latest" - assume_role_policy = jsonencode({ - Statement = [{ - Action = "sts:AssumeRole" - Effect = "Allow" - Principal = { - Service = [ - "eks.${data.aws_partition.current.dns_suffix}", - "eks-nodegroup.${data.aws_partition.current.dns_suffix}", - ] + job_driver { + spark_sql_job_driver { + entry_point = "default" } - }] - Version = "2012-10-17" - }) + } + configuration_overrides { + application_configuration { + classification = "spark-defaults" + properties = { + "spark.executor.memory" = "4G" + "spark.driver.memory" = "2G" + } + } + monitoring_configuration { + cloud_watch_monitoring_configuration { + log_group_name = "/emr/%[1]s" + log_stream_name_prefix = "spark-job-logs" + } + } + } + } + + name = %[1]q +} +`, rName)) } +func testAccJobTemplateConfig_tags1(rName, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose( + testAccJobTemplateConfig_base(rName), + fmt.Sprintf(` resource "aws_emrcontainers_job_template" "test" { job_template_data { execution_role_arn = aws_iam_role.test.arn @@ -244,5 +315,5 @@ resource "aws_emrcontainers_job_template" "test" { } } -`, rName, tagKey1, tagValue1) +`, rName, tagKey1, tagValue1)) } diff --git a/internal/service/fis/experiment_template.go b/internal/service/fis/experiment_template.go index cc92968faade..c3df9f0dbf42 100644 --- a/internal/service/fis/experiment_template.go +++ b/internal/service/fis/experiment_template.go @@ -227,6 +227,10 @@ func resourceExperimentTemplate() *schema.Resource { "log_group_arn": { Type: schema.TypeString, Required: true, + ValidateFunc: validation.All( + verify.ValidARN, + validation.StringMatch(regexache.MustCompile(`:\*$`), "ARN must end with `:*`"), + ), }, }, }, @@ -1329,6 +1333,7 @@ func validExperimentTemplateActionTargetKey() schema.SchemaValidateFunc { "Cluster", "Clusters", "DBInstances", + "Functions", "Instances", "ManagedResources", "Nodegroups", diff --git a/internal/service/fis/experiment_template_test.go b/internal/service/fis/experiment_template_test.go index 4bc352125a37..9c015ad7ab87 100644 --- a/internal/service/fis/experiment_template_test.go +++ b/internal/service/fis/experiment_template_test.go @@ -601,6 +601,52 @@ func TestAccFISExperimentTemplate_reportConfiguration(t *testing.T) { }) } +func TestAccFISExperimentTemplate_lambdaFunctions(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_fis_experiment_template.test" + var conf awstypes.ExperimentTemplate + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, fis.ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckExperimentTemplateDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccExperimentTemplateConfig_lambda_functions(rName, "Lambda function invocation error", "func-invoke-error", "Lambda function invocation error", "aws:lambda:invocation-error", "Functions", "function-target-1", names.AttrDuration, "PT5M", "aws:lambda:function", "ALL", "Name"), + Check: resource.ComposeTestCheckFunc( + testAccExperimentTemplateExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Lambda function invocation error"), + resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test_fis", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "stop_condition.0.source", "none"), + resource.TestCheckResourceAttr(resourceName, "stop_condition.0.value", ""), + resource.TestCheckResourceAttr(resourceName, "stop_condition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.0.name", "func-invoke-error"), + resource.TestCheckResourceAttr(resourceName, "action.0.description", "Lambda function invocation error"), + resource.TestCheckResourceAttr(resourceName, "action.0.action_id", "aws:lambda:invocation-error"), + resource.TestCheckResourceAttr(resourceName, "action.0.parameter.#", "2"), + resource.TestCheckResourceAttr(resourceName, "action.0.parameter.0.key", names.AttrDuration), + resource.TestCheckResourceAttr(resourceName, "action.0.parameter.0.value", "PT5M"), + resource.TestCheckResourceAttr(resourceName, "action.0.start_after.#", "0"), + resource.TestCheckResourceAttr(resourceName, "action.0.target.0.key", "Functions"), + resource.TestCheckResourceAttr(resourceName, "action.0.target.0.value", "function-target-1"), + resource.TestCheckResourceAttr(resourceName, "action.0.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target.0.name", "function-target-1"), + resource.TestCheckResourceAttr(resourceName, "target.0.resource_type", "aws:lambda:function"), + resource.TestCheckResourceAttr(resourceName, "target.0.selection_mode", "ALL"), + resource.TestCheckResourceAttrPair(resourceName, "target.0.resource_arns.0", "aws_lambda_function.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "target.#", "1"), + ), + }, + }, + }) +} + func testAccExperimentTemplateConfig_basic(rName, desc, actionName, actionDesc, actionID, actionTargetK, actionTargetV, targetResType, targetSelectMode, targetResTagK, targetResTagV string) string { return fmt.Sprintf(` data "aws_partition" "current" {} @@ -1593,3 +1639,79 @@ resource "aws_fis_experiment_template" "test" { } `, rName, desc, actionName, actionDesc, actionID, actionTargetK, actionTargetV, targetResType, targetSelectMode, targetResTagK, targetResTagV) } + +func testAccExperimentTemplateConfig_lambda_functions(rName, desc, actionName, actionDesc, actionID, actionTargetK, actionTargetV, paramK1, paramV1, targetResType, targetSelectMode, targetResTagK string) string { + return acctest.ConfigCompose(testAccExperimentTemplateConfig_baseEBSVolume(rName), fmt.Sprintf(` +resource "aws_iam_role" "test_fis" { + name = %[1]q + + assume_role_policy = jsonencode({ + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = [ + "fis.${data.aws_partition.current.dns_suffix}", + "lambda.${data.aws_partition.current.dns_suffix}" + ] + } + }] + Version = "2012-10-17" + }) +} + +resource "aws_lambda_function" "test" { + function_name = %[1]q + role = aws_iam_role.test_fis.arn + handler = "exports.example" + runtime = "nodejs20.x" + filename = "test-fixtures/lambdatest.zip" + + tags = { + Name = %[1]q + } +} + +resource "aws_fis_experiment_template" "test" { + description = %[2]q + role_arn = aws_iam_role.test_fis.arn + + stop_condition { + source = "none" + } + + action { + name = %[3]q + description = %[4]q + action_id = %[5]q + + target { + key = %[6]q + value = %[7]q + } + + parameter { + key = %[8]q + value = %[9]q + } + + parameter { + key = "preventExecution" + value = true + } + } + + target { + name = %[7]q + resource_type = %[10]q + selection_mode = %[11]q + + resource_arns = [aws_lambda_function.test.arn] + } + + tags = { + Name = %[1]q + } +} +`, rName+"-fis", desc, actionName, actionDesc, actionID, actionTargetK, actionTargetV, paramK1, paramV1, targetResType, targetSelectMode, targetResTagK)) +} diff --git a/internal/service/fis/test-fixtures/lambdatest.zip b/internal/service/fis/test-fixtures/lambdatest.zip new file mode 100644 index 000000000000..5fb94f77a220 Binary files /dev/null and b/internal/service/fis/test-fixtures/lambdatest.zip differ diff --git a/internal/service/guardduty/detector_data_source_tags_gen_test.go b/internal/service/guardduty/detector_data_source_tags_gen_test.go index a40dcaeec217..25e7088d6f4a 100644 --- a/internal/service/guardduty/detector_data_source_tags_gen_test.go +++ b/internal/service/guardduty/detector_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfguardduty "github.com/hashicorp/terraform-provider-aws/internal/service/guardduty" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -208,7 +208,7 @@ func testAccGuardDutyDetectorDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *t } func expectFullDetectorDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfguardduty.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfguardduty.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/iam/encryption.go b/internal/service/iam/encryption.go index 39f5ccd5396f..db3780c716ce 100644 --- a/internal/service/iam/encryption.go +++ b/internal/service/iam/encryption.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/vault/helper/pgpkeys" ) @@ -38,5 +38,5 @@ func encryptValue(encryptionKey, value, description string) (string, string, err return "", "", fmt.Errorf("encrypting %s: %w", description, err) } - return fingerprints[0], itypes.Base64Encode(encryptedValue[0]), nil + return fingerprints[0], inttypes.Base64Encode(encryptedValue[0]), nil } diff --git a/internal/service/iam/openid_connect_provider_data_source_tags_gen_test.go b/internal/service/iam/openid_connect_provider_data_source_tags_gen_test.go index 74bced62d9cd..72a27e5d71ad 100644 --- a/internal/service/iam/openid_connect_provider_data_source_tags_gen_test.go +++ b/internal/service/iam/openid_connect_provider_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccIAMOIDCProviderDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *tes } func expectFullOIDCProviderDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, ResourceType: "OIDCProvider", }), knownValue) diff --git a/internal/service/iam/organizations_features.go b/internal/service/iam/organizations_features.go index bb46f659f079..2e348fe99034 100644 --- a/internal/service/iam/organizations_features.go +++ b/internal/service/iam/organizations_features.go @@ -20,7 +20,7 @@ import ( fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -199,8 +199,8 @@ func findOrganizationsFeatures(ctx context.Context, conn *iam.Client) (*iam.List } func updateOrganizationFeatures(ctx context.Context, conn *iam.Client, new, old []awstypes.FeatureType) error { - toEnable := itypes.Set[awstypes.FeatureType](new).Difference(old) - toDisable := itypes.Set[awstypes.FeatureType](old).Difference(new) + toEnable := inttypes.Set[awstypes.FeatureType](new).Difference(old) + toDisable := inttypes.Set[awstypes.FeatureType](old).Difference(new) if slices.Contains(toEnable, awstypes.FeatureTypeRootCredentialsManagement) { input := &iam.EnableOrganizationsRootCredentialsManagementInput{} diff --git a/internal/service/iam/policy_data_source_tags_gen_test.go b/internal/service/iam/policy_data_source_tags_gen_test.go index 1561ecbd5a6f..fd8baf986612 100644 --- a/internal/service/iam/policy_data_source_tags_gen_test.go +++ b/internal/service/iam/policy_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccIAMPolicyDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T } func expectFullPolicyDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, ResourceType: "Policy", }), knownValue) diff --git a/internal/service/iam/role_data_source_tags_gen_test.go b/internal/service/iam/role_data_source_tags_gen_test.go index ccac54781cc7..feeb8a536c21 100644 --- a/internal/service/iam/role_data_source_tags_gen_test.go +++ b/internal/service/iam/role_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccIAMRoleDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) } func expectFullRoleDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrName, ResourceType: "Role", }), knownValue) diff --git a/internal/service/iam/tags.go b/internal/service/iam/tags.go index 52f7c45837c2..420f146a47dd 100644 --- a/internal/service/iam/tags.go +++ b/internal/service/iam/tags.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build !generate -// +build !generate package iam diff --git a/internal/service/iam/user_data_source_tags_gen_test.go b/internal/service/iam/user_data_source_tags_gen_test.go index 837f5cdb6c9d..f31448384fa7 100644 --- a/internal/service/iam/user_data_source_tags_gen_test.go +++ b/internal/service/iam/user_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfiam "github.com/hashicorp/terraform-provider-aws/internal/service/iam" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccIAMUserDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) } func expectFullUserDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfiam.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrUserName, ResourceType: "User", }), knownValue) diff --git a/internal/service/imagebuilder/image_recipe_test.go b/internal/service/imagebuilder/image_recipe_test.go index 81055d3cffab..1820ed2103ac 100644 --- a/internal/service/imagebuilder/image_recipe_test.go +++ b/internal/service/imagebuilder/image_recipe_test.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tfimagebuilder "github.com/hashicorp/terraform-provider-aws/internal/service/imagebuilder" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -746,7 +746,7 @@ func TestAccImageBuilderImageRecipe_userDataBase64(t *testing.T) { Config: testAccImageRecipeConfig_userDataBase64(rName), Check: resource.ComposeTestCheckFunc( testAccCheckImageRecipeExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, "user_data_base64", itypes.Base64EncodeOnce([]byte("hello world"))), + resource.TestCheckResourceAttr(resourceName, "user_data_base64", inttypes.Base64EncodeOnce([]byte("hello world"))), ), }, { diff --git a/internal/service/inspector/tags.go b/internal/service/inspector/tags.go index 0b1d23f037d0..80adc3a5d06a 100644 --- a/internal/service/inspector/tags.go +++ b/internal/service/inspector/tags.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build !generate -// +build !generate package inspector diff --git a/internal/service/inspector2/filter_test.go b/internal/service/inspector2/filter_test.go index d90c1dc07f67..4d1552c57c69 100644 --- a/internal/service/inspector2/filter_test.go +++ b/internal/service/inspector2/filter_test.go @@ -23,7 +23,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func testAccInspector2Filter_basic(t *testing.T) { +func TestAccInspector2Filter_basic(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" @@ -71,7 +71,7 @@ func testAccInspector2Filter_basic(t *testing.T) { }) } -func testAccInspector2Filter_update(t *testing.T) { +func TestAccInspector2Filter_update(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" @@ -147,7 +147,7 @@ func testAccInspector2Filter_update(t *testing.T) { }) } -func testAccInspector2Filter_stringFilters(t *testing.T) { +func TestAccInspector2Filter_stringFilters(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" @@ -243,7 +243,7 @@ func testAccInspector2Filter_stringFilters(t *testing.T) { }) } -func testAccInspector2Filter_numberFilters(t *testing.T) { +func TestAccInspector2Filter_numberFilters(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" @@ -329,7 +329,7 @@ func testAccInspector2Filter_numberFilters(t *testing.T) { }) } -func testAccInspector2Filter_dateFilters(t *testing.T) { +func TestAccInspector2Filter_dateFilters(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" @@ -415,7 +415,7 @@ func testAccInspector2Filter_dateFilters(t *testing.T) { }) } -func testAccInspector2Filter_mapFilters(t *testing.T) { +func TestAccInspector2Filter_mapFilters(t *testing.T) { ctx := acctest.Context(t) comparison := string(awstypes.MapComparisonEquals) action_1 := string(awstypes.FilterActionNone) @@ -494,7 +494,7 @@ func testAccInspector2Filter_mapFilters(t *testing.T) { }) } -func testAccInspector2Filter_portRangeFilters(t *testing.T) { +func TestAccInspector2Filter_portRangeFilters(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" @@ -566,7 +566,7 @@ func testAccInspector2Filter_portRangeFilters(t *testing.T) { }) } -func testAccInspector2Filter_packageFilters(t *testing.T) { +func TestAccInspector2Filter_packageFilters(t *testing.T) { ctx := acctest.Context(t) comparison := string(awstypes.MapComparisonEquals) action_1 := string(awstypes.FilterActionNone) @@ -728,7 +728,7 @@ func testAccInspector2Filter_packageFilters(t *testing.T) { }) } -func testAccInspector2Filter_disappears(t *testing.T) { +func TestAccInspector2Filter_disappears(t *testing.T) { ctx := acctest.Context(t) action_1 := string(awstypes.FilterActionNone) description_1 := "TestDescription_1" diff --git a/internal/service/inspector2/inspector2_test.go b/internal/service/inspector2/inspector2_test.go index da024e00b3c0..0f2a30717e5a 100644 --- a/internal/service/inspector2/inspector2_test.go +++ b/internal/service/inspector2/inspector2_test.go @@ -32,21 +32,6 @@ func TestAccInspector2_serial(t *testing.T) { acctest.CtBasic: testAccDelegatedAdminAccount_basic, acctest.CtDisappears: testAccDelegatedAdminAccount_disappears, }, - "Filter": { - acctest.CtBasic: testAccInspector2Filter_basic, - "update": testAccInspector2Filter_update, - acctest.CtDisappears: testAccInspector2Filter_disappears, - "filter_stringFilters": testAccInspector2Filter_stringFilters, - "filter_dateFilters": testAccInspector2Filter_dateFilters, - "filter_numberFilters": testAccInspector2Filter_numberFilters, - "filter_mapFilters": testAccInspector2Filter_mapFilters, - "filter_portRangeFilters": testAccInspector2Filter_portRangeFilters, - "filter_packageFilters": testAccInspector2Filter_packageFilters, - }, - "FilterAssociation": { - acctest.CtBasic: testAccInspector2Filter_basic, - acctest.CtDisappears: testAccMemberAssociation_disappears, - }, "MemberAssociation": { acctest.CtBasic: testAccMemberAssociation_basic, acctest.CtDisappears: testAccMemberAssociation_disappears, diff --git a/internal/service/invoicing/invoice_unit.go b/internal/service/invoicing/invoice_unit.go index c55309e26db5..d2275dfd8d27 100644 --- a/internal/service/invoicing/invoice_unit.go +++ b/internal/service/invoicing/invoice_unit.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" @@ -75,6 +76,9 @@ func (r *invoiceUnitResource) Schema(ctx context.Context, request resource.Schem "tax_inheritance_disabled": schema.BoolAttribute{ Optional: true, Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), @@ -215,11 +219,13 @@ func (r *invoiceUnitResource) Update(ctx context.Context, request resource.Updat return } - _, err = waitInvoiceUnitUpdated(ctx, conn, new.ARN.ValueString(), r.UpdateTimeout(ctx, new.Timeouts)) + var output *invoicing.GetInvoiceUnitOutput + output, err = waitInvoiceUnitUpdated(ctx, conn, new.ARN.ValueString(), r.UpdateTimeout(ctx, new.Timeouts)) if err != nil { smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, new.ARN.ValueString()) return } + new.LastModified = fwflex.TimeToFramework(ctx, output.LastModified) } smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, new)) diff --git a/internal/service/invoicing/invoice_unit_test.go b/internal/service/invoicing/invoice_unit_test.go index c8f8739f6739..b951e321ae07 100644 --- a/internal/service/invoicing/invoice_unit_test.go +++ b/internal/service/invoicing/invoice_unit_test.go @@ -12,6 +12,7 @@ import ( "github.com/aws/aws-sdk-go-v2/service/invoicing" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -38,6 +39,11 @@ func TestAccInvoicingInvoiceUnit_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccInvoiceUnitConfig_basic(rName, invoiceReceiver, linkedAccount), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, Check: resource.ComposeTestCheckFunc( testAccCheckInvoiceUnitExists(ctx, resourceName, &invoiceUnit), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), @@ -47,6 +53,27 @@ func TestAccInvoicingInvoiceUnit_basic(t *testing.T) { resource.TestCheckTypeSetElemAttr(resourceName, "rule.0.linked_accounts.*", linkedAccount), acctest.MatchResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "invoicing", regexache.MustCompile(`invoice-unit/.+`)), acctest.CheckResourceAttrRFC3339(resourceName, "last_modified"), + resource.TestCheckResourceAttr(resourceName, "tax_inheritance_disabled", acctest.CtFalse), + ), + }, + { + Config: testAccInvoiceUnitConfig_description(rName, invoiceReceiver, linkedAccount, "test"), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckInvoiceUnitExists(ctx, resourceName, &invoiceUnit), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "test"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "invoice_receiver", invoiceReceiver), + resource.TestCheckResourceAttr(resourceName, acctest.CtRulePound, "1"), + resource.TestCheckResourceAttr(resourceName, "rule.0.linked_accounts.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "rule.0.linked_accounts.*", linkedAccount), + acctest.MatchResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "invoicing", regexache.MustCompile(`invoice-unit/.+`)), + acctest.CheckResourceAttrRFC3339(resourceName, "last_modified"), + resource.TestCheckResourceAttr(resourceName, "tax_inheritance_disabled", acctest.CtFalse), ), }, { @@ -116,3 +143,17 @@ resource "aws_invoicing_invoice_unit" "test" { } `, rName, invoiceReceiver, linkedAccount) } + +func testAccInvoiceUnitConfig_description(rName, invoiceReceiver, linkedAccount, description string) string { + return fmt.Sprintf(` +resource "aws_invoicing_invoice_unit" "test" { + name = %[1]q + invoice_receiver = %[2]q + + rule { + linked_accounts = [%[3]q] + } + description = %[4]q +} +`, rName, invoiceReceiver, linkedAccount, description) +} diff --git a/internal/service/kafkaconnect/worker_configuration.go b/internal/service/kafkaconnect/worker_configuration.go index 7b41351e0173..db697d13d197 100644 --- a/internal/service/kafkaconnect/worker_configuration.go +++ b/internal/service/kafkaconnect/worker_configuration.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -228,7 +228,7 @@ func waitWorkerConfigurationDeleted(ctx context.Context, conn *kafkaconnect.Clie } func decodePropertiesFileContent(content string) string { - v, err := itypes.Base64Decode(content) + v, err := inttypes.Base64Decode(content) if err != nil { return content } diff --git a/internal/service/kinesis/tags.go b/internal/service/kinesis/tags.go index 5d7c45689727..ae57d5a927e4 100644 --- a/internal/service/kinesis/tags.go +++ b/internal/service/kinesis/tags.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build !generate -// +build !generate package kinesis diff --git a/internal/service/kms/ciphertext.go b/internal/service/kms/ciphertext.go index ce718cf6f230..aeac3cc2ebc8 100644 --- a/internal/service/kms/ciphertext.go +++ b/internal/service/kms/ciphertext.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -73,7 +73,7 @@ func resourceCiphertextCreate(ctx context.Context, d *schema.ResourceData, meta //lintignore:R017 // Allow legacy unstable ID usage in managed resource d.SetId(time.Now().UTC().String()) - d.Set("ciphertext_blob", itypes.Base64Encode(output.CiphertextBlob)) + d.Set("ciphertext_blob", inttypes.Base64Encode(output.CiphertextBlob)) return diags } diff --git a/internal/service/kms/ciphertext_data_source.go b/internal/service/kms/ciphertext_data_source.go index 3a59f3f40452..87d74e5d4b4e 100644 --- a/internal/service/kms/ciphertext_data_source.go +++ b/internal/service/kms/ciphertext_data_source.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -66,7 +66,7 @@ func dataSourceCiphertextRead(ctx context.Context, d *schema.ResourceData, meta } d.SetId(aws.ToString(output.KeyId)) - d.Set("ciphertext_blob", itypes.Base64Encode(output.CiphertextBlob)) + d.Set("ciphertext_blob", inttypes.Base64Encode(output.CiphertextBlob)) return diags } diff --git a/internal/service/kms/public_key_data_source.go b/internal/service/kms/public_key_data_source.go index 2ec43e09e52d..1e9838fcacc9 100644 --- a/internal/service/kms/public_key_data_source.go +++ b/internal/service/kms/public_key_data_source.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -92,7 +92,7 @@ func dataSourcePublicKeyRead(ctx context.Context, d *schema.ResourceData, meta a d.Set("customer_master_key_spec", output.KeySpec) d.Set("encryption_algorithms", output.EncryptionAlgorithms) d.Set("key_usage", output.KeyUsage) - d.Set(names.AttrPublicKey, itypes.Base64Encode(output.PublicKey)) + d.Set(names.AttrPublicKey, inttypes.Base64Encode(output.PublicKey)) d.Set("public_key_pem", string(pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", Bytes: output.PublicKey, diff --git a/internal/service/kms/secrets_data_source.go b/internal/service/kms/secrets_data_source.go index d97c30d8c0ae..4fe8cd979830 100644 --- a/internal/service/kms/secrets_data_source.go +++ b/internal/service/kms/secrets_data_source.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -82,7 +82,7 @@ func dataSourceSecretsRead(ctx context.Context, d *schema.ResourceData, meta any name := tfMap[names.AttrName].(string) // base64 decode the payload - payload, err := itypes.Base64Decode(tfMap["payload"].(string)) + payload, err := inttypes.Base64Decode(tfMap["payload"].(string)) if err != nil { return sdkdiag.AppendErrorf(diags, "invalid base64 value for secret (%s): %s", name, err) } diff --git a/internal/service/kms/secrets_ephemeral.go b/internal/service/kms/secrets_ephemeral.go index cd13fdb70284..abea6bfbad4a 100644 --- a/internal/service/kms/secrets_ephemeral.go +++ b/internal/service/kms/secrets_ephemeral.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/framework" fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -100,7 +100,7 @@ func (e *secretsEphemeralResource) Open(ctx context.Context, request ephemeral.O } input.EncryptionContext = fwflex.ExpandFrameworkStringValueMap(ctx, v.Context) - payload, err := itypes.Base64Decode(v.Payload.ValueString()) + payload, err := inttypes.Base64Decode(v.Payload.ValueString()) if err != nil { response.Diagnostics.AddError( "invalid base64 value for secret", diff --git a/internal/service/lakeformation/exports_test.go b/internal/service/lakeformation/exports_test.go index 67673e8f1da4..10fe80a35a7f 100644 --- a/internal/service/lakeformation/exports_test.go +++ b/internal/service/lakeformation/exports_test.go @@ -19,8 +19,6 @@ var ( ValidPrincipal = validPrincipal - FilterPermissions = filterPermissions - IncludePrincipalIdentifierInList = includePrincipalIdentifierInList FilterCatalogPermissions = filterCatalogPermissions diff --git a/internal/service/lakeformation/filter.go b/internal/service/lakeformation/filter.go index 6d32b7acc982..d99020f93579 100644 --- a/internal/service/lakeformation/filter.go +++ b/internal/service/lakeformation/filter.go @@ -6,17 +6,8 @@ package lakeformation import ( "github.com/aws/aws-sdk-go-v2/aws" awstypes "github.com/aws/aws-sdk-go-v2/service/lakeformation/types" - tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" ) -func filterPermissions(filter PermissionsFilter, allPermissions []awstypes.PrincipalResourcePermissions) []awstypes.PrincipalResourcePermissions { - if filter != nil { - return tfslices.Filter(allPermissions, filter) - } - - return nil -} - func filterCatalogPermissions(principalIdentifier string) PermissionsFilter { return func(permissions awstypes.PrincipalResourcePermissions) bool { return principalIdentifier == aws.ToString(permissions.Principal.DataLakePrincipalIdentifier) && permissions.Resource.Catalog != nil diff --git a/internal/service/lakeformation/filter_test.go b/internal/service/lakeformation/filter_test.go index 738f1913bc76..36797034aa15 100644 --- a/internal/service/lakeformation/filter_test.go +++ b/internal/service/lakeformation/filter_test.go @@ -18,570 +18,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -type tableType string - -const ( - tableTypeTable tableType = "Table" - tableTypeTableWithColumns tableType = "TableWithColumns" -) - -func TestFilterPermissions(t *testing.T) { - t.Parallel() - - // primitives to make test cases easier - accountID := acctest.Ct12Digit - dbName := "Hiliji" - altDBName := "Hiuhbum" - tableName := "Ladocmoc" - - //lintignore:AWSAT005 - principalIdentifier := fmt.Sprintf("arn:aws-us-gov:iam::%s:role/Zepotiz-Bulgaria", accountID) - - principal := &awstypes.DataLakePrincipal{ - DataLakePrincipalIdentifier: aws.String(principalIdentifier), - } - - testCases := []struct { - Name string - Input *lakeformation.ListPermissionsInput - TableType tableType - ColumnNames []string - ExcludedColumnNames []string - ColumnWildcard bool - All []awstypes.PrincipalResourcePermissions - ExpectedClean []awstypes.PrincipalResourcePermissions - }{ - { - Name: "empty", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{}, - }, - All: nil, - ExpectedClean: nil, - }, - { - Name: "emptyWithInput", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - All: nil, - ExpectedClean: nil, - }, - { - Name: "wrongTableResource", // this may not actually be possible but we account for it - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(altDBName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{}, - }, - { - Name: "tableResource", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - }, - { - Name: "tableResourceSelectPerm", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - ColumnWildcard: &awstypes.ColumnWildcard{}, - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - ColumnWildcard: &awstypes.ColumnWildcard{}, - }, - }, - }, - }, - }, - { - Name: "tableResourceSelectPermGrant", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{awstypes.PermissionSelect}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - ColumnWildcard: &awstypes.ColumnWildcard{}, - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter}, - PermissionsWithGrantOption: []awstypes.Permission{awstypes.PermissionAlter}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{awstypes.PermissionSelect}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - ColumnWildcard: &awstypes.ColumnWildcard{}, - }, - }, - }, - }, - }, - { - Name: "twcBasic", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - TableType: tableTypeTableWithColumns, - ColumnNames: []string{names.AttrValue}, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnNames: []string{names.AttrValue}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnNames: []string{"fred"}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnNames: []string{names.AttrValue}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - }, - { - Name: "twcWildcard", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - TableType: tableTypeTableWithColumns, - ColumnWildcard: true, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnWildcard: &awstypes.ColumnWildcard{}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnNames: []string{"fred"}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnWildcard: &awstypes.ColumnWildcard{}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - }, - { - Name: "twcWildcardExcluded", - Input: &lakeformation.ListPermissionsInput{ - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - TableType: tableTypeTableWithColumns, - ColumnWildcard: true, - ExcludedColumnNames: []string{names.AttrValue}, - All: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnWildcard: &awstypes.ColumnWildcard{ - ExcludedColumnNames: []string{names.AttrValue}, - }, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnNames: []string{"fred"}, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - ExpectedClean: []awstypes.PrincipalResourcePermissions{ - { - Permissions: []awstypes.Permission{awstypes.PermissionAlter, awstypes.PermissionDelete}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - Table: &awstypes.TableResource{ - CatalogId: aws.String(accountID), - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - { - Permissions: []awstypes.Permission{awstypes.PermissionSelect}, - PermissionsWithGrantOption: []awstypes.Permission{}, - Principal: principal, - Resource: &awstypes.Resource{ - TableWithColumns: &awstypes.TableWithColumnsResource{ - CatalogId: aws.String(accountID), - ColumnWildcard: &awstypes.ColumnWildcard{ - ExcludedColumnNames: []string{names.AttrValue}, - }, - DatabaseName: aws.String(dbName), - Name: aws.String(tableName), - }, - }, - }, - }, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.Name, func(t *testing.T) { - t.Parallel() - - var filter tflakeformation.PermissionsFilter - if testCase.TableType != tableTypeTableWithColumns { - filter = tflakeformation.FilterTablePermissions(principalIdentifier, testCase.Input.Resource.Table) - } else { - filter = tflakeformation.FilterTableWithColumnsPermissions(principalIdentifier, testCase.Input.Resource.Table, testCase.ColumnNames, testCase.ExcludedColumnNames, testCase.ColumnWildcard) - } - - got := tflakeformation.FilterPermissions(filter, testCase.All) - - if diff := cmp.Diff(got, testCase.ExpectedClean, - cmpopts.IgnoreUnexported(awstypes.PrincipalResourcePermissions{}), - cmpopts.IgnoreUnexported(awstypes.DataLakePrincipal{}), - cmpopts.IgnoreUnexported(awstypes.Resource{}), - cmpopts.IgnoreUnexported(awstypes.TableResource{}), - cmpopts.IgnoreUnexported(awstypes.TableWithColumnsResource{}), - cmpopts.IgnoreUnexported(awstypes.ColumnWildcard{}), - ); diff != "" { - t.Errorf("unexpected diff (+wanted, -got): %s", diff) - } - }) - } -} - func TestFilterTablePermissions(t *testing.T) { t.Parallel() diff --git a/internal/service/lakeformation/permissions.go b/internal/service/lakeformation/permissions.go index a11401937a9e..23d535ec74af 100644 --- a/internal/service/lakeformation/permissions.go +++ b/internal/service/lakeformation/permissions.go @@ -428,48 +428,17 @@ func resourcePermissionsCreate(ctx context.Context, d *schema.ResourceData, meta Principal: &awstypes.DataLakePrincipal{ DataLakePrincipalIdentifier: aws.String(d.Get(names.AttrPrincipal).(string)), }, - Resource: &awstypes.Resource{}, } if v, ok := d.GetOk(names.AttrCatalogID); ok { input.CatalogId = aws.String(v.(string)) } - if v, ok := d.GetOk("data_cells_filter"); ok { - input.Resource.DataCellsFilter = ExpandDataCellsFilter(v.([]any)) - } - if v, ok := d.GetOk("permissions_with_grant_option"); ok { input.PermissionsWithGrantOption = flex.ExpandStringyValueSet[awstypes.Permission](v.(*schema.Set)) } - if _, ok := d.GetOk("catalog_resource"); ok { - input.Resource.Catalog = ExpandCatalogResource() - } - - if v, ok := d.GetOk("data_location"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.DataLocation = ExpandDataLocationResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk(names.AttrDatabase); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Database = ExpandDatabaseResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTag = ExpandLFTagKeyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag_policy"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTagPolicy = ExpandLFTagPolicyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Table = ExpandTableResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.TableWithColumns = expandTableColumnsResource(v.([]any)[0].(map[string]any)) - } + populateResourceForCreate(input, d) var output *lakeformation.GrantPermissionsOutput err := tfresource.Retry(ctx, IAMPropagationTimeout, func(ctx context.Context) *tfresource.RetryError { @@ -498,7 +467,7 @@ func resourcePermissionsCreate(ctx context.Context, d *schema.ResourceData, meta }) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating Lake Formation Permissions (input: %v): %s", input, err) + return sdkdiag.AppendErrorf(diags, "creating Lake Formation Permissions: %s", err) } if output == nil { @@ -514,9 +483,7 @@ func resourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta a var diags diag.Diagnostics conn := meta.(*conns.AWSClient).LakeFormationClient(ctx) - input := lakeformation.ListPermissionsInput{ - Resource: &awstypes.Resource{}, - } + var input lakeformation.ListPermissionsInput principalIdentifier := d.Get(names.AttrPrincipal).(string) if includePrincipalIdentifierInList(principalIdentifier) { @@ -530,42 +497,11 @@ func resourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta a input.CatalogId = aws.String(v.(string)) } - if _, ok := d.GetOk("catalog_resource"); ok { - input.Resource.Catalog = ExpandCatalogResource() - } - - if v, ok := d.GetOk("data_cells_filter"); ok { - input.Resource.DataCellsFilter = ExpandDataCellsFilter(v.([]any)) - } - - if v, ok := d.GetOk("data_location"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.DataLocation = ExpandDataLocationResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk(names.AttrDatabase); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Database = ExpandDatabaseResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTag = ExpandLFTagKeyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag_policy"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTagPolicy = ExpandLFTagPolicyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Table = ExpandTableResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - // can't ListPermissions for TableWithColumns, so use Table instead - input.Resource.Table = ExpandTableWithColumnsResourceAsTable(v.([]any)[0].(map[string]any)) - } + populateResourceForRead(&input, d) filter := permissionsFilter(d) - allPermissions, err := waitPermissionsReady(ctx, conn, &input, filter, principalIdentifier) + permissions, err := waitPermissionsReady(ctx, conn, &input, filter) if !d.IsNewResource() { if errs.IsA[*awstypes.EntityNotFoundException](err) { @@ -580,7 +516,7 @@ func resourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta a return diags } - if len(allPermissions) == 0 { + if len(permissions) == 0 { log.Printf("[WARN] Resource Lake Formation permissions (%s) not found, removing from state (0 permissions)", d.Id()) d.SetId("") return diags @@ -591,69 +527,50 @@ func resourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta a return sdkdiag.AppendErrorf(diags, "reading Lake Formation permissions: %s", err) } - // clean permissions = filter out permissions that do not pertain to this specific resource - cleanPermissions := filterPermissions(filter, allPermissions) + d.Set(names.AttrPrincipal, permissions[0].Principal.DataLakePrincipalIdentifier) + d.Set(names.AttrPermissions, flattenResourcePermissions(permissions)) + d.Set("permissions_with_grant_option", flattenGrantPermissions(permissions)) - if len(cleanPermissions) != len(allPermissions) { - return sdkdiag.AppendErrorf(diags, "Resource Lake Formation clean permissions (%d) and all permissions (%d) have different lengths", len(cleanPermissions), len(allPermissions)) - } - - if len(cleanPermissions) == 0 { - log.Printf("[WARN] No Lake Formation permissions (%s) found", d.Id()) - d.Set("catalog_resource", false) - d.Set("data_location", nil) - d.Set(names.AttrDatabase, nil) - d.Set("lf_tag", nil) - d.Set("lf_tag_policy", nil) - d.Set("table_with_columns", nil) - d.Set("table", nil) - return diags - } - - d.Set(names.AttrPrincipal, cleanPermissions[0].Principal.DataLakePrincipalIdentifier) - d.Set(names.AttrPermissions, flattenResourcePermissions(cleanPermissions)) - d.Set("permissions_with_grant_option", flattenGrantPermissions(cleanPermissions)) - - if cleanPermissions[0].Resource.Catalog != nil { + if permissions[0].Resource.Catalog != nil { d.Set("catalog_resource", true) } else { d.Set("catalog_resource", false) } - if cleanPermissions[0].Resource.DataLocation != nil { - if err := d.Set("data_location", []any{flattenDataLocationResource(cleanPermissions[0].Resource.DataLocation)}); err != nil { + if permissions[0].Resource.DataLocation != nil { + if err := d.Set("data_location", []any{flattenDataLocationResource(permissions[0].Resource.DataLocation)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting data_location: %s", err) } } else { d.Set("data_location", nil) } - if cleanPermissions[0].Resource.Database != nil { - if err := d.Set(names.AttrDatabase, []any{flattenDatabaseResource(cleanPermissions[0].Resource.Database)}); err != nil { + if permissions[0].Resource.Database != nil { + if err := d.Set(names.AttrDatabase, []any{flattenDatabaseResource(permissions[0].Resource.Database)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting database: %s", err) } } else { d.Set(names.AttrDatabase, nil) } - if cleanPermissions[0].Resource.DataCellsFilter != nil { - if err := d.Set("data_cells_filter", flattenDataCellsFilter(cleanPermissions[0].Resource.DataCellsFilter)); err != nil { + if permissions[0].Resource.DataCellsFilter != nil { + if err := d.Set("data_cells_filter", flattenDataCellsFilter(permissions[0].Resource.DataCellsFilter)); err != nil { return sdkdiag.AppendErrorf(diags, "setting data_cells_filter: %s", err) } } else { d.Set("data_cells_filter", nil) } - if cleanPermissions[0].Resource.LFTag != nil { - if err := d.Set("lf_tag", []any{flattenLFTagKeyResource(cleanPermissions[0].Resource.LFTag)}); err != nil { + if permissions[0].Resource.LFTag != nil { + if err := d.Set("lf_tag", []any{flattenLFTagKeyResource(permissions[0].Resource.LFTag)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting database: %s", err) } } else { d.Set("lf_tag", nil) } - if cleanPermissions[0].Resource.LFTagPolicy != nil { - if err := d.Set("lf_tag_policy", []any{flattenLFTagPolicyResource(cleanPermissions[0].Resource.LFTagPolicy)}); err != nil { + if permissions[0].Resource.LFTagPolicy != nil { + if err := d.Set("lf_tag_policy", []any{flattenLFTagPolicyResource(permissions[0].Resource.LFTagPolicy)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting database: %s", err) } } else { @@ -664,7 +581,7 @@ func resourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta a if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 { // since perm list could include TableWithColumns, get the right one - for _, perm := range cleanPermissions { + for _, perm := range permissions { if perm.Resource == nil { continue } @@ -695,7 +612,7 @@ func resourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta a if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 { // since perm list could include Table, get the right one - for _, perm := range cleanPermissions { + for _, perm := range permissions { if perm.Resource.TableWithColumns != nil { if err := d.Set("table_with_columns", []any{flattenTableColumnsResource(perm.Resource.TableWithColumns)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting table_with_columns: %s", err) @@ -723,44 +640,13 @@ func resourcePermissionsDelete(ctx context.Context, d *schema.ResourceData, meta Principal: &awstypes.DataLakePrincipal{ DataLakePrincipalIdentifier: aws.String(d.Get(names.AttrPrincipal).(string)), }, - Resource: &awstypes.Resource{}, } if v, ok := d.GetOk(names.AttrCatalogID); ok { input.CatalogId = aws.String(v.(string)) } - if _, ok := d.GetOk("catalog_resource"); ok { - input.Resource.Catalog = ExpandCatalogResource() - } - - if v, ok := d.GetOk("data_cells_filter"); ok { - input.Resource.DataCellsFilter = ExpandDataCellsFilter(v.([]any)) - } - - if v, ok := d.GetOk("data_location"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.DataLocation = ExpandDataLocationResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk(names.AttrDatabase); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Database = ExpandDatabaseResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTag = ExpandLFTagKeyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag_policy"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTagPolicy = ExpandLFTagPolicyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Table = ExpandTableResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.TableWithColumns = expandTableColumnsResource(v.([]any)[0].(map[string]any)) - } + populateResourceForDelete(input, d) if input.Resource == nil || reflect.DeepEqual(input.Resource, &awstypes.Resource{}) { // if resource is empty, don't delete = it won't delete anything since this is the predicate @@ -884,6 +770,73 @@ func permissionsFilter(d *schema.ResourceData) PermissionsFilter { return nil } +func populateResourceForCreate(input *lakeformation.GrantPermissionsInput, d *schema.ResourceData) { + if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + input.Resource = &awstypes.Resource{ + TableWithColumns: expandTableColumnsResource(v.([]any)[0].(map[string]any)), + } + } else { + input.Resource = expandResource(d) + } +} + +func populateResourceForRead(input *lakeformation.ListPermissionsInput, d *schema.ResourceData) { + if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + // can't ListPermissions for TableWithColumns, so use Table instead + input.Resource = &awstypes.Resource{ + Table: ExpandTableWithColumnsResourceAsTable(v.([]any)[0].(map[string]any)), + } + } else { + input.Resource = expandResource(d) + } +} + +func populateResourceForDelete(input *lakeformation.RevokePermissionsInput, d *schema.ResourceData) { + if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + input.Resource = &awstypes.Resource{ + TableWithColumns: expandTableColumnsResource(v.([]any)[0].(map[string]any)), + } + } else { + input.Resource = expandResource(d) + } +} + +func expandResource(d *schema.ResourceData) *awstypes.Resource { + var resource *awstypes.Resource + + if _, ok := d.GetOk("catalog_resource"); ok { + resource = &awstypes.Resource{ + Catalog: ExpandCatalogResource(), + } + } else if v, ok := d.GetOk("data_cells_filter"); ok { + resource = &awstypes.Resource{ + DataCellsFilter: ExpandDataCellsFilter(v.([]any)), + } + } else if v, ok := d.GetOk("data_location"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + resource = &awstypes.Resource{ + DataLocation: ExpandDataLocationResource(v.([]any)[0].(map[string]any)), + } + } else if v, ok := d.GetOk(names.AttrDatabase); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + resource = &awstypes.Resource{ + Database: ExpandDatabaseResource(v.([]any)[0].(map[string]any)), + } + } else if v, ok := d.GetOk("lf_tag"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + resource = &awstypes.Resource{ + LFTag: ExpandLFTagKeyResource(v.([]any)[0].(map[string]any)), + } + } else if v, ok := d.GetOk("lf_tag_policy"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + resource = &awstypes.Resource{ + LFTagPolicy: ExpandLFTagPolicyResource(v.([]any)[0].(map[string]any)), + } + } else if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { + resource = &awstypes.Resource{ + Table: ExpandTableResource(v.([]any)[0].(map[string]any)), + } + } + + return resource +} + func ExpandCatalogResource() *awstypes.CatalogResource { return &awstypes.CatalogResource{} } diff --git a/internal/service/lakeformation/permissions_data_source.go b/internal/service/lakeformation/permissions_data_source.go index 957658e21747..71d606c1c4d6 100644 --- a/internal/service/lakeformation/permissions_data_source.go +++ b/internal/service/lakeformation/permissions_data_source.go @@ -278,9 +278,7 @@ func dataSourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta var diags diag.Diagnostics conn := meta.(*conns.AWSClient).LakeFormationClient(ctx) - input := lakeformation.ListPermissionsInput{ - Resource: &awstypes.Resource{}, - } + var input lakeformation.ListPermissionsInput principalIdentifier := d.Get(names.AttrPrincipal).(string) if includePrincipalIdentifierInList(principalIdentifier) { @@ -294,42 +292,11 @@ func dataSourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta input.CatalogId = aws.String(v.(string)) } - if _, ok := d.GetOk("catalog_resource"); ok { - input.Resource.Catalog = ExpandCatalogResource() - } - - if v, ok := d.GetOk("data_cells_filter"); ok { - input.Resource.DataCellsFilter = ExpandDataCellsFilter(v.([]any)) - } - - if v, ok := d.GetOk("data_location"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.DataLocation = ExpandDataLocationResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk(names.AttrDatabase); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Database = ExpandDatabaseResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTag = ExpandLFTagKeyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("lf_tag_policy"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.LFTagPolicy = ExpandLFTagPolicyResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - input.Resource.Table = ExpandTableResource(v.([]any)[0].(map[string]any)) - } - - if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 && v.([]any)[0] != nil { - // can't ListPermissions for TableWithColumns, so use Table instead - input.Resource.Table = ExpandTableWithColumnsResourceAsTable(v.([]any)[0].(map[string]any)) - } + populateResourceForRead(&input, d) filter := permissionsFilter(d) - allPermissions, err := waitPermissionsReady(ctx, conn, &input, filter, principalIdentifier) + permissions, err := waitPermissionsReady(ctx, conn, &input, filter) d.SetId(strconv.Itoa(create.StringHashcode(prettify(input)))) @@ -337,57 +304,50 @@ func dataSourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta return sdkdiag.AppendErrorf(diags, "reading Lake Formation permissions: %s", err) } - // clean permissions = filter out permissions that do not pertain to this specific resource - cleanPermissions := filterPermissions(filter, allPermissions) - - if len(cleanPermissions) != len(allPermissions) { - return sdkdiag.AppendErrorf(diags, "Resource Lake Formation clean permissions (%d) and all permissions (%d) have different lengths", len(cleanPermissions), len(allPermissions)) - } - - d.Set(names.AttrPrincipal, cleanPermissions[0].Principal.DataLakePrincipalIdentifier) - d.Set(names.AttrPermissions, flattenResourcePermissions(cleanPermissions)) - d.Set("permissions_with_grant_option", flattenGrantPermissions(cleanPermissions)) + d.Set(names.AttrPrincipal, permissions[0].Principal.DataLakePrincipalIdentifier) + d.Set(names.AttrPermissions, flattenResourcePermissions(permissions)) + d.Set("permissions_with_grant_option", flattenGrantPermissions(permissions)) - if cleanPermissions[0].Resource.Catalog != nil { + if permissions[0].Resource.Catalog != nil { d.Set("catalog_resource", true) } else { d.Set("catalog_resource", false) } - if cleanPermissions[0].Resource.DataLocation != nil { - if err := d.Set("data_location", []any{flattenDataLocationResource(cleanPermissions[0].Resource.DataLocation)}); err != nil { // nosemgrep:ci.data-source-with-resource-read + if permissions[0].Resource.DataLocation != nil { + if err := d.Set("data_location", []any{flattenDataLocationResource(permissions[0].Resource.DataLocation)}); err != nil { // nosemgrep:ci.data-source-with-resource-read return sdkdiag.AppendErrorf(diags, "setting data_location: %s", err) } } else { d.Set("data_location", nil) } - if cleanPermissions[0].Resource.DataCellsFilter != nil { - if err := d.Set("data_cells_filter", flattenDataCellsFilter(cleanPermissions[0].Resource.DataCellsFilter)); err != nil { + if permissions[0].Resource.DataCellsFilter != nil { + if err := d.Set("data_cells_filter", flattenDataCellsFilter(permissions[0].Resource.DataCellsFilter)); err != nil { return sdkdiag.AppendErrorf(diags, "setting data_cells_filter: %s", err) } } else { d.Set("data_cells_filter", nil) } - if cleanPermissions[0].Resource.Database != nil { - if err := d.Set(names.AttrDatabase, []any{flattenDatabaseResource(cleanPermissions[0].Resource.Database)}); err != nil { // nosemgrep:ci.data-source-with-resource-read + if permissions[0].Resource.Database != nil { + if err := d.Set(names.AttrDatabase, []any{flattenDatabaseResource(permissions[0].Resource.Database)}); err != nil { // nosemgrep:ci.data-source-with-resource-read return sdkdiag.AppendErrorf(diags, "setting database: %s", err) } } else { d.Set(names.AttrDatabase, nil) } - if cleanPermissions[0].Resource.LFTag != nil { - if err := d.Set("lf_tag", []any{flattenLFTagKeyResource(cleanPermissions[0].Resource.LFTag)}); err != nil { // nosemgrep:ci.data-source-with-resource-read + if permissions[0].Resource.LFTag != nil { + if err := d.Set("lf_tag", []any{flattenLFTagKeyResource(permissions[0].Resource.LFTag)}); err != nil { // nosemgrep:ci.data-source-with-resource-read return sdkdiag.AppendErrorf(diags, "setting LF-tag: %s", err) } } else { d.Set("lf_tag", nil) } - if cleanPermissions[0].Resource.LFTagPolicy != nil { - if err := d.Set("lf_tag_policy", []any{flattenLFTagPolicyResource(cleanPermissions[0].Resource.LFTagPolicy)}); err != nil { // nosemgrep:ci.data-source-with-resource-read + if permissions[0].Resource.LFTagPolicy != nil { + if err := d.Set("lf_tag_policy", []any{flattenLFTagPolicyResource(permissions[0].Resource.LFTagPolicy)}); err != nil { // nosemgrep:ci.data-source-with-resource-read return sdkdiag.AppendErrorf(diags, "setting LF-tag policy: %s", err) } } else { @@ -398,7 +358,7 @@ func dataSourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta if v, ok := d.GetOk("table"); ok && len(v.([]any)) > 0 { // since perm list could include TableWithColumns, get the right one - for _, perm := range cleanPermissions { + for _, perm := range permissions { if perm.Resource == nil { continue } @@ -429,7 +389,7 @@ func dataSourcePermissionsRead(ctx context.Context, d *schema.ResourceData, meta if v, ok := d.GetOk("table_with_columns"); ok && len(v.([]any)) > 0 { // since perm list could include Table, get the right one - for _, perm := range cleanPermissions { + for _, perm := range permissions { if perm.Resource.TableWithColumns != nil { if err := d.Set("table_with_columns", []any{flattenTableColumnsResource(perm.Resource.TableWithColumns)}); err != nil { // nosemgrep:ci.data-source-with-resource-read return sdkdiag.AppendErrorf(diags, "setting table_with_columns: %s", err) diff --git a/internal/service/lakeformation/permissions_test.go b/internal/service/lakeformation/permissions_test.go index 3b78cca453c3..1fecfd0cdf73 100644 --- a/internal/service/lakeformation/permissions_test.go +++ b/internal/service/lakeformation/permissions_test.go @@ -6,7 +6,6 @@ package lakeformation_test import ( "context" "fmt" - "reflect" "strconv" "testing" @@ -1114,6 +1113,29 @@ func permissionCountForResource(ctx context.Context, conn *lakeformation.Client, noResource = false } + if v, ok := rs.Primary.Attributes["data_cells_filter.#"]; ok && v != "" && v != "0" { + tfMap := map[string]any{} + + if v := rs.Primary.Attributes["data_cells_filter.0.database_name"]; v != "" { + tfMap[names.AttrDatabaseName] = v + } + + if v := rs.Primary.Attributes["data_cells_filter.0.name"]; v != "" { + tfMap[names.AttrName] = v + } + + if v := rs.Primary.Attributes["data_cells_filter.0.table_catalog_id"]; v != "" { + tfMap["table_catalog_id"] = v + } + + if v := rs.Primary.Attributes["data_cells_filter.0.table_name"]; v != "" { + tfMap[names.AttrTableName] = v + } + + input.Resource.DataCellsFilter = tflakeformation.ExpandDataCellsFilter([]any{tfMap}) + noResource = false + } + if v, ok := rs.Primary.Attributes["data_location.#"]; ok && v != "" && v != "0" { tfMap := map[string]any{} @@ -1252,29 +1274,6 @@ func permissionCountForResource(ctx context.Context, conn *lakeformation.Client, noResource = false } - if v, ok := rs.Primary.Attributes["data_cells_filter.#"]; ok && v != "" && v != "0" { - tfMap := map[string]any{} - - if v := rs.Primary.Attributes["data_cells_filter.0.database_name"]; v != "" { - tfMap[names.AttrDatabaseName] = v - } - - if v := rs.Primary.Attributes["data_cells_filter.0.name"]; v != "" { - tfMap[names.AttrName] = v - } - - if v := rs.Primary.Attributes["data_cells_filter.0.table_catalog_id"]; v != "" { - tfMap["table_catalog_id"] = v - } - - if v := rs.Primary.Attributes["data_cells_filter.0.table_name"]; v != "" { - tfMap[names.AttrTableName] = v - } - - input.Resource.DataCellsFilter = tflakeformation.ExpandDataCellsFilter([]any{tfMap}) - noResource = false - } - if noResource { // if after read, there is no resource, it has been deleted return 0, nil @@ -1285,11 +1284,10 @@ func permissionCountForResource(ctx context.Context, conn *lakeformation.Client, return 0, fmt.Errorf("acceptance test: error creating permissions filter for (%s): %w", rs.Primary.ID, err) } - var allPermissions []awstypes.PrincipalResourcePermissions + var permissions []awstypes.PrincipalResourcePermissions err = tfresource.Retry(ctx, tflakeformation.IAMPropagationTimeout, func(ctx context.Context) *tfresource.RetryError { pages := lakeformation.NewListPermissionsPaginator(conn, input) - for pages.HasMorePages() { page, err := pages.NextPage(ctx) @@ -1310,11 +1308,9 @@ func permissionCountForResource(ctx context.Context, conn *lakeformation.Client, } for _, permission := range page.PrincipalResourcePermissions { - if reflect.ValueOf(permission).IsZero() { - continue + if filter(permission) { + permissions = append(permissions, permission) } - - allPermissions = append(allPermissions, permission) } } @@ -1331,13 +1327,10 @@ func permissionCountForResource(ctx context.Context, conn *lakeformation.Client, } if err != nil { - return 0, fmt.Errorf("acceptance test: error listing Lake Formation permissions after retry %v: %w", input, err) + return 0, fmt.Errorf("acceptance test: error listing Lake Formation permissions: %w", err) } - // clean permissions = filter out permissions that do not pertain to this specific resource - cleanPermissions := tflakeformation.FilterPermissions(filter, allPermissions) - - return len(cleanPermissions), nil + return len(permissions), nil } func permissionsFilter(attributes map[string]string) (tflakeformation.PermissionsFilter, error) { diff --git a/internal/service/lakeformation/status.go b/internal/service/lakeformation/status.go index 07b9a64c2e6c..4345583fb36e 100644 --- a/internal/service/lakeformation/status.go +++ b/internal/service/lakeformation/status.go @@ -6,16 +6,14 @@ package lakeformation import ( "context" "fmt" - "reflect" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/lakeformation" awstypes "github.com/aws/aws-sdk-go-v2/service/lakeformation/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-provider-aws/internal/errs" ) -func statusPermissions(ctx context.Context, conn *lakeformation.Client, input *lakeformation.ListPermissionsInput, filter PermissionsFilter, principalIdentifier string) retry.StateRefreshFunc { +func statusPermissions(ctx context.Context, conn *lakeformation.Client, input *lakeformation.ListPermissionsInput, filter PermissionsFilter) retry.StateRefreshFunc { return func() (any, string, error) { var permissions []awstypes.PrincipalResourcePermissions @@ -24,7 +22,7 @@ func statusPermissions(ctx context.Context, conn *lakeformation.Client, input *l page, err := pages.NextPage(ctx) if errs.IsA[*awstypes.EntityNotFoundException](err) { - return nil, statusNotFound, err + return nil, "", nil } if errs.IsAErrorMessageContains[*awstypes.InvalidInputException](err, "Invalid principal") { @@ -32,27 +30,18 @@ func statusPermissions(ctx context.Context, conn *lakeformation.Client, input *l } if err != nil { - return nil, statusFailed, fmt.Errorf("listing permissions: %w", err) + return nil, "", fmt.Errorf("listing permissions: %w", err) } for _, permission := range page.PrincipalResourcePermissions { - if reflect.ValueOf(permission).IsZero() { - continue + if filter(permission) { + permissions = append(permissions, permission) } - - if principalIdentifier != aws.ToString(permission.Principal.DataLakePrincipalIdentifier) { - continue - } - - permissions = append(permissions, permission) } } - // clean permissions = filter out permissions that do not pertain to this specific resource - cleanPermissions := filterPermissions(filter, permissions) - - if len(cleanPermissions) == 0 { - return nil, statusNotFound, nil + if len(permissions) == 0 { + return nil, "", nil } return permissions, statusAvailable, nil diff --git a/internal/service/lakeformation/wait.go b/internal/service/lakeformation/wait.go index 2a302517ea5c..7e1185567352 100644 --- a/internal/service/lakeformation/wait.go +++ b/internal/service/lakeformation/wait.go @@ -17,16 +17,14 @@ const ( permissionsDeleteRetryTimeout = 30 * time.Second statusAvailable = "AVAILABLE" - statusNotFound = "NOT FOUND" - statusFailed = "FAILED" statusIAMDelay = "IAM DELAY" ) -func waitPermissionsReady(ctx context.Context, conn *lakeformation.Client, input *lakeformation.ListPermissionsInput, filter PermissionsFilter, principalIdentifier string) ([]awstypes.PrincipalResourcePermissions, error) { +func waitPermissionsReady(ctx context.Context, conn *lakeformation.Client, input *lakeformation.ListPermissionsInput, filter PermissionsFilter) ([]awstypes.PrincipalResourcePermissions, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{statusNotFound, statusIAMDelay}, + Pending: []string{statusIAMDelay}, Target: []string{statusAvailable}, - Refresh: statusPermissions(ctx, conn, input, filter, principalIdentifier), + Refresh: statusPermissions(ctx, conn, input, filter), Timeout: permissionsReadyTimeout, } diff --git a/internal/service/lambda/exports_test.go b/internal/service/lambda/exports_test.go index 4b6488686d57..ad51b08b69a7 100644 --- a/internal/service/lambda/exports_test.go +++ b/internal/service/lambda/exports_test.go @@ -35,6 +35,7 @@ var ( LayerVersionParseResourceID = layerVersionParseResourceID LayerVersionPermissionParseResourceID = layerVersionPermissionParseResourceID SignerServiceIsAvailable = signerServiceIsAvailable + InvocationParseResourceID = invocationParseResourceID ValidFunctionName = validFunctionName ValidPermissionAction = validPermissionAction diff --git a/internal/service/lambda/function_data_source_tags_gen_test.go b/internal/service/lambda/function_data_source_tags_gen_test.go index a5ae81c88a78..cf9fd5acd538 100644 --- a/internal/service/lambda/function_data_source_tags_gen_test.go +++ b/internal/service/lambda/function_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tflambda "github.com/hashicorp/terraform-provider-aws/internal/service/lambda" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccLambdaFunctionDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *test } func expectFullFunctionDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tflambda.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tflambda.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/lambda/invocation.go b/internal/service/lambda/invocation.go index 4740e9df5a72..d13e63c8b8c4 100644 --- a/internal/service/lambda/invocation.go +++ b/internal/service/lambda/invocation.go @@ -12,6 +12,7 @@ import ( "log" "strings" + "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/lambda" awstypes "github.com/aws/aws-sdk-go-v2/service/lambda/types" @@ -22,9 +23,14 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/names" ) +const ( + invocationResourceIDPartCount = 3 +) + // @SDKResource("aws_lambda_invocation", name="Invocation") func resourceInvocation() *schema.Resource { return &schema.Resource{ @@ -41,6 +47,19 @@ func resourceInvocation() *schema.Resource { Version: 0, }, }, + Importer: &schema.ResourceImporter{ + StateContext: func(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { + functionName, qualifier, _, err := invocationParseResourceID(d.Id()) + if err != nil { + return nil, err + } + + d.Set("function_name", functionName) + d.Set("qualifier", qualifier) + + return []*schema.ResourceData{d}, nil + }, + }, Schema: map[string]*schema.Schema{ "function_name": { @@ -205,7 +224,13 @@ func invoke(ctx context.Context, conn *lambda.Client, d *schema.ResourceData, ac return sdkdiag.AppendErrorf(diags, "invoking Lambda Function (%s): %s", functionName, string(output.Payload)) } - d.SetId(fmt.Sprintf("%s_%s_%x", functionName, qualifier, md5.Sum(payload))) + resultHash := fmt.Sprintf("%x", md5.Sum(payload)) + id, err := flex.FlattenResourceId([]string{functionName, qualifier, resultHash}, invocationResourceIDPartCount, false) + if err != nil { + return sdkdiag.AppendFromErr(diags, err) + } + + d.SetId(id) d.Set("result", string(output.Payload)) return diags @@ -248,3 +273,26 @@ func customizeDiffInputChangeWithCRUDScope(_ context.Context, diff *schema.Resou } return nil } + +func invocationParseResourceID(id string) (string, string, string, error) { + parts, err := flex.ExpandResourceId(id, invocationResourceIDPartCount, false) + if err != nil { + return "", "", "", err + } + + functionName := parts[0] + qualifier := parts[1] + resultHash := parts[2] + + // Validate qualifier format + if qualifier != "$LATEST" && !regexache.MustCompile(`^[0-9]+$`).MatchString(qualifier) { + return "", "", "", fmt.Errorf("invalid qualifier format: %s, expected $LATEST or numeric version", qualifier) + } + + // Validate hash format (should be MD5 - 32 hex chars) + if !regexache.MustCompile(`^[a-f0-9]{32}$`).MatchString(resultHash) { + return "", "", "", fmt.Errorf("invalid result hash format: %s, expected 32-character MD5 hash", resultHash) + } + + return functionName, qualifier, resultHash, nil +} diff --git a/internal/service/lambda/invocation_test.go b/internal/service/lambda/invocation_test.go index 6640b8a62e01..2ef85ff8cf52 100644 --- a/internal/service/lambda/invocation_test.go +++ b/internal/service/lambda/invocation_test.go @@ -16,10 +16,89 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + tflambda "github.com/hashicorp/terraform-provider-aws/internal/service/lambda" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) +func TestParseRecordID(t *testing.T) { + t.Parallel() + + cases := []struct { + Input string + FunctionName, Qualifier, ResultHash string + ExpectError bool + }{ + // Invalid cases + {"ABCDEF", "", "", "", true}, + {"ABCDEF,42", "", "", "", true}, + {"ABCDEF,,", "", "", "", true}, + {"ABCDEF,invalid_qualifier,b326b5062b2f0e69046810717534cb09", "", "", "", true}, + {"ABCDEF,42,invalid_hash", "", "", "", true}, + // Valid cases + {"ABCDEF,42,b326b5062b2f0e69046810717534cb09", "ABCDEF", "42", "b326b5062b2f0e69046810717534cb09", false}, + {"ABC_DEF,42,b326b5062b2f0e69046810717534cb09", "ABC_DEF", "42", "b326b5062b2f0e69046810717534cb09", false}, + {"ABCDEF,$LATEST,b326b5062b2f0e69046810717534cb09", "ABCDEF", "$LATEST", "b326b5062b2f0e69046810717534cb09", false}, + {"ABC_DEF,$LATEST,b326b5062b2f0e69046810717534cb09", "ABC_DEF", "$LATEST", "b326b5062b2f0e69046810717534cb09", false}, + {"ABC_DEF_1234,567,b326b5062b2f0e69046810717534cb09", "ABC_DEF_1234", "567", "b326b5062b2f0e69046810717534cb09", false}, + } + + for _, tc := range cases { + t.Run(tc.Input, func(t *testing.T) { + t.Parallel() + + functionName, qualifier, resultHash, err := tflambda.InvocationParseResourceID(tc.Input) + + if tc.ExpectError { + if err == nil { + t.Fatalf("expected error for input: %s", tc.Input) + } + return + } + + if err != nil { + t.Fatalf("unexpected error for input %s: %v", tc.Input, err) + } + + if functionName != tc.FunctionName { + t.Fatalf("input: %s\nfunction_name: %s\nexpected:%s", tc.Input, functionName, tc.FunctionName) + } + if qualifier != tc.Qualifier { + t.Fatalf("input: %s\nqualifier: %s\nexpected:%s", tc.Input, qualifier, tc.Qualifier) + } + if resultHash != tc.ResultHash { + t.Fatalf("input: %s\nresult: %s\nexpected:%s", tc.Input, resultHash, tc.ResultHash) + } + }) + } +} + +func TestInvocationResourceIDCreation(t *testing.T) { + t.Parallel() + + functionName := "my_test_function" + qualifier := "$LATEST" + resultHash := "b326b5062b2f0e69046810717534cb09" + + expectedID := "my_test_function,$LATEST,b326b5062b2f0e69046810717534cb09" + + // Test parsing the expected ID format + parsedFunctionName, parsedQualifier, parsedResultHash, err := tflambda.InvocationParseResourceID(expectedID) + if err != nil { + t.Fatalf("unexpected error parsing resource ID: %v", err) + } + + if parsedFunctionName != functionName { + t.Fatalf("expected function name: %s, got: %s", functionName, parsedFunctionName) + } + if parsedQualifier != qualifier { + t.Fatalf("expected qualifier: %s, got: %s", qualifier, parsedQualifier) + } + if parsedResultHash != resultHash { + t.Fatalf("expected result hash: %s, got: %s", resultHash, parsedResultHash) + } +} + func TestAccLambdaInvocation_basic(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_lambda_invocation.test" @@ -44,6 +123,12 @@ func TestAccLambdaInvocation_basic(t *testing.T) { testAccCheckInvocationResult(resourceName, resultJSON), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"input", "lifecycle_scope", "result", "terraform_key"}, + }, }, }) } @@ -66,6 +151,12 @@ func TestAccLambdaInvocation_qualifier(t *testing.T) { testAccCheckInvocationResult(resourceName, `{"key1":"value1","key2":"value2","key3":"`+testData+`"}`), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"input", "lifecycle_scope", "result", "terraform_key"}, + }, }, }) } @@ -153,6 +244,12 @@ func TestAccLambdaInvocation_lifecycle_scopeCRUDCreate(t *testing.T) { testAccCheckInvocationResult(resourceName, resultJSON), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"input", "lifecycle_scope", "result", "terraform_key"}, + }, }, }) } diff --git a/internal/service/lightsail/key_pair.go b/internal/service/lightsail/key_pair.go index 09ca4901a054..a53932d69432 100644 --- a/internal/service/lightsail/key_pair.go +++ b/internal/service/lightsail/key_pair.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/vault/helper/pgpkeys" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -253,7 +253,7 @@ func encryptValue(encryptionKey, value, description string) (string, string, err return "", "", fmt.Errorf("encrypting %s: %w", description, err) } - return fingerprints[0], itypes.Base64Encode(encryptedValue[0]), nil + return fingerprints[0], inttypes.Base64Encode(encryptedValue[0]), nil } func FindKeyPairById(ctx context.Context, conn *lightsail.Client, id string) (*types.KeyPair, error) { diff --git a/internal/service/lightsail/tags.go b/internal/service/lightsail/tags.go index b596f95d8781..b32fd9efea16 100644 --- a/internal/service/lightsail/tags.go +++ b/internal/service/lightsail/tags.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build !generate -// +build !generate package lightsail diff --git a/internal/service/logs/delivery_destination.go b/internal/service/logs/delivery_destination.go index 9c83ed94cc37..79ccd9cb2ec9 100644 --- a/internal/service/logs/delivery_destination.go +++ b/internal/service/logs/delivery_destination.go @@ -50,6 +50,7 @@ func (r *deliveryDestinationResource) Schema(ctx context.Context, request resour names.AttrARN: framework.ARNAttributeComputedOnly(), "delivery_destination_type": schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.DeliveryDestinationType](), + Optional: true, Computed: true, }, names.AttrName: schema.StringAttribute{ @@ -75,15 +76,13 @@ func (r *deliveryDestinationResource) Schema(ctx context.Context, request resour "delivery_destination_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[deliveryDestinationConfigurationModel](ctx), Validators: []validator.List{ - listvalidator.IsRequired(), - listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "destination_resource_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, - Required: true, + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplaceIf(requiresReplaceIfARNServiceChanges, "", ""), }, @@ -95,6 +94,34 @@ func (r *deliveryDestinationResource) Schema(ctx context.Context, request resour } } +func (r *deliveryDestinationResource) ValidateConfig(ctx context.Context, request resource.ValidateConfigRequest, response *resource.ValidateConfigResponse) { + var data deliveryDestinationResourceModel + response.Diagnostics.Append(request.Config.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + isXray := !data.DeliveryDestinationType.IsNull() && !data.DeliveryDestinationType.IsUnknown() && + data.DeliveryDestinationType.ValueString() == string(awstypes.DeliveryDestinationTypeXray) + hasConfig := !data.DeliveryDestinationConfiguration.IsNull() && !data.DeliveryDestinationConfiguration.IsUnknown() + + if isXray && hasConfig { + response.Diagnostics.AddAttributeError( + path.Root("delivery_destination_configuration"), + "Invalid Configuration", + "delivery_destination_configuration must not be set when delivery_destination_type is XRAY", + ) + } + + if !isXray && !hasConfig && !data.DeliveryDestinationType.IsUnknown() && !data.DeliveryDestinationConfiguration.IsUnknown() { + response.Diagnostics.AddAttributeError( + path.Root("delivery_destination_configuration"), + "Missing Configuration", + "delivery_destination_configuration is required when delivery_destination_type is not XRAY", + ) + } +} + func (r *deliveryDestinationResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { var data deliveryDestinationResourceModel response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) @@ -152,6 +179,13 @@ func (r *deliveryDestinationResource) Read(ctx context.Context, request resource return } + // Handle empty destination_resource_arn for XRAY type destinations + // Clear it before flattening to avoid ARN validation error + if output.DeliveryDestinationConfiguration != nil && + aws.ToString(output.DeliveryDestinationConfiguration.DestinationResourceArn) == "" { + output.DeliveryDestinationConfiguration = nil + } + // Set attributes for import. response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) if response.Diagnostics.HasError() { diff --git a/internal/service/logs/delivery_destination_test.go b/internal/service/logs/delivery_destination_test.go index 3d1decbcf100..981e2bd742ee 100644 --- a/internal/service/logs/delivery_destination_test.go +++ b/internal/service/logs/delivery_destination_test.go @@ -90,6 +90,47 @@ func TestAccLogsDeliveryDestination_disappears(t *testing.T) { }) } +func TestAccLogsDeliveryDestination_XRAY(t *testing.T) { + ctx := acctest.Context(t) + var v awstypes.DeliveryDestination + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + resourceName := "aws_cloudwatch_log_delivery_destination.test" + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.LogsServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDeliveryDestinationDestroy(ctx, t), + Steps: []resource.TestStep{ + { + Config: testAccDeliveryDestinationConfig_xray(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDeliveryDestinationExists(ctx, t, resourceName, &v), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("delivery_destination_type"), knownvalue.StringExact("XRAY")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rName)), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccDeliveryDestinationImportStateIDFunc(resourceName), + ImportStateVerifyIdentifierAttribute: names.AttrName, + }, + }, + }) +} + func TestAccLogsDeliveryDestination_tags(t *testing.T) { ctx := acctest.Context(t) var v awstypes.DeliveryDestination @@ -456,6 +497,15 @@ resource "aws_cloudwatch_log_delivery_destination" "test" { `, rName) } +func testAccDeliveryDestinationConfig_xray(rName string) string { + return fmt.Sprintf(` +resource "aws_cloudwatch_log_delivery_destination" "test" { + name = %[1]q + delivery_destination_type = "XRAY" +} +`, rName) +} + func testAccDeliveryDestinationConfig_tags1(rName, tag1Key, tag1Value string) string { return fmt.Sprintf(` resource "aws_cloudwatch_log_group" "test" { diff --git a/internal/service/medialive/input_data_source_tags_gen_test.go b/internal/service/medialive/input_data_source_tags_gen_test.go index d361e3b96b44..9b423bafc2a1 100644 --- a/internal/service/medialive/input_data_source_tags_gen_test.go +++ b/internal/service/medialive/input_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfmedialive "github.com/hashicorp/terraform-provider-aws/internal/service/medialive" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccMediaLiveInputDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *test } func expectFullInputDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfmedialive.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfmedialive.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/neptune/cluster.go b/internal/service/neptune/cluster.go index 0e6ef2e0d1f3..6ee9bfad424e 100644 --- a/internal/service/neptune/cluster.go +++ b/internal/service/neptune/cluster.go @@ -29,7 +29,7 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -901,7 +901,7 @@ func statusDBCluster(ctx context.Context, conn *neptune.Client, id string, waitN status := aws.ToString(output.Status) - if status == clusterStatusAvailable && waitNoPendingModifiedValues && !itypes.IsZero(output.PendingModifiedValues) { + if status == clusterStatusAvailable && waitNoPendingModifiedValues && !inttypes.IsZero(output.PendingModifiedValues) { status = clusterStatusAvailableWithPendingModifiedValues } diff --git a/internal/service/networkflowmonitor/exports_test.go b/internal/service/networkflowmonitor/exports_test.go new file mode 100644 index 000000000000..458b6ede9dfa --- /dev/null +++ b/internal/service/networkflowmonitor/exports_test.go @@ -0,0 +1,13 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor + +// Exports for use in tests only. +var ( + ResourceMonitor = newMonitorResource + ResourceScope = newScopeResource + + FindMonitorByName = findMonitorByName + FindScopeByID = findScopeByID +) diff --git a/internal/service/networkflowmonitor/generate.go b/internal/service/networkflowmonitor/generate.go index ef406938b6b1..4bf50c2009ed 100644 --- a/internal/service/networkflowmonitor/generate.go +++ b/internal/service/networkflowmonitor/generate.go @@ -3,7 +3,6 @@ //go:generate go run ../../generate/servicepackage/main.go //go:generate go run ../../generate/tags/main.go -KVTValues -ServiceTagsMap -ListTags -UpdateTags -//go:generate go run ../../generate/tagstests/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. package networkflowmonitor diff --git a/internal/service/networkflowmonitor/monitor.go b/internal/service/networkflowmonitor/monitor.go new file mode 100644 index 000000000000..2190ea80191f --- /dev/null +++ b/internal/service/networkflowmonitor/monitor.go @@ -0,0 +1,418 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor + +import ( + "context" + "fmt" + "time" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor" + awstypes "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor/types" + set "github.com/hashicorp/go-set/v3" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_networkflowmonitor_monitor", name="Monitor") +// @Tags(identifierAttribute="monitor_arn") +func newMonitorResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &monitorResource{} + + r.SetDefaultCreateTimeout(30 * time.Minute) + r.SetDefaultUpdateTimeout(30 * time.Minute) + r.SetDefaultDeleteTimeout(30 * time.Minute) + + return r, nil +} + +type monitorResource struct { + framework.ResourceWithModel[monitorResourceModel] + framework.WithTimeouts +} + +func (r *monitorResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "monitor_arn": framework.ARNAttributeComputedOnly(), + "monitor_name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 255), + stringvalidator.RegexMatches(regexache.MustCompile(`[a-zA-Z0-9_.-]+`), ""), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "scope_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + "local_resource": schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[monitorLocalResourceModel](ctx), + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.IsRequired(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrIdentifier: schema.StringAttribute{ + Required: true, + }, + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.MonitorLocalResourceType](), + Required: true, + }, + }, + }, + }, + "remote_resource": schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[monitorRemoteResourceModel](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrIdentifier: schema.StringAttribute{ + Required: true, + }, + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.MonitorRemoteResourceType](), + Required: true, + }, + }, + }, + }, + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), + }, + } +} + +func (r *monitorResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data monitorResourceModel + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + var input networkflowmonitor.CreateMonitorInput + response.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...) + if response.Diagnostics.HasError() { + return + } + + // Additional fields. + uuid, _ := uuid.GenerateUUID() + input.ClientToken = aws.String(uuid) + input.Tags = getTagsIn(ctx) + + output, err := conn.CreateMonitor(ctx, &input) + + if err != nil { + response.Diagnostics.AddError("creating Network Flow Monitor Monitor", err.Error()) + return + } + + // Set values for unknowns. + data.MonitorARN = fwflex.StringToFramework(ctx, output.MonitorArn) + + monitorName := fwflex.StringValueFromFramework(ctx, data.MonitorName) + if _, err := waitMonitorCreated(ctx, conn, monitorName, r.CreateTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Network Flow Monitor Monitor (%s) create", monitorName), err.Error()) + return + } + + response.Diagnostics.Append(response.State.Set(ctx, data)...) +} + +func (r *monitorResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data monitorResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + monitorName := fwflex.StringValueFromFramework(ctx, data.MonitorName) + output, err := findMonitorByName(ctx, conn, monitorName) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Network Flow Monitor Monitor (%s)", monitorName), err.Error()) + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + setTagsOut(ctx, output.Tags) + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *monitorResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var old, new monitorResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &old)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(request.Plan.Get(ctx, &new)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + diff, d := fwflex.Diff(ctx, new, old) + response.Diagnostics.Append(d...) + if response.Diagnostics.HasError() { + return + } + + if diff.HasChanges() { + var oldLocalResources, newLocalResources []awstypes.MonitorLocalResource + response.Diagnostics.Append(fwflex.Expand(ctx, old.LocalResources, &oldLocalResources)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(fwflex.Expand(ctx, new.LocalResources, &newLocalResources)...) + if response.Diagnostics.HasError() { + return + } + + hashLocalResource := func(v awstypes.MonitorLocalResource) string { + return string(v.Type) + ":" + aws.ToString(v.Identifier) + } + osLocalResource, nsLocalResource := set.HashSetFromFunc(oldLocalResources, hashLocalResource), set.HashSetFromFunc(newLocalResources, hashLocalResource) + + var oldRemoteResources, newRemoteResources []awstypes.MonitorRemoteResource + response.Diagnostics.Append(fwflex.Expand(ctx, old.RemoteResources, &oldRemoteResources)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(fwflex.Expand(ctx, new.RemoteResources, &newRemoteResources)...) + if response.Diagnostics.HasError() { + return + } + + hashRemoteResource := func(v awstypes.MonitorRemoteResource) string { + return string(v.Type) + ":" + aws.ToString(v.Identifier) + } + osRemoteResource, nsRemoteResource := set.HashSetFromFunc(oldRemoteResources, hashRemoteResource), set.HashSetFromFunc(newRemoteResources, hashRemoteResource) + + monitorName := fwflex.StringValueFromFramework(ctx, new.MonitorName) + input := networkflowmonitor.UpdateMonitorInput{ + LocalResourcesToAdd: nsLocalResource.Difference(osLocalResource).Slice(), + LocalResourcesToRemove: osLocalResource.Difference(nsLocalResource).Slice(), + MonitorName: aws.String(monitorName), + RemoteResourcesToAdd: nsRemoteResource.Difference(osRemoteResource).Slice(), + RemoteResourcesToRemove: osRemoteResource.Difference(nsRemoteResource).Slice(), + } + + _, err := conn.UpdateMonitor(ctx, &input) + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("updating Network Flow Monitor Monitor (%s)", monitorName), err.Error()) + return + } + + if _, err := waitMonitorUpdated(ctx, conn, monitorName, r.UpdateTimeout(ctx, new.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Network Flow Monitor Monitor (%s) update", monitorName), err.Error()) + return + } + } + + response.Diagnostics.Append(response.State.Set(ctx, &new)...) +} + +func (r *monitorResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data monitorResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + monitorName := fwflex.StringValueFromFramework(ctx, data.MonitorName) + input := networkflowmonitor.DeleteMonitorInput{ + MonitorName: aws.String(monitorName), + } + _, err := conn.DeleteMonitor(ctx, &input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting Network Flow Monitor Monitor (%s)", monitorName), err.Error()) + return + } + + if _, err := waitMonitorDeleted(ctx, conn, monitorName, r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Network Flow Monitor Monitor (%s) delete", monitorName), err.Error()) + return + } +} + +func (r *monitorResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("monitor_name"), request, response) +} + +func findMonitorByName(ctx context.Context, conn *networkflowmonitor.Client, name string) (*networkflowmonitor.GetMonitorOutput, error) { + input := networkflowmonitor.GetMonitorInput{ + MonitorName: aws.String(name), + } + + return findMonitor(ctx, conn, &input) +} + +func findMonitor(ctx context.Context, conn *networkflowmonitor.Client, input *networkflowmonitor.GetMonitorInput) (*networkflowmonitor.GetMonitorOutput, error) { + output, err := conn.GetMonitor(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +func statusMonitor(ctx context.Context, conn *networkflowmonitor.Client, name string) retry.StateRefreshFunc { + return func() (any, string, error) { + output, err := findMonitorByName(ctx, conn, name) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, string(output.MonitorStatus), nil + } +} + +func waitMonitorCreated(ctx context.Context, conn *networkflowmonitor.Client, name string, timeout time.Duration) (*networkflowmonitor.GetMonitorOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.MonitorStatusPending), + Target: enum.Slice(awstypes.MonitorStatusActive), + Refresh: statusMonitor(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*networkflowmonitor.GetMonitorOutput); ok { + return output, err + } + + return nil, err +} + +func waitMonitorUpdated(ctx context.Context, conn *networkflowmonitor.Client, name string, timeout time.Duration) (*networkflowmonitor.GetMonitorOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.MonitorStatusPending), + Target: enum.Slice(awstypes.MonitorStatusActive), + Refresh: statusMonitor(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*networkflowmonitor.GetMonitorOutput); ok { + return output, err + } + + return nil, err +} + +func waitMonitorDeleted(ctx context.Context, conn *networkflowmonitor.Client, name string, timeout time.Duration) (*networkflowmonitor.GetMonitorOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.MonitorStatusDeleting), + Target: []string{}, + Refresh: statusMonitor(ctx, conn, name), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*networkflowmonitor.GetMonitorOutput); ok { + return output, err + } + + return nil, err +} + +type monitorResourceModel struct { + framework.WithRegionModel + LocalResources fwtypes.SetNestedObjectValueOf[monitorLocalResourceModel] `tfsdk:"local_resource"` + MonitorARN types.String `tfsdk:"monitor_arn"` + MonitorName types.String `tfsdk:"monitor_name"` + RemoteResources fwtypes.SetNestedObjectValueOf[monitorRemoteResourceModel] `tfsdk:"remote_resource"` + ScopeARN fwtypes.ARN `tfsdk:"scope_arn"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +type monitorLocalResourceModel struct { + Identifier types.String `tfsdk:"identifier"` + Type fwtypes.StringEnum[awstypes.MonitorLocalResourceType] `tfsdk:"type"` +} + +type monitorRemoteResourceModel struct { + Identifier types.String `tfsdk:"identifier"` + Type fwtypes.StringEnum[awstypes.MonitorRemoteResourceType] `tfsdk:"type"` +} diff --git a/internal/service/networkflowmonitor/monitor_test.go b/internal/service/networkflowmonitor/monitor_test.go new file mode 100644 index 000000000000..cddc4e7454d2 --- /dev/null +++ b/internal/service/networkflowmonitor/monitor_test.go @@ -0,0 +1,502 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor_test + +import ( + "context" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor" + "github.com/hashicorp/aws-sdk-go-base/v2/endpoints" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfnetworkflowmonitor "github.com/hashicorp/terraform-provider-aws/internal/service/networkflowmonitor" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func testAccMonitor_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_networkflowmonitor_monitor.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMonitorDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMonitorConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("monitor_arn"), tfknownvalue.RegionalARNExact("networkflowmonitor", `monitor/`+rName)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "monitor_name"), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "monitor_name", + ImportStateVerifyIgnore: []string{"scope_arn"}, + }, + }, + }) +} + +func testAccMonitor_disappears(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_networkflowmonitor_monitor.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMonitorDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMonitorConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfnetworkflowmonitor.ResourceMonitor, resourceName), + ), + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + +func testAccMonitor_tags(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_networkflowmonitor_monitor.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMonitorDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMonitorConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "monitor_name"), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "monitor_name", + ImportStateVerifyIgnore: []string{"scope_arn"}, + }, + { + Config: testAccMonitorConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + { + Config: testAccMonitorConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + }) +} + +func testAccMonitor_update(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_networkflowmonitor_monitor.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckMonitorDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMonitorConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("local_resource"), knownvalue.SetSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("remote_resource"), knownvalue.SetSizeExact(0)), + }, + }, + { + Config: testAccMonitorConfig_updated1(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("local_resource"), knownvalue.SetSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("remote_resource"), knownvalue.SetSizeExact(1)), + }, + }, + { + Config: testAccMonitorConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("local_resource"), knownvalue.SetSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("remote_resource"), knownvalue.SetSizeExact(0)), + }, + }, + { + Config: testAccMonitorConfig_updated2(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckMonitorExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("local_resource"), knownvalue.SetSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("remote_resource"), knownvalue.SetSizeExact(2)), + }, + }, + }, + }) +} + +func testAccCheckMonitorExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).NetworkFlowMonitorClient(ctx) + + _, err := tfnetworkflowmonitor.FindMonitorByName(ctx, conn, rs.Primary.Attributes["monitor_name"]) + + return err + } +} + +func testAccCheckMonitorDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).NetworkFlowMonitorClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_networkflowmonitor_monitor" { + continue + } + + _, err := tfnetworkflowmonitor.FindMonitorByName(ctx, conn, rs.Primary.Attributes["monitor_name"]) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("Network Flow Monitor Monitor %s still exists", rs.Primary.Attributes["monitor_name"]) + } + + return nil + } +} + +const testAccMonitorConfig_base = ` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +resource "aws_networkflowmonitor_scope" "test" { + target { + region = data.aws_region.current.name + target_identifier { + target_type = "ACCOUNT" + target_id { + account_id = data.aws_caller_identity.current.account_id + } + } + } +} +` + +func testAccMonitorConfig_basic(rName string) string { + return acctest.ConfigCompose(testAccMonitorConfig_base, fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_networkflowmonitor_monitor" "test" { + monitor_name = %[1]q + scope_arn = aws_networkflowmonitor_scope.test.scope_arn + + local_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } +} +`, rName)) +} + +func testAccMonitorConfig_tags1(rName, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose(testAccMonitorConfig_base, fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_networkflowmonitor_monitor" "test" { + monitor_name = %[1]q + scope_arn = aws_networkflowmonitor_scope.test.scope_arn + + local_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + remote_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccMonitorConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose(testAccMonitorConfig_base, fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_networkflowmonitor_monitor" "test" { + monitor_name = %[1]q + scope_arn = aws_networkflowmonitor_scope.test.scope_arn + + local_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + remote_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} + +func testAccMonitorConfig_updated1(rName string) string { + return acctest.ConfigCompose(testAccMonitorConfig_base, fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + vpc_id = aws_vpc.test.id + cidr_block = "10.0.1.0/24" + + tags = { + Name = %[1]q + } +} + +resource "aws_networkflowmonitor_monitor" "test" { + monitor_name = %[1]q + scope_arn = aws_networkflowmonitor_scope.test.scope_arn + + local_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + local_resource { + type = "AWS::EC2::Subnet" + identifier = aws_subnet.test.arn + } + + remote_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } +} +`, rName)) +} + +func testAccMonitorConfig_updated2(rName string) string { + return acctest.ConfigCompose(testAccMonitorConfig_base, fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + vpc_id = aws_vpc.test.id + cidr_block = "10.0.1.0/24" + + tags = { + Name = %[1]q + } +} + +resource "aws_networkflowmonitor_monitor" "test" { + monitor_name = %[1]q + scope_arn = aws_networkflowmonitor_scope.test.scope_arn + + local_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + local_resource { + type = "AWS::EC2::Subnet" + identifier = aws_subnet.test.arn + } + + remote_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.test.arn + } + + remote_resource { + type = "AWS::EC2::Subnet" + identifier = aws_subnet.test.arn + } +} +`, rName)) +} + +func testAccPreCheck(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).NetworkFlowMonitorClient(ctx) + + input := networkflowmonitor.ListMonitorsInput{} + + _, err := conn.ListMonitors(ctx, &input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} diff --git a/internal/service/networkflowmonitor/networkflowmonitor_test.go b/internal/service/networkflowmonitor/networkflowmonitor_test.go new file mode 100644 index 000000000000..deb1828a42c9 --- /dev/null +++ b/internal/service/networkflowmonitor/networkflowmonitor_test.go @@ -0,0 +1,30 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor_test + +import ( + "testing" + + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccNetworkFlowMonitor_serial(t *testing.T) { + t.Parallel() + + testCases := map[string]map[string]func(t *testing.T){ + "Monitor": { + acctest.CtBasic: testAccMonitor_basic, + acctest.CtDisappears: testAccMonitor_disappears, + "tags": testAccMonitor_tags, + "update": testAccMonitor_update, + }, + "Scope": { + acctest.CtBasic: testAccScope_basic, + acctest.CtDisappears: testAccScope_disappears, + "tags": testAccScope_tags, + }, + } + + acctest.RunSerialTests2Levels(t, testCases, 0) +} diff --git a/internal/service/networkflowmonitor/scope.go b/internal/service/networkflowmonitor/scope.go new file mode 100644 index 000000000000..cf6f05113e4d --- /dev/null +++ b/internal/service/networkflowmonitor/scope.go @@ -0,0 +1,440 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor" + awstypes "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor/types" + set "github.com/hashicorp/go-set/v3" + uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + fwvalidators "github.com/hashicorp/terraform-provider-aws/internal/framework/validators" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_networkflowmonitor_scope", name="Scope") +// @Tags(identifierAttribute="scope_arn") +func newScopeResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &scopeResource{} + + r.SetDefaultCreateTimeout(30 * time.Minute) + r.SetDefaultUpdateTimeout(30 * time.Minute) + r.SetDefaultDeleteTimeout(30 * time.Minute) + + return r, nil +} + +type scopeResource struct { + framework.ResourceWithModel[scopeResourceModel] + framework.WithTimeouts +} + +func (r *scopeResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "scope_arn": framework.ARNAttributeComputedOnly(), + "scope_id": framework.IDAttribute(), + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + names.AttrTarget: schema.SetNestedBlock{ + CustomType: fwtypes.NewSetNestedObjectTypeOf[targetResourceModel](ctx), + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.IsRequired(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrRegion: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + fwvalidators.AWSRegion(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "target_identifier": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[targetIdentifierModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + listvalidator.IsRequired(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "target_type": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.TargetType](), + Required: true, + }, + }, + Blocks: map[string]schema.Block{ + "target_id": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[targetIdModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + listvalidator.IsRequired(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrAccountID: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + fwvalidators.AWSAccountID(), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), + }, + } +} + +func (r *scopeResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data scopeResourceModel + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + var input networkflowmonitor.CreateScopeInput + response.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...) + if response.Diagnostics.HasError() { + return + } + + // Additional fields. + uuid, _ := uuid.GenerateUUID() + input.ClientToken = aws.String(uuid) + input.Tags = getTagsIn(ctx) + + output, err := conn.CreateScope(ctx, &input) + + if err != nil { + response.Diagnostics.AddError("creating Network Flow Monitor Scope", err.Error()) + return + } + + // Set values for unknowns. + data.ScopeARN = fwflex.StringToFramework(ctx, output.ScopeArn) + data.ScopeID = fwflex.StringToFramework(ctx, output.ScopeId) + + scopeID := fwflex.StringValueFromFramework(ctx, data.ScopeID) + if _, err := waitScopeCreated(ctx, conn, scopeID, r.CreateTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Network Flow Monitor Scope (%s) create", scopeID), err.Error()) + return + } + + response.Diagnostics.Append(response.State.Set(ctx, data)...) +} + +func (r *scopeResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data scopeResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + scopeID := fwflex.StringValueFromFramework(ctx, data.ScopeID) + output, err := findScopeByID(ctx, conn, scopeID) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Network Flow Monitor Scope (%s)", scopeID), err.Error()) + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + setTagsOut(ctx, output.Tags) + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *scopeResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var old, new scopeResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &old)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(request.Plan.Get(ctx, &new)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + diff, d := fwflex.Diff(ctx, new, old) + response.Diagnostics.Append(d...) + if response.Diagnostics.HasError() { + return + } + + if diff.HasChanges() { + var oldTargets, newTargets []awstypes.TargetResource + response.Diagnostics.Append(fwflex.Expand(ctx, old.Targets, &oldTargets)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(fwflex.Expand(ctx, new.Targets, &newTargets)...) + if response.Diagnostics.HasError() { + return + } + + hash := func(v awstypes.TargetResource) string { + accountID := any(v.TargetIdentifier.TargetId).(*awstypes.TargetIdMemberAccountId).Value + return aws.ToString(v.Region) + ":" + string(v.TargetIdentifier.TargetType) + ":" + accountID + } + os, ns := set.HashSetFromFunc(oldTargets, hash), set.HashSetFromFunc(newTargets, hash) + + scopeID := fwflex.StringValueFromFramework(ctx, new.ScopeID) + input := networkflowmonitor.UpdateScopeInput{ + ResourcesToAdd: ns.Difference(os).Slice(), + ResourcesToDelete: os.Difference(ns).Slice(), + ScopeId: aws.String(scopeID), + } + + _, err := conn.UpdateScope(ctx, &input) + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("updating Network Flow Monitor Scope (%s) targets", scopeID), err.Error()) + return + } + + if _, err := waitScopeUpdated(ctx, conn, scopeID, r.UpdateTimeout(ctx, new.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Network Flow Monitor Scope (%s) update", scopeID), err.Error()) + return + } + } + + response.Diagnostics.Append(response.State.Set(ctx, &new)...) +} + +func (r *scopeResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data scopeResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().NetworkFlowMonitorClient(ctx) + + scopeID := fwflex.StringValueFromFramework(ctx, data.ScopeID) + input := networkflowmonitor.DeleteScopeInput{ + ScopeId: aws.String(scopeID), + } + _, err := conn.DeleteScope(ctx, &input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting Network Flow Monitor Scope (%s)", scopeID), err.Error()) + return + } + + if _, err := waitScopeDeleted(ctx, conn, scopeID, r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Network Flow Monitor Scope (%s) delete", scopeID), err.Error()) + return + } +} + +func (r *scopeResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("scope_id"), request, response) +} + +func findScopeByID(ctx context.Context, conn *networkflowmonitor.Client, id string) (*networkflowmonitor.GetScopeOutput, error) { + input := networkflowmonitor.GetScopeInput{ + ScopeId: aws.String(id), + } + + return findScope(ctx, conn, &input) +} + +func findScope(ctx context.Context, conn *networkflowmonitor.Client, input *networkflowmonitor.GetScopeInput) (*networkflowmonitor.GetScopeOutput, error) { + output, err := conn.GetScope(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +func statusScope(ctx context.Context, conn *networkflowmonitor.Client, id string) retry.StateRefreshFunc { + return func() (any, string, error) { + output, err := findScopeByID(ctx, conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, string(output.Status), nil + } +} + +func waitScopeCreated(ctx context.Context, conn *networkflowmonitor.Client, id string, timeout time.Duration) (*networkflowmonitor.GetScopeOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.ScopeStatusInProgress), + Target: enum.Slice(awstypes.ScopeStatusSucceeded), + Refresh: statusScope(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*networkflowmonitor.GetScopeOutput); ok { + return output, err + } + + return nil, err +} + +func waitScopeUpdated(ctx context.Context, conn *networkflowmonitor.Client, id string, timeout time.Duration) (*networkflowmonitor.GetScopeOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.ScopeStatusInProgress), + Target: enum.Slice(awstypes.ScopeStatusSucceeded), + Refresh: statusScope(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*networkflowmonitor.GetScopeOutput); ok { + return output, err + } + + return nil, err +} + +func waitScopeDeleted(ctx context.Context, conn *networkflowmonitor.Client, id string, timeout time.Duration) (*networkflowmonitor.GetScopeOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.ScopeStatusDeactivating), + Target: []string{}, + Refresh: statusScope(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*networkflowmonitor.GetScopeOutput); ok { + return output, err + } + + return nil, err +} + +type scopeResourceModel struct { + framework.WithRegionModel + ScopeARN types.String `tfsdk:"scope_arn"` + ScopeID types.String `tfsdk:"scope_id"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` + Targets fwtypes.SetNestedObjectValueOf[targetResourceModel] `tfsdk:"target"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +type targetResourceModel struct { + Region types.String `tfsdk:"region"` + TargetIdentifier fwtypes.ListNestedObjectValueOf[targetIdentifierModel] `tfsdk:"target_identifier"` +} + +type targetIdentifierModel struct { + TargetID fwtypes.ListNestedObjectValueOf[targetIdModel] `tfsdk:"target_id"` + TargetType fwtypes.StringEnum[awstypes.TargetType] `tfsdk:"target_type"` +} + +type targetIdModel struct { + AccountID types.String `tfsdk:"account_id"` +} + +var ( + _ fwflex.Expander = targetIdModel{} + _ fwflex.Flattener = &targetIdModel{} +) + +func (m targetIdModel) Expand(ctx context.Context) (any, diag.Diagnostics) { + var diags diag.Diagnostics + switch { + case !m.AccountID.IsNull(): + var r awstypes.TargetIdMemberAccountId + r.Value = fwflex.StringValueFromFramework(ctx, m.AccountID) + return &r, diags + } + return nil, diags +} + +func (m *targetIdModel) Flatten(ctx context.Context, v any) diag.Diagnostics { + var diags diag.Diagnostics + switch t := v.(type) { + case awstypes.TargetIdMemberAccountId: + m.AccountID = fwflex.StringValueToFramework(ctx, t.Value) + default: + diags.AddError( + "Unsupported Type", + fmt.Sprintf("target ID flatten: %T", v), + ) + } + return diags +} diff --git a/internal/service/networkflowmonitor/scope_test.go b/internal/service/networkflowmonitor/scope_test.go new file mode 100644 index 000000000000..6c8d5f604f03 --- /dev/null +++ b/internal/service/networkflowmonitor/scope_test.go @@ -0,0 +1,284 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor_test + +import ( + "context" + "fmt" + "testing" + + "github.com/YakDriver/regexache" + "github.com/hashicorp/aws-sdk-go-base/v2/endpoints" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfnetworkflowmonitor "github.com/hashicorp/terraform-provider-aws/internal/service/networkflowmonitor" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func testAccScope_basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_networkflowmonitor_scope.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckScopeDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccScopeConfig_basic(acctest.Region()), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScopeExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("scope_arn"), tfknownvalue.RegionalARNRegexp("networkflowmonitor", regexache.MustCompile(`scope/.+`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("scope_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTarget), knownvalue.SetSizeExact(1)), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "scope_id"), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "scope_id", + }, + }, + }) +} + +func testAccScope_disappears(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_networkflowmonitor_scope.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckScopeDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccScopeConfig_basic(endpoints.UsWest2RegionID), + Check: resource.ComposeTestCheckFunc( + testAccCheckScopeExists(ctx, resourceName), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfnetworkflowmonitor.ResourceScope, resourceName), + ), + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + +func testAccScope_tags(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_networkflowmonitor_scope.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.NetworkFlowMonitorServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckScopeDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccScopeConfig_tags1(acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckScopeExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "scope_id"), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "scope_id", + }, + { + Config: testAccScopeConfig_tags2(acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckScopeExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + { + Config: testAccScopeConfig_tags1(acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckScopeExists(ctx, resourceName), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + }) +} + +func testAccCheckScopeExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).NetworkFlowMonitorClient(ctx) + + _, err := tfnetworkflowmonitor.FindScopeByID(ctx, conn, rs.Primary.Attributes["scope_id"]) + + return err + } +} + +func testAccCheckScopeDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).NetworkFlowMonitorClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_networkflowmonitor_scope" { + continue + } + + _, err := tfnetworkflowmonitor.FindScopeByID(ctx, conn, rs.Primary.Attributes["scope_id"]) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("Network Flow Monitor Scope %s still exists", rs.Primary.Attributes["scope_id"]) + } + + return nil + } +} + +func testAccScopeConfig_basic(regions ...string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_networkflowmonitor_scope" "test" { + dynamic "target" { + for_each = [%[1]s] + content { + region = target.value + target_identifier { + target_type = "ACCOUNT" + target_id { + account_id = data.aws_caller_identity.current.account_id + } + } + } + } +} +`, acctest.ListOfStrings(regions...)) +} + +func testAccScopeConfig_tags1(tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +resource "aws_networkflowmonitor_scope" "test" { + target { + region = data.aws_region.current.name + target_identifier { + target_type = "ACCOUNT" + target_id { + account_id = data.aws_caller_identity.current.account_id + } + } + } + + tags = { + %[1]q = %[2]q + } +} +`, tagKey1, tagValue1) +} + +func testAccScopeConfig_tags2(tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +resource "aws_networkflowmonitor_scope" "test" { + target { + region = data.aws_region.current.name + target_identifier { + target_type = "ACCOUNT" + target_id { + account_id = data.aws_caller_identity.current.account_id + } + } + } + + tags = { + %[1]q = %[2]q + %[3]q = %[4]q + } +} +`, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/internal/service/networkflowmonitor/service_package_gen.go b/internal/service/networkflowmonitor/service_package_gen.go index f0c06407b5b7..b2b7102fc458 100644 --- a/internal/service/networkflowmonitor/service_package_gen.go +++ b/internal/service/networkflowmonitor/service_package_gen.go @@ -4,6 +4,7 @@ package networkflowmonitor import ( "context" + "unique" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor" @@ -21,7 +22,26 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S } func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.ServicePackageFrameworkResource { - return []*inttypes.ServicePackageFrameworkResource{} + return []*inttypes.ServicePackageFrameworkResource{ + { + Factory: newMonitorResource, + TypeName: "aws_networkflowmonitor_monitor", + Name: "Monitor", + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: "monitor_arn", + }), + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + { + Factory: newScopeResource, + TypeName: "aws_networkflowmonitor_scope", + Name: "Scope", + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: "scope_arn", + }), + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } } func (p *servicePackage) SDKDataSources(ctx context.Context) []*inttypes.ServicePackageSDKDataSource { diff --git a/internal/service/networkflowmonitor/sweep.go b/internal/service/networkflowmonitor/sweep.go new file mode 100644 index 000000000000..9ec84c749821 --- /dev/null +++ b/internal/service/networkflowmonitor/sweep.go @@ -0,0 +1,114 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package networkflowmonitor + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/networkflowmonitor" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/sweep" + "github.com/hashicorp/terraform-provider-aws/internal/sweep/awsv2" + "github.com/hashicorp/terraform-provider-aws/internal/sweep/framework" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func RegisterSweepers() { + resource.AddTestSweepers("aws_networkflowmonitor_monitor", &resource.Sweeper{ + Name: "aws_networkflowmonitor_monitor", + F: sweepMonitors, + }) + + resource.AddTestSweepers("aws_networkflowmonitor_scope", &resource.Sweeper{ + Name: "aws_networkflowmonitor_scope", + F: sweepScopes, + }) +} + +func sweepMonitors(region string) error { + ctx := sweep.Context(region) + client, err := sweep.SharedRegionalSweepClient(ctx, region) + if err != nil { + return fmt.Errorf("error getting client: %w", err) + } + conn := client.NetworkFlowMonitorClient(ctx) + input := networkflowmonitor.ListMonitorsInput{} + sweepResources := make([]sweep.Sweepable, 0) + + pages := networkflowmonitor.NewListMonitorsPaginator(conn, &input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if awsv2.SkipSweepError(err) { + log.Printf("[WARN] Skipping Network Flow Monitor Monitor sweep for %s: %s", region, err) + return nil + } + + if err != nil { + return fmt.Errorf("error listing Network Flow Monitor Monitors (%s): %w", region, err) + } + + for _, v := range page.Monitors { + arn := aws.ToString(v.MonitorArn) + name := aws.ToString(v.MonitorName) + + sweepResources = append(sweepResources, framework.NewSweepResource(newMonitorResource, client, + framework.NewAttribute(names.AttrID, arn), + framework.NewAttribute("monitor_name", name), + )) + } + } + + err = sweep.SweepOrchestrator(ctx, sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping Network Flow Monitor Monitors (%s): %w", region, err) + } + + return nil +} +func sweepScopes(region string) error { + ctx := sweep.Context(region) + client, err := sweep.SharedRegionalSweepClient(ctx, region) + if err != nil { + return fmt.Errorf("error getting client: %w", err) + } + conn := client.NetworkFlowMonitorClient(ctx) + input := networkflowmonitor.ListScopesInput{} + sweepResources := make([]sweep.Sweepable, 0) + + pages := networkflowmonitor.NewListScopesPaginator(conn, &input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if awsv2.SkipSweepError(err) { + log.Printf("[WARN] Skipping Network Flow Monitor Scope sweep for %s: %s", region, err) + return nil + } + + if err != nil { + return fmt.Errorf("error listing Network Flow Monitor Scopes (%s): %w", region, err) + } + + for _, v := range page.Scopes { + scopeId := aws.ToString(v.ScopeId) + scopeArn := aws.ToString(v.ScopeArn) + + sweepResources = append(sweepResources, framework.NewSweepResource(newScopeResource, client, + framework.NewAttribute(names.AttrID, scopeArn), + framework.NewAttribute("scope_id", scopeId), + )) + } + } + + err = sweep.SweepOrchestrator(ctx, sweepResources) + + if err != nil { + return fmt.Errorf("error sweeping Network Flow Monitor Scopes (%s): %w", region, err) + } + + return nil +} diff --git a/internal/service/networkflowmonitor/tags_gen_test.go b/internal/service/networkflowmonitor/tags_gen_test.go new file mode 100644 index 000000000000..88465be11f11 --- /dev/null +++ b/internal/service/networkflowmonitor/tags_gen_test.go @@ -0,0 +1,16 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package networkflowmonitor_test + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + tfnetworkflowmonitor "github.com/hashicorp/terraform-provider-aws/internal/service/networkflowmonitor" +) + +func expectFullResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullResourceTags(tfnetworkflowmonitor.ServicePackage(ctx), resourceAddress, knownValue) +} diff --git a/internal/service/observabilityadmin/centralization_rule_for_organization.go b/internal/service/observabilityadmin/centralization_rule_for_organization.go new file mode 100644 index 000000000000..8301331a01b3 --- /dev/null +++ b/internal/service/observabilityadmin/centralization_rule_for_organization.go @@ -0,0 +1,474 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package observabilityadmin + +import ( + "context" + "errors" + "time" + + "github.com/YakDriver/regexache" + "github.com/YakDriver/smarterr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/observabilityadmin" + awstypes "github.com/aws/aws-sdk-go-v2/service/observabilityadmin/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + sdkretry "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + fwvalidators "github.com/hashicorp/terraform-provider-aws/internal/framework/validators" + "github.com/hashicorp/terraform-provider-aws/internal/retry" + "github.com/hashicorp/terraform-provider-aws/internal/smerr" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_observabilityadmin_centralization_rule_for_organization", name="Centralization Rule For Organization") +// @Tags(identifierAttribute="rule_arn") +func newCentralizationRuleForOrganizationResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := ¢ralizationRuleForOrganizationResource{} + + r.SetDefaultCreateTimeout(5 * time.Minute) + r.SetDefaultUpdateTimeout(5 * time.Minute) + + return r, nil +} + +type centralizationRuleForOrganizationResource struct { + framework.ResourceWithModel[centralizationRuleForOrganizationResourceModel] + framework.WithTimeouts +} + +func (r *centralizationRuleForOrganizationResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "rule_arn": framework.ARNAttributeComputedOnly(), + "rule_name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 100), + stringvalidator.RegexMatches(regexache.MustCompile(`[0-9A-Za-z-_.#/]+`), ""), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + names.AttrRule: schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[centralizationRuleModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + names.AttrDestination: schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[centralizationRuleDestinationModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "account": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + fwvalidators.AWSAccountID(), + }, + }, + names.AttrRegion: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + fwvalidators.AWSRegion(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "destination_logs_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[destinationLogsConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "backup_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[logsBackupConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrKMSKeyARN: schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + }, + names.AttrRegion: schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + fwvalidators.AWSRegion(), + }, + }, + }, + }, + }, + "logs_encryption_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[logsEncryptionConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "encryption_conflict_resolution_strategy": schema.StringAttribute{ + Optional: true, + CustomType: fwtypes.StringEnumType[awstypes.EncryptionConflictResolutionStrategy](), + }, + "encryption_strategy": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.EncryptionStrategy](), + }, + names.AttrKMSKeyARN: schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + names.AttrSource: schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtMost(1), + listvalidator.SizeAtLeast(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "regions": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + ElementType: types.StringType, + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ValueStringsAre(fwvalidators.AWSRegion()), + }, + Required: true, + }, + names.AttrScope: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.LengthAtMost(2000), + }, + }, + }, + Blocks: map[string]schema.Block{ + "source_logs_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[sourceLogsConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "encrypted_log_group_strategy": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.EncryptedLogGroupStrategy](), + Required: true, + }, + "log_group_selection_criteria": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.LengthAtMost(2000), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + }), + }, + } +} + +func (r *centralizationRuleForOrganizationResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data centralizationRuleForOrganizationResourceModel + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().ObservabilityAdminClient(ctx) + + ruleName := fwflex.StringValueFromFramework(ctx, data.RuleName) + var input observabilityadmin.CreateCentralizationRuleForOrganizationInput + response.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...) + if response.Diagnostics.HasError() { + return + } + + // Additional fields. + input.Tags = getTagsIn(ctx) + + output, err := conn.CreateCentralizationRuleForOrganization(ctx, &input) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, ruleName) + return + } + + // Set values for unknowns. + data.RuleARN = fwflex.StringToFramework(ctx, output.RuleArn) + + smerr.AddEnrich(ctx, &response.Diagnostics, fwflex.Flatten(ctx, output, &data)) + if response.Diagnostics.HasError() { + return + } + + if _, err := waitCentralizationRuleForOrganizationHealthy(ctx, conn, ruleName, r.CreateTimeout(ctx, data.Timeouts)); err != nil { + smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, ruleName) + return + } + + smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, data)) +} + +func (r *centralizationRuleForOrganizationResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data centralizationRuleForOrganizationResourceModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.State.Get(ctx, &data)) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().ObservabilityAdminClient(ctx) + + ruleName := fwflex.StringValueFromFramework(ctx, data.RuleName) + out, err := findCentralizationRuleForOrganizationByID(ctx, conn, ruleName) + if retry.NotFound(err) { + smerr.AddOne(ctx, &response.Diagnostics, fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + return + } + + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, ruleName) + return + } + + smerr.AddEnrich(ctx, &response.Diagnostics, fwflex.Flatten(ctx, out, &data, fwflex.WithFieldNamePrefix("Centralization"))) + if response.Diagnostics.HasError() { + return + } + + smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, &data)) +} + +func (r *centralizationRuleForOrganizationResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var new, old centralizationRuleForOrganizationResourceModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.Plan.Get(ctx, &new)) + smerr.AddEnrich(ctx, &response.Diagnostics, request.State.Get(ctx, &old)) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().ObservabilityAdminClient(ctx) + + diff, d := fwflex.Diff(ctx, new, old) + smerr.AddEnrich(ctx, &response.Diagnostics, d) + if response.Diagnostics.HasError() { + return + } + + if diff.HasChanges() { + ruleName := fwflex.StringValueFromFramework(ctx, new.RuleName) + var input observabilityadmin.UpdateCentralizationRuleForOrganizationInput + smerr.AddEnrich(ctx, &response.Diagnostics, fwflex.Expand(ctx, new, &input)) + if response.Diagnostics.HasError() { + return + } + + // Additional fields. + input.RuleIdentifier = aws.String(ruleName) + + _, err := conn.UpdateCentralizationRuleForOrganization(ctx, &input) + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, ruleName) + return + } + + if _, err := waitCentralizationRuleForOrganizationHealthy(ctx, conn, ruleName, r.UpdateTimeout(ctx, new.Timeouts)); err != nil { + smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, ruleName) + return + } + } + + smerr.AddEnrich(ctx, &response.Diagnostics, response.State.Set(ctx, &new)) +} + +func (r *centralizationRuleForOrganizationResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data centralizationRuleForOrganizationResourceModel + smerr.AddEnrich(ctx, &response.Diagnostics, request.State.Get(ctx, &data)) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().ObservabilityAdminClient(ctx) + + ruleName := fwflex.StringValueFromFramework(ctx, data.RuleName) + input := observabilityadmin.DeleteCentralizationRuleForOrganizationInput{ + RuleIdentifier: aws.String(ruleName), + } + + _, err := conn.DeleteCentralizationRuleForOrganization(ctx, &input) + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + if err != nil { + smerr.AddError(ctx, &response.Diagnostics, err, smerr.ID, ruleName) + return + } +} + +func (r *centralizationRuleForOrganizationResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("rule_name"), request, response) +} + +func findCentralizationRuleForOrganizationByID(ctx context.Context, conn *observabilityadmin.Client, id string) (*observabilityadmin.GetCentralizationRuleForOrganizationOutput, error) { + input := observabilityadmin.GetCentralizationRuleForOrganizationInput{ + RuleIdentifier: aws.String(id), + } + + return findCentralizationRuleForOrganization(ctx, conn, &input) +} + +func findCentralizationRuleForOrganization(ctx context.Context, conn *observabilityadmin.Client, input *observabilityadmin.GetCentralizationRuleForOrganizationInput) (*observabilityadmin.GetCentralizationRuleForOrganizationOutput, error) { + output, err := conn.GetCentralizationRuleForOrganization(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &sdkretry.NotFoundError{ + LastError: err, + LastRequest: &input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +func statusCentralizationRuleForOrganization(conn *observabilityadmin.Client, id string) retry.StateRefreshFunc { + return func(ctx context.Context) (any, string, error) { + output, err := findCentralizationRuleForOrganizationByID(ctx, conn, id) + + if retry.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", smarterr.NewError(err) + } + + return output, string(output.RuleHealth), nil + } +} + +func waitCentralizationRuleForOrganizationHealthy(ctx context.Context, conn *observabilityadmin.Client, id string, timeout time.Duration) (*observabilityadmin.GetCentralizationRuleForOrganizationOutput, error) { //nolint:unparam + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.RuleHealthProvisioning), + Target: enum.Slice(awstypes.RuleHealthHealthy), + Refresh: statusCentralizationRuleForOrganization(conn, id), + Timeout: timeout, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*observabilityadmin.GetCentralizationRuleForOrganizationOutput); ok { + tfresource.SetLastError(err, errors.New(string(out.FailureReason))) + return out, smarterr.NewError(err) + } + + return nil, smarterr.NewError(err) +} + +type centralizationRuleForOrganizationResourceModel struct { + framework.WithRegionModel + Rule fwtypes.ListNestedObjectValueOf[centralizationRuleModel] `tfsdk:"rule"` + RuleARN types.String `tfsdk:"rule_arn"` + RuleName types.String `tfsdk:"rule_name"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +type centralizationRuleModel struct { + Destination fwtypes.ListNestedObjectValueOf[centralizationRuleDestinationModel] `tfsdk:"destination"` + Source fwtypes.ListNestedObjectValueOf[centralizationRuleSourceModel] `tfsdk:"source"` +} + +type centralizationRuleDestinationModel struct { + Account types.String `tfsdk:"account"` + DestinationLogsConfiguration fwtypes.ListNestedObjectValueOf[destinationLogsConfigurationModel] `tfsdk:"destination_logs_configuration"` + Region types.String `tfsdk:"region"` +} + +type centralizationRuleSourceModel struct { + Regions fwtypes.SetOfString `tfsdk:"regions"` + Scope types.String `tfsdk:"scope"` + SourceLogsConfiguration fwtypes.ListNestedObjectValueOf[sourceLogsConfigurationModel] `tfsdk:"source_logs_configuration"` +} + +type destinationLogsConfigurationModel struct { + BackupConfiguration fwtypes.ListNestedObjectValueOf[logsBackupConfigurationModel] `tfsdk:"backup_configuration"` + LogsEncryptionConfiguration fwtypes.ListNestedObjectValueOf[logsEncryptionConfigurationModel] `tfsdk:"logs_encryption_configuration"` +} + +type sourceLogsConfigurationModel struct { + EncryptedLogGroupStrategy fwtypes.StringEnum[awstypes.EncryptedLogGroupStrategy] `tfsdk:"encrypted_log_group_strategy"` + LogGroupSelectionCriteria types.String `tfsdk:"log_group_selection_criteria"` +} + +type logsBackupConfigurationModel struct { + KMSKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` + Region types.String `tfsdk:"region"` +} + +type logsEncryptionConfigurationModel struct { + EncryptionConflictResolutionStrategy fwtypes.StringEnum[awstypes.EncryptionConflictResolutionStrategy] `tfsdk:"encryption_conflict_resolution_strategy"` + EncryptionStrategy fwtypes.StringEnum[awstypes.EncryptionStrategy] `tfsdk:"encryption_strategy"` + KMSKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` +} diff --git a/internal/service/observabilityadmin/centralization_rule_for_organization_test.go b/internal/service/observabilityadmin/centralization_rule_for_organization_test.go new file mode 100644 index 000000000000..41e14eb5e90a --- /dev/null +++ b/internal/service/observabilityadmin/centralization_rule_for_organization_test.go @@ -0,0 +1,500 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package observabilityadmin_test + +import ( + "context" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/observabilityadmin" + awstypes "github.com/aws/aws-sdk-go-v2/service/observabilityadmin/types" + "github.com/hashicorp/aws-sdk-go-base/v2/endpoints" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfobservabilityadmin "github.com/hashicorp/terraform-provider-aws/internal/service/observabilityadmin" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccObservabilityAdminCentralizationRuleForOrganization_basic(t *testing.T) { + ctx := acctest.Context(t) + var rule observabilityadmin.GetCentralizationRuleForOrganizationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_observabilityadmin_centralization_rule_for_organization.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckOrganizationManagementAccount(ctx, t) + // https://docs.aws.amazon.com/organizations/latest/userguide/services-that-can-integrate-cloudwatch.html. + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/observabilityadmin.amazonaws.com") + acctest.PreCheckOrganizationsEnabledServicePrincipal(ctx, t, "observabilityadmin.amazonaws.com") + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/logs-centralization.observabilityadmin.amazonaws.com") + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ObservabilityAdminServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCentralizationRuleForOrganizationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCentralizationRuleForOrganizationConfig_basic(rName, endpoints.EuWest1RegionID, endpoints.ApSoutheast1RegionID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("rule_arn"), tfknownvalue.RegionalARNExact("observabilityadmin", `organization-centralization-rule/`+rName)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "rule_name"), + ImportStateVerifyIdentifierAttribute: "rule_name", + }, + }, + }) +} + +func TestAccObservabilityAdminCentralizationRuleForOrganization_disappears(t *testing.T) { + ctx := acctest.Context(t) + var rule observabilityadmin.GetCentralizationRuleForOrganizationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_observabilityadmin_centralization_rule_for_organization.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckOrganizationManagementAccount(ctx, t) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/observabilityadmin.amazonaws.com") + acctest.PreCheckOrganizationsEnabledServicePrincipal(ctx, t, "observabilityadmin.amazonaws.com") + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/logs-centralization.observabilityadmin.amazonaws.com") + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ObservabilityAdminServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCentralizationRuleForOrganizationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCentralizationRuleForOrganizationConfig_basic(rName, endpoints.EuWest1RegionID, endpoints.ApSoutheast1RegionID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfobservabilityadmin.ResourceCentralizationRuleForOrganization, resourceName), + ), + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + +func TestAccObservabilityAdminCentralizationRuleForOrganization_update(t *testing.T) { + ctx := acctest.Context(t) + var rule observabilityadmin.GetCentralizationRuleForOrganizationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_observabilityadmin_centralization_rule_for_organization.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckOrganizationManagementAccount(ctx, t) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/observabilityadmin.amazonaws.com") + acctest.PreCheckOrganizationsEnabledServicePrincipal(ctx, t, "observabilityadmin.amazonaws.com") + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/logs-centralization.observabilityadmin.amazonaws.com") + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ObservabilityAdminServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCentralizationRuleForOrganizationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCentralizationRuleForOrganizationConfig_basic(rName, endpoints.EuWest1RegionID, endpoints.ApSoutheast1RegionID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRule), knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrDestination: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "destination_logs_configuration": knownvalue.ListSizeExact(0), + names.AttrRegion: knownvalue.StringExact(endpoints.EuWest1RegionID), + })}), + names.AttrSource: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "regions": knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact(endpoints.ApSoutheast1RegionID), + }), + "source_logs_configuration": knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "log_group_selection_criteria": knownvalue.StringExact("*"), + })}), + })}), + })})), + }, + }, + { + Config: testAccCentralizationRuleForOrganizationConfig_basic(rName, endpoints.EuWest1RegionID, endpoints.ApSoutheast1RegionID, endpoints.UsEast1RegionID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRule), knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrDestination: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "destination_logs_configuration": knownvalue.ListSizeExact(0), + names.AttrRegion: knownvalue.StringExact(endpoints.EuWest1RegionID), + })}), + names.AttrSource: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "regions": knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact(endpoints.ApSoutheast1RegionID), + knownvalue.StringExact(endpoints.UsEast1RegionID), + }), + "source_logs_configuration": knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "log_group_selection_criteria": knownvalue.StringExact("*"), + })}), + })}), + })})), + }, + }, + { + Config: testAccCentralizationRuleForOrganizationConfig_updated(rName, endpoints.EuWest1RegionID, endpoints.UsWest1RegionID, endpoints.ApSoutheast1RegionID, endpoints.UsEast1RegionID), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRule), knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrDestination: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "destination_logs_configuration": knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectExact(map[string]knownvalue.Check{ + "backup_configuration": knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + names.AttrRegion: knownvalue.StringExact(endpoints.UsWest1RegionID), + })}), + "logs_encryption_configuration": knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "encryption_strategy": tfknownvalue.StringExact(awstypes.EncryptionStrategyAwsOwned), + })}), + })}), + names.AttrRegion: knownvalue.StringExact(endpoints.EuWest1RegionID), + })}), + names.AttrSource: knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "regions": knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact(endpoints.ApSoutheast1RegionID), + knownvalue.StringExact(endpoints.UsEast1RegionID), + }), + "source_logs_configuration": knownvalue.ListExact([]knownvalue.Check{knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "log_group_selection_criteria": knownvalue.StringExact("LogGroupName LIKE '/aws/lambda%'"), + })}), + })}), + })})), + }, + }, + }, + }) +} + +func TestAccObservabilityAdminCentralizationRuleForOrganization_tags(t *testing.T) { + ctx := acctest.Context(t) + var rule observabilityadmin.GetCentralizationRuleForOrganizationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_observabilityadmin_centralization_rule_for_organization.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckOrganizationManagementAccount(ctx, t) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/observabilityadmin.amazonaws.com") + acctest.PreCheckOrganizationsEnabledServicePrincipal(ctx, t, "observabilityadmin.amazonaws.com") + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/logs-centralization.observabilityadmin.amazonaws.com") + acctest.PreCheckPartition(t, endpoints.AwsPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ObservabilityAdminServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCentralizationRuleForOrganizationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCentralizationRuleForOrganizationConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "rule_name"), + ImportStateVerifyIdentifierAttribute: "rule_name", + }, + { + Config: testAccCentralizationRuleForOrganizationConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + { + Config: testAccCentralizationRuleForOrganizationConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckCentralizationRuleForOrganizationExists(ctx, resourceName, &rule), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + }) +} + +func testAccCheckCentralizationRuleForOrganizationDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ObservabilityAdminClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_observabilityadmin_centralization_rule_for_organization" { + continue + } + + _, err := tfobservabilityadmin.FindCentralizationRuleForOrganizationByID(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("Observability Admin Centralization Rule For Organization %s still exists", rs.Primary.Attributes["rule_name"]) + } + + return nil + } +} + +func testAccCheckCentralizationRuleForOrganizationExists(ctx context.Context, n string, v *observabilityadmin.GetCentralizationRuleForOrganizationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ObservabilityAdminClient(ctx) + + output, err := tfobservabilityadmin.FindCentralizationRuleForOrganizationByID(ctx, conn, rs.Primary.Attributes["rule_name"]) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccPreCheck(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).ObservabilityAdminClient(ctx) + + input := observabilityadmin.ListCentralizationRulesForOrganizationInput{} + _, err := conn.ListCentralizationRulesForOrganization(ctx, &input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func testAccCentralizationRuleForOrganizationConfig_basic(rName, dstRegion string, srcRegions ...string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "test" { + rule_name = %[1]q + + rule { + destination { + region = %[2]q + account = data.aws_caller_identity.current.account_id + } + + source { + regions = [%[3]s] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "SKIP" + log_group_selection_criteria = "*" + } + } + } +} +`, rName, dstRegion, acctest.ListOfStrings(srcRegions...)) +} + +func testAccCentralizationRuleForOrganizationConfig_updated(rName, dstRegion, bkupRegion string, srcRegions ...string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "test" { + rule_name = %[1]q + + rule { + destination { + region = %[2]q + account = data.aws_caller_identity.current.account_id + + destination_logs_configuration { + logs_encryption_configuration { + encryption_strategy = "AWS_OWNED" + } + + backup_configuration { + region = %[3]q + } + } + } + + source { + regions = [%[4]s] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "ALLOW" + log_group_selection_criteria = "LogGroupName LIKE '/aws/lambda%%'" + } + } + } +} +`, rName, dstRegion, bkupRegion, acctest.ListOfStrings(srcRegions...)) +} + +func testAccCentralizationRuleForOrganizationConfig_tags1(rName, tag1Key, tag1Value string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "test" { + rule_name = %[1]q + + rule { + destination { + region = %[4]q + account = data.aws_caller_identity.current.account_id + } + + source { + regions = [%[5]q] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "SKIP" + log_group_selection_criteria = "*" + } + } + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tag1Key, tag1Value, endpoints.EuWest1RegionID, endpoints.ApSoutheast1RegionID) +} + +func testAccCentralizationRuleForOrganizationConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "test" { + rule_name = %[1]q + + rule { + destination { + region = %[6]q + account = data.aws_caller_identity.current.account_id + } + + source { + regions = [%[7]q] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "SKIP" + log_group_selection_criteria = "*" + } + } + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tag1Key, tag1Value, tag2Key, tag2Value, endpoints.EuWest1RegionID, endpoints.ApSoutheast1RegionID) +} diff --git a/internal/service/observabilityadmin/exports_test.go b/internal/service/observabilityadmin/exports_test.go new file mode 100644 index 000000000000..8cf2fbc61c88 --- /dev/null +++ b/internal/service/observabilityadmin/exports_test.go @@ -0,0 +1,11 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package observabilityadmin + +// Exports for use in tests only. +var ( + ResourceCentralizationRuleForOrganization = newCentralizationRuleForOrganizationResource + + FindCentralizationRuleForOrganizationByID = findCentralizationRuleForOrganizationByID +) diff --git a/internal/service/observabilityadmin/generate.go b/internal/service/observabilityadmin/generate.go index e2c73e7a98f4..3eda9f147d57 100644 --- a/internal/service/observabilityadmin/generate.go +++ b/internal/service/observabilityadmin/generate.go @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 //go:generate go run ../../generate/servicepackage/main.go +//go:generate go run ../../generate/tags/main.go -ServiceTagsMap -KVTValues -ListTags -ListTagsInIDElem=ResourceARN -UpdateTags -TagOp=TagResource -TagInIDElem=ResourceARN -UntagOp=UntagResource -UntagInTagsElem=TagKeys // ONLY generate directives and package declaration! Do not add anything else to this file. package observabilityadmin diff --git a/internal/service/observabilityadmin/service_package_gen.go b/internal/service/observabilityadmin/service_package_gen.go index 02b85871878a..8640bcae0d39 100644 --- a/internal/service/observabilityadmin/service_package_gen.go +++ b/internal/service/observabilityadmin/service_package_gen.go @@ -4,6 +4,7 @@ package observabilityadmin import ( "context" + "unique" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/observabilityadmin" @@ -21,7 +22,17 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S } func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.ServicePackageFrameworkResource { - return []*inttypes.ServicePackageFrameworkResource{} + return []*inttypes.ServicePackageFrameworkResource{ + { + Factory: newCentralizationRuleForOrganizationResource, + TypeName: "aws_observabilityadmin_centralization_rule_for_organization", + Name: "Centralization Rule For Organization", + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: "rule_arn", + }), + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, + } } func (p *servicePackage) SDKDataSources(ctx context.Context) []*inttypes.ServicePackageSDKDataSource { diff --git a/internal/service/observabilityadmin/tags_gen.go b/internal/service/observabilityadmin/tags_gen.go new file mode 100644 index 000000000000..39b78a87b4d6 --- /dev/null +++ b/internal/service/observabilityadmin/tags_gen.go @@ -0,0 +1,128 @@ +// Code generated by internal/generate/tags/main.go; DO NOT EDIT. +package observabilityadmin + +import ( + "context" + + "github.com/YakDriver/smarterr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/observabilityadmin" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/logging" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/types/option" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// listTags lists observabilityadmin service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func listTags(ctx context.Context, conn *observabilityadmin.Client, identifier string, optFns ...func(*observabilityadmin.Options)) (tftags.KeyValueTags, error) { + input := observabilityadmin.ListTagsForResourceInput{ + ResourceARN: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(ctx, &input, optFns...) + + if err != nil { + return tftags.New(ctx, nil), smarterr.NewError(err) + } + + return keyValueTags(ctx, output.Tags), nil +} + +// ListTags lists observabilityadmin service tags and set them in Context. +// It is called from outside this package. +func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { + tags, err := listTags(ctx, meta.(*conns.AWSClient).ObservabilityAdminClient(ctx), identifier) + + if err != nil { + return smarterr.NewError(err) + } + + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(tags) + } + + return nil +} + +// map[string]string handling + +// svcTags returns observabilityadmin service tags. +func svcTags(tags tftags.KeyValueTags) map[string]string { + return tags.Map() +} + +// keyValueTags creates tftags.KeyValueTags from observabilityadmin service tags. +func keyValueTags(ctx context.Context, tags map[string]string) tftags.KeyValueTags { + return tftags.New(ctx, tags) +} + +// getTagsIn returns observabilityadmin service tags from Context. +// nil is returned if there are no input tags. +func getTagsIn(ctx context.Context) map[string]string { + if inContext, ok := tftags.FromContext(ctx); ok { + if tags := svcTags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { + return tags + } + } + + return nil +} + +// setTagsOut sets observabilityadmin service tags in Context. +func setTagsOut(ctx context.Context, tags map[string]string) { + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(keyValueTags(ctx, tags)) + } +} + +// updateTags updates observabilityadmin service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func updateTags(ctx context.Context, conn *observabilityadmin.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*observabilityadmin.Options)) error { + oldTags := tftags.New(ctx, oldTagsMap) + newTags := tftags.New(ctx, newTagsMap) + + ctx = tflog.SetField(ctx, logging.KeyResourceId, identifier) + + removedTags := oldTags.Removed(newTags) + removedTags = removedTags.IgnoreSystem(names.ObservabilityAdmin) + if len(removedTags) > 0 { + input := observabilityadmin.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: removedTags.Keys(), + } + + _, err := conn.UntagResource(ctx, &input, optFns...) + + if err != nil { + return smarterr.NewError(err) + } + } + + updatedTags := oldTags.Updated(newTags) + updatedTags = updatedTags.IgnoreSystem(names.ObservabilityAdmin) + if len(updatedTags) > 0 { + input := observabilityadmin.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: svcTags(updatedTags), + } + + _, err := conn.TagResource(ctx, &input, optFns...) + + if err != nil { + return smarterr.NewError(err) + } + } + + return nil +} + +// UpdateTags updates observabilityadmin service tags. +// It is called from outside this package. +func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { + return updateTags(ctx, meta.(*conns.AWSClient).ObservabilityAdminClient(ctx), identifier, oldTags, newTags) +} diff --git a/internal/service/odb/cloud_vm_cluster.go b/internal/service/odb/cloud_vm_cluster.go index 3e144ef00cdf..bf145895c97c 100644 --- a/internal/service/odb/cloud_vm_cluster.go +++ b/internal/service/odb/cloud_vm_cluster.go @@ -81,9 +81,20 @@ func (r *resourceCloudVmCluster) Schema(ctx context.Context, req resource.Schema names.AttrARN: framework.ARNAttributeComputedOnly(), names.AttrID: framework.IDAttribute(), "cloud_exadata_infrastructure_id": schema.StringAttribute{ - Required: true, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), + }, + Description: "The unique identifier of the Exadata infrastructure for this VM cluster. Changing this will create a new resource.", + }, + "cloud_exadata_infrastructure_arn": schema.StringAttribute{ + Optional: true, + Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, Description: "The unique identifier of the Exadata infrastructure for this VM cluster. Changing this will create a new resource.", }, @@ -270,9 +281,20 @@ func (r *resourceCloudVmCluster) Schema(ctx context.Context, req resource.Schema Description: "The HTTPS link to the VM cluster resource in OCI.", }, "odb_network_id": schema.StringAttribute{ - Required: true, + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), + }, + Description: "The unique identifier of the ODB network for the VM cluster. This member is required. Changing this will create a new resource.", + }, + "odb_network_arn": schema.StringAttribute{ + Optional: true, + Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, Description: "The unique identifier of the ODB network for the VM cluster. This member is required. Changing this will create a new resource.", }, @@ -442,6 +464,51 @@ func (r *resourceCloudVmCluster) Schema(ctx context.Context, req resource.Schema } } +func (r *resourceCloudVmCluster) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { + var data cloudVmClusterResourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + //Neither is present + if !data.isNetworkARNAndExadataInfraARNPresent() && !data.isNetworkIdAndExadataInfraIdPresent() { + err := errors.New("either odb_network_id & cloud_exadata_infrastructure_id combination or odb_network_arn & cloud_exadata_infrastructure_arn combination must present. neither is present") + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionCreating, ResNameCloudVmCluster, data.DisplayName.String(), err), + err.Error(), + ) + return + } + //Both are present + if data.isNetworkARNAndExadataInfraARNPresent() && data.isNetworkIdAndExadataInfraIdPresent() { + err := errors.New("either odb_network_id & cloud_exadata_infrastructure_id combination or odb_network_arn & cloud_exadata_infrastructure_arn combination must present. both are present") + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionCreating, ResNameCloudVmCluster, data.DisplayName.String(), err), + err.Error(), + ) + return + } + // both exadata infra id and ARN present + if data.isExadataInfraARNAndIdPresent() { + err := errors.New("either odb_network_id & cloud_exadata_infrastructure_id combination or odb_network_arn & cloud_exadata_infrastructure_arn combination must present. exadata infrastructure id and ARN present") + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionCreating, ResNameCloudVmCluster, data.DisplayName.String(), err), + err.Error(), + ) + return + } + // both odb network infra and ARN present + if data.isNetworkARNAndIdPresent() { + err := errors.New("either odb_network_id & cloud_exadata_infrastructure_id combination or odb_network_arn & cloud_exadata_infrastructure_arn combination must present. odb network id and ARN ") + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionCreating, ResNameCloudVmCluster, data.DisplayName.String(), err), + err.Error(), + ) + return + } +} + func (r *resourceCloudVmCluster) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { conn := r.Meta().ODBClient(ctx) var plan cloudVmClusterResourceModel @@ -449,12 +516,21 @@ func (r *resourceCloudVmCluster) Create(ctx context.Context, req resource.Create if resp.Diagnostics.HasError() { return } - + odbNetwork := plan.OdbNetworkId + if odbNetwork.IsNull() || odbNetwork.IsUnknown() { + odbNetwork = plan.OdbNetworkArn + } + cloudExadataInfra := plan.CloudExadataInfrastructureId + if cloudExadataInfra.IsNull() || cloudExadataInfra.IsUnknown() { + cloudExadataInfra = plan.CloudExadataInfrastructureArn + } input := odb.CreateCloudVmClusterInput{ Tags: getTagsIn(ctx), //Underlying API treats Hostname as hostname prefix. Hostname: plan.HostnamePrefix.ValueStringPointer(), } + input.OdbNetworkId = odbNetwork.ValueStringPointer() + input.CloudExadataInfrastructureId = cloudExadataInfra.ValueStringPointer() resp.Diagnostics.Append(flex.Expand(ctx, plan, &input)...) if resp.Diagnostics.HasError() { return @@ -485,8 +561,7 @@ func (r *resourceCloudVmCluster) Create(ctx context.Context, req resource.Create ) return } - hostnamePrefix := strings.Split(*input.Hostname, "-")[0] - plan.HostnamePrefix = flex.StringValueToFramework(ctx, hostnamePrefix) + plan.HostnamePrefix = flex.StringToFramework(ctx, input.Hostname) plan.HostnamePrefixComputed = flex.StringToFramework(ctx, createdVmCluster.Hostname) //scan listener port not returned by API directly plan.ScanListenerPortTcp = flex.Int32ToFramework(ctx, createdVmCluster.ListenerPort) @@ -500,6 +575,40 @@ func (r *resourceCloudVmCluster) Create(ctx context.Context, req resource.Create return } plan.GiVersion = flex.StringToFramework(ctx, giVersionMajor) + odbNetwork = plan.OdbNetworkId + if odbNetwork.IsNull() || odbNetwork.IsUnknown() { + odbNetwork = plan.OdbNetworkArn + } + getOdbNetworkInput := odb.GetOdbNetworkInput{ + OdbNetworkId: odbNetwork.ValueStringPointer(), + } + odbNetworkOutput, err := conn.GetOdbNetwork(ctx, &getOdbNetworkInput) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameCloudVmCluster, plan.CloudVmClusterId.ValueString(), err), + err.Error(), + ) + return + } + plan.OdbNetworkId = flex.StringToFramework(ctx, odbNetworkOutput.OdbNetwork.OdbNetworkId) + plan.OdbNetworkArn = flex.StringToFramework(ctx, odbNetworkOutput.OdbNetwork.OdbNetworkArn) + cloudExadataInfra = plan.CloudExadataInfrastructureId + if cloudExadataInfra.IsNull() || cloudExadataInfra.IsUnknown() { + cloudExadataInfra = plan.CloudExadataInfrastructureArn + } + getCloudExadataInfraInput := odb.GetCloudExadataInfrastructureInput{ + CloudExadataInfrastructureId: cloudExadataInfra.ValueStringPointer(), + } + cloudExadataInfraOutput, err := conn.GetCloudExadataInfrastructure(ctx, &getCloudExadataInfraInput) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameCloudVmCluster, plan.CloudVmClusterId.ValueString(), err), + err.Error(), + ) + return + } + plan.CloudExadataInfrastructureId = flex.StringToFramework(ctx, cloudExadataInfraOutput.CloudExadataInfrastructure.CloudExadataInfrastructureId) + plan.CloudExadataInfrastructureArn = flex.StringToFramework(ctx, cloudExadataInfraOutput.CloudExadataInfrastructure.CloudExadataInfrastructureArn) resp.Diagnostics.Append(flex.Flatten(ctx, createdVmCluster, &plan)...) if resp.Diagnostics.HasError() { return @@ -514,7 +623,6 @@ func (r *resourceCloudVmCluster) Read(ctx context.Context, req resource.ReadRequ if resp.Diagnostics.HasError() { return } - out, err := findCloudVmClusterForResourceByID(ctx, conn, state.CloudVmClusterId.ValueString()) if tfresource.NotFound(err) { resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -528,8 +636,8 @@ func (r *resourceCloudVmCluster) Read(ctx context.Context, req resource.ReadRequ ) return } - hostnamePrefix := strings.Split(*out.Hostname, "-")[0] - state.HostnamePrefix = types.StringValue(hostnamePrefix) + hostnamePrefix := computeHostnamePrefix(out.Hostname) + state.HostnamePrefix = flex.StringToFramework(ctx, hostnamePrefix) state.HostnamePrefixComputed = types.StringValue(*out.Hostname) //scan listener port not returned by API directly state.ScanListenerPortTcp = flex.Int32ToFramework(ctx, out.ListenerPort) @@ -543,6 +651,32 @@ func (r *resourceCloudVmCluster) Read(ctx context.Context, req resource.ReadRequ return } state.GiVersion = flex.StringToFramework(ctx, giVersionMajor) + getOdbNetworkInput := odb.GetOdbNetworkInput{ + OdbNetworkId: out.OdbNetworkId, + } + odbNetworkOutput, err := conn.GetOdbNetwork(ctx, &getOdbNetworkInput) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameCloudVmCluster, state.CloudVmClusterId.ValueString(), err), + err.Error(), + ) + return + } + state.OdbNetworkId = flex.StringToFramework(ctx, odbNetworkOutput.OdbNetwork.OdbNetworkId) + state.OdbNetworkArn = flex.StringToFramework(ctx, odbNetworkOutput.OdbNetwork.OdbNetworkArn) + getCloudExadataInfraInput := odb.GetCloudExadataInfrastructureInput{ + CloudExadataInfrastructureId: out.CloudExadataInfrastructureId, + } + cloudExadataInfraOutput, err := conn.GetCloudExadataInfrastructure(ctx, &getCloudExadataInfraInput) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ODB, create.ErrActionWaitingForCreation, ResNameCloudVmCluster, state.CloudVmClusterId.ValueString(), err), + err.Error(), + ) + return + } + state.CloudExadataInfrastructureId = flex.StringToFramework(ctx, cloudExadataInfraOutput.CloudExadataInfrastructure.CloudExadataInfrastructureId) + state.CloudExadataInfrastructureArn = flex.StringToFramework(ctx, cloudExadataInfraOutput.CloudExadataInfrastructure.CloudExadataInfrastructureArn) resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...) if resp.Diagnostics.HasError() { return @@ -584,6 +718,16 @@ func (r *resourceCloudVmCluster) Delete(ctx context.Context, req resource.Delete } } +// computes hostname prefix from hostname prefix computed value. +func computeHostnamePrefix(hostnamePrefixComputed *string) *string { + suffixIndex := strings.LastIndex(*hostnamePrefixComputed, "-") + if suffixIndex != -1 { + actualHostnamePrefix := (*hostnamePrefixComputed)[:suffixIndex] + return &actualHostnamePrefix + } else { + return hostnamePrefixComputed + } +} func waitCloudVmClusterCreated(ctx context.Context, conn *odb.Client, id string, timeout time.Duration) (*odbtypes.CloudVmCluster, error) { stateConf := &retry.StateChangeConf{ Pending: enum.Slice(odbtypes.ResourceStatusProvisioning), @@ -666,52 +810,54 @@ func getMajorGiVersion(giVersionComputed *string) (*string, error) { type cloudVmClusterResourceModel struct { framework.WithRegionModel - CloudVmClusterArn types.String `tfsdk:"arn"` - CloudExadataInfrastructureId types.String `tfsdk:"cloud_exadata_infrastructure_id"` - CloudVmClusterId types.String `tfsdk:"id"` - ClusterName types.String `tfsdk:"cluster_name"` - CpuCoreCount types.Int32 `tfsdk:"cpu_core_count"` - DataCollectionOptions fwtypes.ListNestedObjectValueOf[cloudVMCDataCollectionOptionsResourceModel] `tfsdk:"data_collection_options"` - DataStorageSizeInTBs types.Float64 `tfsdk:"data_storage_size_in_tbs"` - DbNodeStorageSizeInGBs types.Int32 `tfsdk:"db_node_storage_size_in_gbs"` - DbServers fwtypes.SetValueOf[types.String] `tfsdk:"db_servers"` - DiskRedundancy fwtypes.StringEnum[odbtypes.DiskRedundancy] `tfsdk:"disk_redundancy"` - DisplayName types.String `tfsdk:"display_name"` - Domain types.String `tfsdk:"domain"` - GiVersion types.String `tfsdk:"gi_version" autoflex:",noflatten"` - GiVersionComputed types.String `tfsdk:"gi_version_computed" autoflex:",noflatten"` - HostnamePrefixComputed types.String `tfsdk:"hostname_prefix_computed" autoflex:",noflatten"` - HostnamePrefix types.String `tfsdk:"hostname_prefix" autoflex:"-"` - IormConfigCache fwtypes.ListNestedObjectValueOf[cloudVMCExadataIormConfigResourceModel] `tfsdk:"iorm_config_cache"` - IsLocalBackupEnabled types.Bool `tfsdk:"is_local_backup_enabled"` - IsSparseDiskGroupEnabled types.Bool `tfsdk:"is_sparse_diskgroup_enabled"` - LastUpdateHistoryEntryId types.String `tfsdk:"last_update_history_entry_id"` - LicenseModel fwtypes.StringEnum[odbtypes.LicenseModel] `tfsdk:"license_model"` - ListenerPort types.Int32 `tfsdk:"listener_port"` - MemorySizeInGbs types.Int32 `tfsdk:"memory_size_in_gbs"` - NodeCount types.Int32 `tfsdk:"node_count"` - Ocid types.String `tfsdk:"ocid"` - OciResourceAnchorName types.String `tfsdk:"oci_resource_anchor_name"` - OciUrl types.String `tfsdk:"oci_url"` - OdbNetworkId types.String `tfsdk:"odb_network_id"` - PercentProgress types.Float32 `tfsdk:"percent_progress"` - ScanDnsName types.String `tfsdk:"scan_dns_name"` - ScanDnsRecordId types.String `tfsdk:"scan_dns_record_id"` - ScanIpIds fwtypes.ListValueOf[types.String] `tfsdk:"scan_ip_ids"` - Shape types.String `tfsdk:"shape"` - SshPublicKeys fwtypes.SetValueOf[types.String] `tfsdk:"ssh_public_keys"` - Status fwtypes.StringEnum[odbtypes.ResourceStatus] `tfsdk:"status"` - StatusReason types.String `tfsdk:"status_reason"` - StorageSizeInGBs types.Int32 `tfsdk:"storage_size_in_gbs"` - SystemVersion types.String `tfsdk:"system_version"` - Timeouts timeouts.Value `tfsdk:"timeouts"` - Timezone types.String `tfsdk:"timezone"` - VipIds fwtypes.ListValueOf[types.String] `tfsdk:"vip_ids"` - CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` - ComputeModel fwtypes.StringEnum[odbtypes.ComputeModel] `tfsdk:"compute_model"` - ScanListenerPortTcp types.Int32 `tfsdk:"scan_listener_port_tcp" autoflex:",noflatten"` - Tags tftags.Map `tfsdk:"tags"` - TagsAll tftags.Map `tfsdk:"tags_all"` + CloudVmClusterArn types.String `tfsdk:"arn"` + CloudExadataInfrastructureId types.String `tfsdk:"cloud_exadata_infrastructure_id" autoflex:"-"` + CloudExadataInfrastructureArn types.String `tfsdk:"cloud_exadata_infrastructure_arn" autoflex:"-"` + CloudVmClusterId types.String `tfsdk:"id"` + ClusterName types.String `tfsdk:"cluster_name"` + CpuCoreCount types.Int32 `tfsdk:"cpu_core_count"` + DataCollectionOptions fwtypes.ListNestedObjectValueOf[cloudVMCDataCollectionOptionsResourceModel] `tfsdk:"data_collection_options"` + DataStorageSizeInTBs types.Float64 `tfsdk:"data_storage_size_in_tbs"` + DbNodeStorageSizeInGBs types.Int32 `tfsdk:"db_node_storage_size_in_gbs"` + DbServers fwtypes.SetValueOf[types.String] `tfsdk:"db_servers"` + DiskRedundancy fwtypes.StringEnum[odbtypes.DiskRedundancy] `tfsdk:"disk_redundancy"` + DisplayName types.String `tfsdk:"display_name"` + Domain types.String `tfsdk:"domain"` + GiVersion types.String `tfsdk:"gi_version" autoflex:",noflatten"` + GiVersionComputed types.String `tfsdk:"gi_version_computed" autoflex:",noflatten"` + HostnamePrefixComputed types.String `tfsdk:"hostname_prefix_computed" autoflex:",noflatten"` + HostnamePrefix types.String `tfsdk:"hostname_prefix" autoflex:"-"` + IormConfigCache fwtypes.ListNestedObjectValueOf[cloudVMCExadataIormConfigResourceModel] `tfsdk:"iorm_config_cache"` + IsLocalBackupEnabled types.Bool `tfsdk:"is_local_backup_enabled"` + IsSparseDiskGroupEnabled types.Bool `tfsdk:"is_sparse_diskgroup_enabled"` + LastUpdateHistoryEntryId types.String `tfsdk:"last_update_history_entry_id"` + LicenseModel fwtypes.StringEnum[odbtypes.LicenseModel] `tfsdk:"license_model"` + ListenerPort types.Int32 `tfsdk:"listener_port"` + MemorySizeInGbs types.Int32 `tfsdk:"memory_size_in_gbs"` + NodeCount types.Int32 `tfsdk:"node_count"` + Ocid types.String `tfsdk:"ocid"` + OciResourceAnchorName types.String `tfsdk:"oci_resource_anchor_name"` + OciUrl types.String `tfsdk:"oci_url"` + OdbNetworkId types.String `tfsdk:"odb_network_id" autoflex:"-"` + OdbNetworkArn types.String `tfsdk:"odb_network_arn" autoflex:"-"` + PercentProgress types.Float32 `tfsdk:"percent_progress"` + ScanDnsName types.String `tfsdk:"scan_dns_name"` + ScanDnsRecordId types.String `tfsdk:"scan_dns_record_id"` + ScanIpIds fwtypes.ListValueOf[types.String] `tfsdk:"scan_ip_ids"` + Shape types.String `tfsdk:"shape"` + SshPublicKeys fwtypes.SetValueOf[types.String] `tfsdk:"ssh_public_keys"` + Status fwtypes.StringEnum[odbtypes.ResourceStatus] `tfsdk:"status"` + StatusReason types.String `tfsdk:"status_reason"` + StorageSizeInGBs types.Int32 `tfsdk:"storage_size_in_gbs"` + SystemVersion types.String `tfsdk:"system_version"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + Timezone types.String `tfsdk:"timezone"` + VipIds fwtypes.ListValueOf[types.String] `tfsdk:"vip_ids"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` + ComputeModel fwtypes.StringEnum[odbtypes.ComputeModel] `tfsdk:"compute_model"` + ScanListenerPortTcp types.Int32 `tfsdk:"scan_listener_port_tcp" autoflex:",noflatten"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` } type cloudVMCDataCollectionOptionsResourceModel struct { @@ -732,3 +878,19 @@ type cloudVMCDbIormConfigResourceModel struct { FlashCacheLimit types.String `tfsdk:"flash_cache_limit"` Share types.Int32 `tfsdk:"share"` } + +func (r cloudVmClusterResourceModel) isNetworkIdAndExadataInfraIdPresent() bool { + return !r.OdbNetworkId.IsNull() && !r.OdbNetworkId.IsUnknown() && !r.CloudExadataInfrastructureId.IsNull() && !r.CloudExadataInfrastructureId.IsUnknown() +} + +func (r cloudVmClusterResourceModel) isNetworkARNAndExadataInfraARNPresent() bool { + return !r.OdbNetworkArn.IsNull() && !r.OdbNetworkArn.IsUnknown() && !r.CloudExadataInfrastructureArn.IsNull() && !r.CloudExadataInfrastructureArn.IsUnknown() +} + +func (r cloudVmClusterResourceModel) isNetworkARNAndIdPresent() bool { + return (!r.OdbNetworkId.IsNull() && !r.OdbNetworkId.IsUnknown()) && (!r.OdbNetworkArn.IsNull() && !r.OdbNetworkArn.IsUnknown()) +} + +func (r cloudVmClusterResourceModel) isExadataInfraARNAndIdPresent() bool { + return (!r.CloudExadataInfrastructureId.IsNull() && !r.CloudExadataInfrastructureId.IsUnknown()) && (!r.CloudExadataInfrastructureArn.IsNull() && !r.CloudExadataInfrastructureArn.IsUnknown()) +} diff --git a/internal/service/odb/cloud_vm_cluster_test.go b/internal/service/odb/cloud_vm_cluster_test.go index d45d899ffc26..b7e561c8d87c 100644 --- a/internal/service/odb/cloud_vm_cluster_test.go +++ b/internal/service/odb/cloud_vm_cluster_test.go @@ -270,6 +270,68 @@ func TestAccODBCloudVmCluster_disappears(t *testing.T) { }) } +func TestAccODBCloudVmCluster_usingARN(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + var cloudvmcluster1 odbtypes.CloudVmCluster + var cloudvmcluster2 odbtypes.CloudVmCluster + vmcDisplayName := sdkacctest.RandomWithPrefix("Ofake") + resourceName := "aws_odb_cloud_vm_cluster.test" + + publicKey, _, err := sdkacctest.RandSSHKeyPair(acctest.DefaultEmailAddress) + if err != nil { + t.Fatal(err) + return + } + vmcWithoutTag, vmcWithTag := vmClusterTestEntity.cloudVmClusterByARN(vmcDisplayName, publicKey) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + vmClusterTestEntity.testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ODBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: vmClusterTestEntity.testAccCheckCloudVmClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: vmcWithoutTag, + Check: resource.ComposeAggregateTestCheckFunc( + resource.ComposeTestCheckFunc(func(state *terraform.State) error { + return nil + }), + vmClusterTestEntity.testAccCheckCloudVmClusterExists(ctx, resourceName, &cloudvmcluster1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: vmcWithTag, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), + resource.TestCheckResourceAttr(resourceName, "tags.env", "dev"), + vmClusterTestEntity.testAccCheckCloudVmClusterExists(ctx, resourceName, &cloudvmcluster2), + resource.ComposeTestCheckFunc(func(state *terraform.State) error { + if strings.Compare(*(cloudvmcluster1.CloudVmClusterId), *(cloudvmcluster2.CloudVmClusterId)) != 0 { + return errors.New("Should not create a new cloud vm cluster for tag update") + } + return nil + }), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func (cloudVmClusterResourceTest) testAccCheckCloudVmClusterDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).ODBClient(ctx) @@ -339,9 +401,9 @@ data "aws_odb_db_servers" "test" { resource "aws_odb_cloud_vm_cluster" "test" { display_name = %[3]q cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id - cpu_core_count = 6 - gi_version = "23.0.0.0" - hostname_prefix = "apollo12" + cpu_core_count = 16 + gi_version = "26.0.0.0" + hostname_prefix = "apollo-12" ssh_public_keys = ["%[4]s"] odb_network_id = aws_odb_network.test.id is_local_backup_enabled = true @@ -373,9 +435,9 @@ data "aws_odb_db_servers" "test" { resource "aws_odb_cloud_vm_cluster" "test" { display_name = %[3]q cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.id - cpu_core_count = 6 - gi_version = "23.0.0.0" - hostname_prefix = "apollo12" + cpu_core_count = 16 + gi_version = "26.0.0.0" + hostname_prefix = "apollo-12" ssh_public_keys = ["%[4]s"] odb_network_id = aws_odb_network.test.id is_local_backup_enabled = true @@ -559,3 +621,91 @@ resource "aws_odb_cloud_vm_cluster" "test" { return vmClusterResourceNoTag, vmClusterResourceWithTag } + +func (cloudVmClusterResourceTest) cloudVmClusterByARN(vmClusterDisplayName, sshKey string) (string, string) { + exaInfraDisplayName := sdkacctest.RandomWithPrefix("Ofake-exa") + odbNetDisplayName := sdkacctest.RandomWithPrefix(vmClusterTestEntity.odbNetDisplayNamePrefix) + exaInfra := vmClusterTestEntity.exaInfra(exaInfraDisplayName) + odbNet := vmClusterTestEntity.oracleDBNetwork(odbNetDisplayName) + vmClusterResourceNoTag := fmt.Sprintf(` + + + + +%s + +%s + + + +data "aws_odb_db_servers" "test" { + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.arn +} + +resource "aws_odb_cloud_vm_cluster" "test" { + display_name = %[3]q + cloud_exadata_infrastructure_arn = aws_odb_cloud_exadata_infrastructure.test.arn + cpu_core_count = 16 + gi_version = "26.0.0.0" + hostname_prefix = "apollo12" + ssh_public_keys = ["%[4]s"] + odb_network_arn = aws_odb_network.test.arn + is_local_backup_enabled = true + is_sparse_diskgroup_enabled = true + license_model = "LICENSE_INCLUDED" + data_storage_size_in_tbs = 20.0 + db_servers = [for db_server in data.aws_odb_db_servers.test.db_servers : db_server.id] + db_node_storage_size_in_gbs = 120.0 + memory_size_in_gbs = 60 + data_collection_options { + is_diagnostics_events_enabled = false + is_health_monitoring_enabled = false + is_incident_logs_enabled = false + } + +} +`, exaInfra, odbNet, vmClusterDisplayName, sshKey) + + vmClusterResourceWithTag := fmt.Sprintf(` + + +%s + +%s + + + + +data "aws_odb_db_servers" "test" { + cloud_exadata_infrastructure_id = aws_odb_cloud_exadata_infrastructure.test.arn +} + +resource "aws_odb_cloud_vm_cluster" "test" { + display_name = %[3]q + cloud_exadata_infrastructure_arn = aws_odb_cloud_exadata_infrastructure.test.arn + cpu_core_count = 16 + gi_version = "26.0.0.0" + hostname_prefix = "apollo12" + ssh_public_keys = ["%[4]s"] + odb_network_arn = aws_odb_network.test.arn + is_local_backup_enabled = true + is_sparse_diskgroup_enabled = true + license_model = "LICENSE_INCLUDED" + data_storage_size_in_tbs = 20.0 + db_servers = [for db_server in data.aws_odb_db_servers.test.db_servers : db_server.id] + db_node_storage_size_in_gbs = 120.0 + memory_size_in_gbs = 60 + data_collection_options { + is_diagnostics_events_enabled = false + is_health_monitoring_enabled = false + is_incident_logs_enabled = false + } + tags = { + "env" = "dev" + } + +} +`, exaInfra, odbNet, vmClusterDisplayName, sshKey) + + return vmClusterResourceNoTag, vmClusterResourceWithTag +} diff --git a/internal/service/opensearch/authorize_vpc_endpoint_access.go b/internal/service/opensearch/authorize_vpc_endpoint_access.go index aa68cc646527..f72e4bdeebc9 100644 --- a/internal/service/opensearch/authorize_vpc_endpoint_access.go +++ b/internal/service/opensearch/authorize_vpc_endpoint_access.go @@ -19,9 +19,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + intflex "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -78,7 +81,7 @@ func (r *authorizeVPCEndpointAccessResource) Create(ctx context.Context, req res DomainName: plan.DomainName.ValueStringPointer(), } - resp.Diagnostics.Append(flex.Expand(ctx, plan, in)...) + resp.Diagnostics.Append(fwflex.Expand(ctx, plan, in)...) if resp.Diagnostics.HasError() { return } @@ -100,7 +103,7 @@ func (r *authorizeVPCEndpointAccessResource) Create(ctx context.Context, req res return } - resp.Diagnostics.Append(flex.Flatten(ctx, out, &plan)...) + resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &plan)...) if resp.Diagnostics.HasError() { return } @@ -117,8 +120,9 @@ func (r *authorizeVPCEndpointAccessResource) Read(ctx context.Context, req resou return } - out, err := findAuthorizeVPCEndpointAccessByName(ctx, conn, state.DomainName.ValueString()) + out, err := findAuthorizeVPCEndpointAccessByTwoPartKey(ctx, conn, state.DomainName.ValueString(), state.Account.ValueString()) if tfresource.NotFound(err) { + resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) return } @@ -130,7 +134,7 @@ func (r *authorizeVPCEndpointAccessResource) Read(ctx context.Context, req resou return } - resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...) + resp.Diagnostics.Append(fwflex.Flatten(ctx, out, &state)...) if resp.Diagnostics.HasError() { return } @@ -164,20 +168,37 @@ func (r *authorizeVPCEndpointAccessResource) Delete(ctx context.Context, req res } } -func (r *authorizeVPCEndpointAccessResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrDomainName), req, resp) +func (r *authorizeVPCEndpointAccessResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + const ( + authorizeVPCEndpointAccessImportIDParts = 2 + ) + parts, err := intflex.ExpandResourceId(request.ID, authorizeVPCEndpointAccessImportIDParts, true) + + if err != nil { + response.Diagnostics.Append(fwdiag.NewParsingResourceIDErrorDiagnostic(err)) + + return + } + + response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root("account"), parts[1])...) + response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root(names.AttrDomainName), parts[0])...) } -func findAuthorizeVPCEndpointAccessByName(ctx context.Context, conn *opensearch.Client, domainName string) (*awstypes.AuthorizedPrincipal, error) { - in := &opensearch.ListVpcEndpointAccessInput{ +func findAuthorizeVPCEndpointAccessByTwoPartKey(ctx context.Context, conn *opensearch.Client, domainName, account string) (*awstypes.AuthorizedPrincipal, error) { + input := opensearch.ListVpcEndpointAccessInput{ DomainName: aws.String(domainName), } - return findAuthorizeVPCEndpointAccess(ctx, conn, in) + return findAuthorizeVPCEndpointAccess(ctx, conn, &input, func(ap *awstypes.AuthorizedPrincipal) bool { + // AWS API documentation, and the SDK for Go following it, seems to be wrong for the possible values for PrincipalType. + // It states it can be "AWS_ACCOUNT" or "AWS_SERVICE", but in practice for accounts the value is "AWS Account". + // Hence, not using the constant awstypes.PrincipalTypeAwsAccount from the SDK. + return ap.PrincipalType == "AWS Account" && aws.ToString(ap.Principal) == account + }) } -func findAuthorizeVPCEndpointAccess(ctx context.Context, conn *opensearch.Client, input *opensearch.ListVpcEndpointAccessInput) (*awstypes.AuthorizedPrincipal, error) { - output, err := findAuthorizeVPCEndpointAccesses(ctx, conn, input) +func findAuthorizeVPCEndpointAccess(ctx context.Context, conn *opensearch.Client, input *opensearch.ListVpcEndpointAccessInput, filter tfslices.Predicate[*awstypes.AuthorizedPrincipal]) (*awstypes.AuthorizedPrincipal, error) { + output, err := findAuthorizeVPCEndpointAccesses(ctx, conn, input, filter) if err != nil { return nil, err @@ -186,7 +207,7 @@ func findAuthorizeVPCEndpointAccess(ctx context.Context, conn *opensearch.Client return tfresource.AssertSingleValueResult(output) } -func findAuthorizeVPCEndpointAccesses(ctx context.Context, conn *opensearch.Client, input *opensearch.ListVpcEndpointAccessInput) ([]awstypes.AuthorizedPrincipal, error) { +func findAuthorizeVPCEndpointAccesses(ctx context.Context, conn *opensearch.Client, input *opensearch.ListVpcEndpointAccessInput, filter tfslices.Predicate[*awstypes.AuthorizedPrincipal]) ([]awstypes.AuthorizedPrincipal, error) { var output []awstypes.AuthorizedPrincipal err := listVPCEndpointAccessPages(ctx, conn, input, func(page *opensearch.ListVpcEndpointAccessOutput, lastPage bool) bool { @@ -194,7 +215,11 @@ func findAuthorizeVPCEndpointAccesses(ctx context.Context, conn *opensearch.Clie return !lastPage } - output = append(output, page.AuthorizedPrincipalList...) + for _, v := range page.AuthorizedPrincipalList { + if filter(&v) { + output = append(output, v) + } + } return !lastPage }) diff --git a/internal/service/opensearch/authorize_vpc_endpoint_access_test.go b/internal/service/opensearch/authorize_vpc_endpoint_access_test.go index 327ec6b3ef61..e5c62d4da66e 100644 --- a/internal/service/opensearch/authorize_vpc_endpoint_access_test.go +++ b/internal/service/opensearch/authorize_vpc_endpoint_access_test.go @@ -5,7 +5,6 @@ package opensearch_test import ( "context" - "errors" "fmt" "testing" @@ -15,7 +14,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/create" tfopensearch "github.com/hashicorp/terraform-provider-aws/internal/service/opensearch" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" @@ -51,9 +49,8 @@ func TestAccOpenSearchAuthorizeVPCEndpointAccess_basic(t *testing.T) { { ResourceName: resourceName, ImportState: true, - ImportStateId: domainName, ImportStateVerifyIdentifierAttribute: names.AttrDomainName, - ImportStateIdFunc: testAccAuthorizeVPCEndpointAccessImportStateIDFunc(resourceName), + ImportStateIdFunc: acctest.AttrsImportStateIdFunc(resourceName, ",", names.AttrDomainName, "account"), }, }, }) @@ -96,8 +93,7 @@ func testAccCheckAuthorizeVPCEndpointAccessDestroy(ctx context.Context) resource continue } - _, err := tfopensearch.FindAuthorizeVPCEndpointAccessByName(ctx, conn, rs.Primary.Attributes[names.AttrDomainName]) - + _, err := tfopensearch.FindAuthorizeVPCEndpointAccessByTwoPartKey(ctx, conn, rs.Primary.Attributes[names.AttrDomainName], rs.Primary.Attributes["account"]) if tfresource.NotFound(err) { continue } @@ -106,48 +102,34 @@ func testAccCheckAuthorizeVPCEndpointAccessDestroy(ctx context.Context) resource return err } - return fmt.Errorf("Elastic Beanstalk Application Version %s still exists", rs.Primary.ID) + return fmt.Errorf("OpenSearch Authorize VPC Endpoint Access %s still exists", rs.Primary.Attributes[names.AttrDomainName]) } return nil } } -func testAccCheckAuthorizeVPCEndpointAccessExists(ctx context.Context, name string, authorizevpcendpointaccess *awstypes.AuthorizedPrincipal) resource.TestCheckFunc { +func testAccCheckAuthorizeVPCEndpointAccessExists(ctx context.Context, n string, v *awstypes.AuthorizedPrincipal) resource.TestCheckFunc { return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return create.Error(names.OpenSearch, create.ErrActionCheckingExistence, tfopensearch.ResNameAuthorizeVPCEndpointAccess, name, errors.New("not found")) - } - - if rs.Primary.ID == "" { - return create.Error(names.Route53Profiles, create.ErrActionCheckingExistence, tfopensearch.ResNameAuthorizeVPCEndpointAccess, name, errors.New("not set")) + return fmt.Errorf("Not found: %s", n) } conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchClient(ctx) - resp, err := tfopensearch.FindAuthorizeVPCEndpointAccessByName(ctx, conn, rs.Primary.Attributes[names.AttrDomainName]) + output, err := tfopensearch.FindAuthorizeVPCEndpointAccessByTwoPartKey(ctx, conn, rs.Primary.Attributes[names.AttrDomainName], rs.Primary.Attributes["account"]) + if err != nil { - return create.Error(names.OpenSearch, create.ErrActionCheckingExistence, tfopensearch.ResNameAuthorizeVPCEndpointAccess, rs.Primary.ID, err) + return err } - *authorizevpcendpointaccess = *resp + *v = *output return nil } } -func testAccAuthorizeVPCEndpointAccessImportStateIDFunc(resourceName string) resource.ImportStateIdFunc { - return func(s *terraform.State) (string, error) { - rs, ok := s.RootModule().Resources[resourceName] - if !ok { - return "", fmt.Errorf("Not found: %s", resourceName) - } - - return rs.Primary.Attributes[names.AttrDomainName], nil - } -} - func testAccAuthorizeVPCEndpointAccessConfig_basic(rName, domainName string) string { return acctest.ConfigCompose(testAccVPCEndpointConfig_base(rName, domainName), ` data "aws_caller_identity" "current" {} diff --git a/internal/service/opensearch/domain.go b/internal/service/opensearch/domain.go index 8a77505f0cb3..b5c08690bfcb 100644 --- a/internal/service/opensearch/domain.go +++ b/internal/service/opensearch/domain.go @@ -564,6 +564,40 @@ func resourceDomain() *schema.Resource { Optional: true, Computed: true, }, + "identity_center_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled_api_access": { + Type: schema.TypeBool, + Optional: true, + }, + "identity_center_instance_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + DiffSuppressFunc: suppressDiffIfIdentityCenterOptionsDisabled, + }, + "roles_key": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateDiagFunc: enum.Validate[awstypes.RolesKeyIdCOption](), + DiffSuppressFunc: suppressDiffIfIdentityCenterOptionsDisabled, + }, + "subject_key": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateDiagFunc: enum.Validate[awstypes.SubjectKeyIdCOption](), + DiffSuppressFunc: suppressDiffIfIdentityCenterOptionsDisabled, + }, + }, + }, + }, names.AttrIPAddressType: { Type: schema.TypeString, Optional: true, @@ -720,6 +754,14 @@ func resourceDomain() *schema.Resource { } } +func suppressDiffIfIdentityCenterOptionsDisabled(_, _, _ string, d *schema.ResourceData) bool { + // `!ok` means the attribute is not set, or the attribute is set to false + if _, ok := d.GetOk("identity_center_options.0.enabled_api_access"); !ok { + return true + } + return false +} + func resourceDomainCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchClient(ctx) @@ -906,6 +948,27 @@ func resourceDomainCreate(ctx context.Context, d *schema.ResourceData, meta any) } } + if v, ok := d.GetOk("identity_center_options"); ok { + input := opensearch.UpdateDomainConfigInput{ + IdentityCenterOptions: expandIdentityCenterOptions(v.([]any)), + DomainName: aws.String(name), + } + + _, err := tfresource.RetryWhen(ctx, propagationTimeout, + func(ctx context.Context) (any, error) { + return conn.UpdateDomainConfig(ctx, &input) + }, + domainErrorRetryable, + ) + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating OpenSearch Domain (%s) Config: %s", d.Id(), err) + } + + if err := waitForDomainUpdate(ctx, conn, name, d.Timeout(schema.TimeoutCreate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for OpenSearch Domain (%s) update: %s", d.Id(), err) + } + } + return append(diags, resourceDomainRead(ctx, d, meta)...) } @@ -989,6 +1052,11 @@ func resourceDomainRead(ctx context.Context, d *schema.ResourceData, meta any) d return sdkdiag.AppendErrorf(diags, "setting encrypt_at_rest: %s", err) } d.Set(names.AttrEngineVersion, ds.EngineVersion) + if ds.IdentityCenterOptions != nil { + if err := d.Set("identity_center_options", flattenIdentityCenterOptions(ds.IdentityCenterOptions)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting identity_center_options: %s", err) + } + } d.Set(names.AttrIPAddressType, ds.IPAddressType) // Remove any disabled log types that aren't in state. var inStateLogTypes []string @@ -1157,6 +1225,15 @@ func resourceDomainUpdate(ctx context.Context, d *schema.ResourceData, meta any) } } + if d.HasChange("identity_center_options") { + if v, ok := d.GetOk("identity_center_options"); ok && len(v.([]any)) > 0 { + input.IdentityCenterOptions = expandIdentityCenterOptions(d.Get("identity_center_options").([]any)) + } else { + // Identity Center Options is disabled when empty object is provided. + input.IdentityCenterOptions = &awstypes.IdentityCenterOptionsInput{} + } + } + if d.HasChange(names.AttrIPAddressType) { input.IPAddressType = awstypes.IPAddressType(d.Get(names.AttrIPAddressType).(string)) } diff --git a/internal/service/opensearch/domain_data_source.go b/internal/service/opensearch/domain_data_source.go index 66103c05a9a3..4ad5bd307803 100644 --- a/internal/service/opensearch/domain_data_source.go +++ b/internal/service/opensearch/domain_data_source.go @@ -321,6 +321,30 @@ func dataSourceDomain() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "identity_center_options": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled_api_access": { + Type: schema.TypeBool, + Computed: true, + }, + "identity_center_instance_arn": { + Type: schema.TypeString, + Computed: true, + }, + "roles_key": { + Type: schema.TypeString, + Computed: true, + }, + "subject_key": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, names.AttrIPAddressType: { Type: schema.TypeString, Computed: true, @@ -359,8 +383,7 @@ func dataSourceDomain() *schema.Resource { }, "off_peak_window_options": { Type: schema.TypeList, - Optional: true, - MaxItems: 1, + Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ names.AttrEnabled: { @@ -572,6 +595,11 @@ func dataSourceDomainRead(ctx context.Context, d *schema.ResourceData, meta any) } d.Set(names.AttrEngineVersion, ds.EngineVersion) + if ds.IdentityCenterOptions != nil { + if err := d.Set("identity_center_options", flattenIdentityCenterOptions(ds.IdentityCenterOptions)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting identity_center_options: %s", err) + } + } d.Set(names.AttrIPAddressType, ds.IPAddressType) if err := d.Set("cognito_options", flattenCognitoOptions(ds.CognitoOptions)); err != nil { diff --git a/internal/service/opensearch/domain_data_source_test.go b/internal/service/opensearch/domain_data_source_test.go index 0ccc3394e8c5..821cfe8f42ce 100644 --- a/internal/service/opensearch/domain_data_source_test.go +++ b/internal/service/opensearch/domain_data_source_test.go @@ -73,6 +73,7 @@ func TestAccOpenSearchDomainDataSource_complex(t *testing.T) { resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_size", resourceName, "ebs_options.0.volume_size"), resource.TestCheckResourceAttrPair(datasourceName, "ebs_options.0.volume_type", resourceName, "ebs_options.0.volume_type"), resource.TestCheckResourceAttrPair(datasourceName, names.AttrEngineVersion, resourceName, names.AttrEngineVersion), + resource.TestCheckResourceAttrPair(datasourceName, "identity_center_options.#", resourceName, "identity_center_options.#"), resource.TestCheckResourceAttrPair(datasourceName, "log_publishing_options.#", resourceName, "log_publishing_options.#"), resource.TestCheckResourceAttrPair(datasourceName, "off_peak_window_options.#", resourceName, "off_peak_window_options.#"), resource.TestCheckResourceAttrPair(datasourceName, "snapshot_options.#", resourceName, "snapshot_options.#"), diff --git a/internal/service/opensearch/domain_structure.go b/internal/service/opensearch/domain_structure.go index 3f5bab082406..ab0d9b52c395 100644 --- a/internal/service/opensearch/domain_structure.go +++ b/internal/service/opensearch/domain_structure.go @@ -437,6 +437,65 @@ func getMasterUserOptions(d *schema.ResourceData) []any { return []any{} } +func expandIdentityCenterOptions(tfList []any) *awstypes.IdentityCenterOptionsInput { + if len(tfList) == 0 { + return nil + } + + if tfList[0] == nil { + return &awstypes.IdentityCenterOptionsInput{} + } + + apiObject := &awstypes.IdentityCenterOptionsInput{} + tfMap := tfList[0].(map[string]any) + + if v, ok := tfMap["enabled_api_access"].(bool); ok { + apiObject.EnabledAPIAccess = aws.Bool(v) + } + + if apiObject.EnabledAPIAccess != nil && aws.ToBool(apiObject.EnabledAPIAccess) { + if v, ok := tfMap["identity_center_instance_arn"].(string); ok && v != "" { + apiObject.IdentityCenterInstanceARN = aws.String(v) + } + + if v, ok := tfMap["roles_key"].(string); ok && v != "" { + apiObject.RolesKey = awstypes.RolesKeyIdCOption(v) + } + + if v, ok := tfMap["subject_key"].(string); ok && v != "" { + apiObject.SubjectKey = awstypes.SubjectKeyIdCOption(v) + } + } + + return apiObject +} + +func flattenIdentityCenterOptions(apiObject *awstypes.IdentityCenterOptions) []any { + if apiObject == nil { + return nil + } + + tfMap := map[string]any{} + + if v := apiObject.EnabledAPIAccess; v != nil { + tfMap["enabled_api_access"] = aws.ToBool(v) + } + + if v := apiObject.IdentityCenterInstanceARN; v != nil { + tfMap["identity_center_instance_arn"] = aws.ToString(v) + } + + if v := apiObject.RolesKey; v != "" { + tfMap["roles_key"] = v + } + + if v := apiObject.SubjectKey; v != "" { + tfMap["subject_key"] = v + } + + return []any{tfMap} +} + func expandLogPublishingOptions(tfList []any) map[string]awstypes.LogPublishingOption { apiObjects := make(map[string]awstypes.LogPublishingOption) diff --git a/internal/service/opensearch/domain_test.go b/internal/service/opensearch/domain_test.go index 435cc479ba08..88f9de8bdd9f 100644 --- a/internal/service/opensearch/domain_test.go +++ b/internal/service/opensearch/domain_test.go @@ -158,6 +158,7 @@ func TestAccOpenSearchDomain_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "aiml_options.#", "1"), resource.TestMatchResourceAttr(resourceName, "dashboard_endpoint", regexache.MustCompile(`.*(opensearch|es)\..*/_dashboards`)), resource.TestCheckResourceAttrSet(resourceName, names.AttrEngineVersion), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), resource.TestCheckResourceAttr(resourceName, "off_peak_window_options.#", "1"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"), resource.TestCheckResourceAttr(resourceName, "vpc_options.#", "0"), @@ -2388,6 +2389,114 @@ func TestAccOpenSearchDomain_AIMLOptions_createDisabled(t *testing.T) { }) } +func TestAccOpenSearchDomain_identityCenterOptions(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var domain awstypes.DomainStatus + rName := testAccRandomDomainName() + resourceName := "aws_opensearch_domain.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheckIAMServiceLinkedRole(ctx, t) + acctest.PreCheckSSOAdminInstances(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy(ctx), + Steps: []resource.TestStep{ + { + // Enable identity_center_options with explicit roles_key and subject_key + Config: testAccDomainConfig_identityCenterOptionsFull(rName, true, string(awstypes.RolesKeyIdCOptionGroupName), string(awstypes.SubjectKeyIdCOptionUserName)), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtTrue), + resource.TestCheckResourceAttrSet(resourceName, "identity_center_options.0.identity_center_instance_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.roles_key", string(awstypes.RolesKeyIdCOptionGroupName)), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.subject_key", string(awstypes.SubjectKeyIdCOptionUserName)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateId: rName, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "advanced_security_options.0.master_user_options", + }, + }, + { + // Update identity_center_options with different explicit roles_key and subject_key + Config: testAccDomainConfig_identityCenterOptionsFull(rName, true, string(awstypes.RolesKeyIdCOptionGroupId), string(awstypes.SubjectKeyIdCOptionUserId)), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtTrue), + resource.TestCheckResourceAttrSet(resourceName, "identity_center_options.0.identity_center_instance_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.roles_key", string(awstypes.RolesKeyIdCOptionGroupId)), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.subject_key", string(awstypes.SubjectKeyIdCOptionUserId)), + ), + }, + { + // Disable identity_center_options by setting enabled_api_access to false, leaving other attributes unchanged + Config: testAccDomainConfig_identityCenterOptionsFull(rName, false, string(awstypes.RolesKeyIdCOptionGroupId), string(awstypes.SubjectKeyIdCOptionUserId)), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtFalse), + ), + }, + { + // Re-enable identity_center_options with roles_key and subject_key unspecified to test defaults + Config: testAccDomainConfig_identityCenterOptionsDefault(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtTrue), + resource.TestCheckResourceAttrSet(resourceName, "identity_center_options.0.identity_center_instance_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.roles_key", string(awstypes.RolesKeyIdCOptionGroupId)), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.subject_key", string(awstypes.SubjectKeyIdCOptionUserId)), + ), + }, + { + // Disable identity_center_options by just specifying enabled_api_access as false, with other attributes unspecified + Config: testAccDomainConfig_identityCenterOptionsEnabledFalse(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtFalse), + ), + }, + { + // Re-enable identity_center_options + Config: testAccDomainConfig_identityCenterOptionsDefault(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtTrue), + resource.TestCheckResourceAttrSet(resourceName, "identity_center_options.0.identity_center_instance_arn"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.roles_key", string(awstypes.RolesKeyIdCOptionGroupId)), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.subject_key", string(awstypes.SubjectKeyIdCOptionUserId)), + ), + }, + { + // Disable identity_center_options by removing the block entirely + Config: testAccDomainConfig_identityCenterOptionsRemoved(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "identity_center_options.0.enabled_api_access", acctest.CtFalse), + ), + }, + }, + }) +} + func TestAccOpenSearchDomain_disappears(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -4380,3 +4489,187 @@ resource "aws_opensearch_domain" "test" { } `, rName, desiredState, S3VecotrsEnabled) } + +func testAccDomainConfig_identityCenterOptionsFull(rName string, enableAPIAccess bool, rolesKey, subjectKey string) string { + return fmt.Sprintf(` +data "aws_ssoadmin_instances" "test" {} + +resource "aws_opensearch_domain" "test" { + domain_name = %[1]q + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + cluster_config { + instance_type = "t3.small.search" + instance_count = 1 + } + + advanced_security_options { + enabled = true + internal_user_database_enabled = true + master_user_options { + master_user_name = "testmasteruser" + master_user_password = "Barbarbarbar1!" + } + } + + encrypt_at_rest { + enabled = true + } + + node_to_node_encryption { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } + + identity_center_options { + enabled_api_access = %[2]t + identity_center_instance_arn = tolist(data.aws_ssoadmin_instances.test.arns)[0] + roles_key = %[3]q + subject_key = %[4]q + } +} +`, rName, enableAPIAccess, rolesKey, subjectKey) +} + +func testAccDomainConfig_identityCenterOptionsDefault(rName string, enableAPIAccess bool) string { + return fmt.Sprintf(` +data "aws_ssoadmin_instances" "test" {} + +resource "aws_opensearch_domain" "test" { + domain_name = %[1]q + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + cluster_config { + instance_type = "t3.small.search" + instance_count = 1 + } + + advanced_security_options { + enabled = true + internal_user_database_enabled = true + master_user_options { + master_user_name = "testmasteruser" + master_user_password = "Barbarbarbar1!" + } + } + + encrypt_at_rest { + enabled = true + } + + node_to_node_encryption { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } + + identity_center_options { + enabled_api_access = %[2]t + identity_center_instance_arn = tolist(data.aws_ssoadmin_instances.test.arns)[0] + } +} +`, rName, enableAPIAccess) +} + +func testAccDomainConfig_identityCenterOptionsEnabledFalse(rName string) string { + return fmt.Sprintf(` +data "aws_ssoadmin_instances" "test" {} + +resource "aws_opensearch_domain" "test" { + domain_name = %[1]q + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + cluster_config { + instance_type = "t3.small.search" + instance_count = 1 + } + + advanced_security_options { + enabled = true + internal_user_database_enabled = true + master_user_options { + master_user_name = "testmasteruser" + master_user_password = "Barbarbarbar1!" + } + } + + encrypt_at_rest { + enabled = true + } + + node_to_node_encryption { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } + + identity_center_options { + enabled_api_access = false + } +} +`, rName) +} + +func testAccDomainConfig_identityCenterOptionsRemoved(rName string) string { + return fmt.Sprintf(` +data "aws_ssoadmin_instances" "test" {} + +resource "aws_opensearch_domain" "test" { + domain_name = %[1]q + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + cluster_config { + instance_type = "t3.small.search" + instance_count = 1 + } + + advanced_security_options { + enabled = true + internal_user_database_enabled = true + master_user_options { + master_user_name = "testmasteruser" + master_user_password = "Barbarbarbar1!" + } + } + + encrypt_at_rest { + enabled = true + } + + node_to_node_encryption { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } +} +`, rName) +} diff --git a/internal/service/opensearch/exports_test.go b/internal/service/opensearch/exports_test.go index 4709d3e602d7..54b41fa270a5 100644 --- a/internal/service/opensearch/exports_test.go +++ b/internal/service/opensearch/exports_test.go @@ -5,19 +5,19 @@ package opensearch // Exports for use in tests only. var ( + ResourceAuthorizeVPCEndpointAccess = newAuthorizeVPCEndpointAccessResource ResourceDomainSAMLOptions = resourceDomainSAMLOptions ResourceInboundConnectionAccepter = resourceInboundConnectionAccepter ResourceOutboundConnection = resourceOutboundConnection ResourcePackage = resourcePackage ResourcePackageAssociation = resourcePackageAssociation ResourceVPCEndpoint = resourceVPCEndpoint - ResourceAuthorizeVPCEndpointAccess = newAuthorizeVPCEndpointAccessResource - FindDomainByName = findDomainByName - FindPackageByID = findPackageByID - FindPackageAssociationByTwoPartKey = findPackageAssociationByTwoPartKey - FindVPCEndpointByID = findVPCEndpointByID - FindAuthorizeVPCEndpointAccessByName = findAuthorizeVPCEndpointAccessByName + FindAuthorizeVPCEndpointAccessByTwoPartKey = findAuthorizeVPCEndpointAccessByTwoPartKey + FindDomainByName = findDomainByName + FindPackageByID = findPackageByID + FindPackageAssociationByTwoPartKey = findPackageAssociationByTwoPartKey + FindVPCEndpointByID = findVPCEndpointByID EBSVolumeTypePermitsIopsInput = ebsVolumeTypePermitsIopsInput EBSVolumeTypePermitsThroughputInput = ebsVolumeTypePermitsThroughputInput diff --git a/internal/service/organizations/organization.go b/internal/service/organizations/organization.go index 2f751e564280..655d067813b6 100644 --- a/internal/service/organizations/organization.go +++ b/internal/service/organizations/organization.go @@ -343,37 +343,35 @@ func resourceOrganizationUpdate(ctx context.Context, d *schema.ResourceData, met var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OrganizationsClient(ctx) - if d.HasChange("aws_service_access_principals") { - o, n := d.GetChange("aws_service_access_principals") - os, ns := o.(*schema.Set), n.(*schema.Set) - add, del := flex.ExpandStringValueSet(ns.Difference(os)), flex.ExpandStringValueSet(os.Difference(ns)) + if d.HasChanges("aws_service_access_principals", "enabled_policy_types") { + oa, na := d.GetChange("aws_service_access_principals") + oas, nas := oa.(*schema.Set), na.(*schema.Set) + adda, dela := flex.ExpandStringValueSet(nas.Difference(oas)), flex.ExpandStringValueSet(oas.Difference(nas)) - for _, v := range del { - if err := disableServicePrincipal(ctx, conn, v); err != nil { + defaultRootID := d.Get("roots.0.id").(string) + ot, nt := d.GetChange("enabled_policy_types") + ots, nts := ot.(*schema.Set), nt.(*schema.Set) + addt, delt := flex.ExpandStringValueSet(nts.Difference(ots)), flex.ExpandStringValueSet(ots.Difference(nts)) + + for _, v := range delt { + if err := disablePolicyType(ctx, conn, awstypes.PolicyType(v), defaultRootID); err != nil { return sdkdiag.AppendFromErr(diags, err) } } - for _, v := range add { - if err := enableServicePrincipal(ctx, conn, v); err != nil { + for _, v := range dela { + if err := disableServicePrincipal(ctx, conn, v); err != nil { return sdkdiag.AppendFromErr(diags, err) } } - } - - if d.HasChange("enabled_policy_types") { - defaultRootID := d.Get("roots.0.id").(string) - o, n := d.GetChange("enabled_policy_types") - os, ns := o.(*schema.Set), n.(*schema.Set) - add, del := flex.ExpandStringValueSet(ns.Difference(os)), flex.ExpandStringValueSet(os.Difference(ns)) - for _, v := range del { - if err := disablePolicyType(ctx, conn, awstypes.PolicyType(v), defaultRootID); err != nil { + for _, v := range adda { + if err := enableServicePrincipal(ctx, conn, v); err != nil { return sdkdiag.AppendFromErr(diags, err) } } - for _, v := range add { + for _, v := range addt { if err := enablePolicyType(ctx, conn, awstypes.PolicyType(v), defaultRootID); err != nil { return sdkdiag.AppendFromErr(diags, err) } diff --git a/internal/service/organizations/organization_test.go b/internal/service/organizations/organization_test.go index 05a47c04f703..a637c1258224 100644 --- a/internal/service/organizations/organization_test.go +++ b/internal/service/organizations/organization_test.go @@ -40,7 +40,7 @@ func testAccOrganization_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "accounts.0.arn", resourceName, "master_account_arn"), resource.TestCheckResourceAttrPair(resourceName, "accounts.0.email", resourceName, "master_account_email"), resource.TestCheckResourceAttrPair(resourceName, "accounts.0.id", resourceName, "master_account_id"), - acctest.CheckResourceAttrGlobalARNFormat(ctx, resourceName, names.AttrARN, "organizations", "organization/o-{id}"), + acctest.CheckResourceAttrGlobalARNFormat(ctx, resourceName, names.AttrARN, "organizations", "organization/{id}"), resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "feature_set", string(awstypes.OrganizationFeatureSetAll)), acctest.MatchResourceAttrGlobalARN(ctx, resourceName, "master_account_arn", "organizations", regexache.MustCompile(`account/`+organizationIDRegexPattern+`/\d{12}$`)), @@ -146,6 +146,7 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeServiceControlPolicy)), Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeServiceControlPolicy)), ), @@ -159,6 +160,7 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_basic, Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "0"), ), }, @@ -166,6 +168,7 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeAiservicesOptOutPolicy)), Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeAiservicesOptOutPolicy)), ), @@ -174,6 +177,7 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeServiceControlPolicy)), Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeServiceControlPolicy)), ), @@ -182,18 +186,57 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeBackupPolicy)), Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeBackupPolicy)), ), }, + { + Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeChatbotPolicy)), + Check: resource.ComposeTestCheckFunc( + testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeChatbotPolicy)), + ), + }, + { + Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeDeclarativePolicyEc2)), + Check: resource.ComposeTestCheckFunc( + testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeDeclarativePolicyEc2)), + ), + }, + { + Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeResourceControlPolicy)), + Check: resource.ComposeTestCheckFunc( + testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeResourceControlPolicy)), + ), + }, { Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeTagPolicy)), Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeTagPolicy)), ), }, + { + Config: testAccOrganizationConfig_enabledPolicyTypeWithServiceAccessPrincipals(string(awstypes.PolicyTypeSecurityhubPolicy), "securityhub.amazonaws.com"), + Check: resource.ComposeTestCheckFunc( + testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "aws_service_access_principals.*", "securityhub.amazonaws.com"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.0", string(awstypes.PolicyTypeSecurityhubPolicy)), + ), + }, { ResourceName: resourceName, ImportState: true, @@ -203,6 +246,7 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_basic, Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "0"), ), }, @@ -210,6 +254,7 @@ func testAccOrganization_EnabledPolicyTypes(t *testing.T) { Config: testAccOrganizationConfig_enabledPolicyTypes1(string(awstypes.PolicyTypeTagPolicy)), Check: resource.ComposeTestCheckFunc( testAccCheckOrganizationExists(ctx, resourceName, &organization), + resource.TestCheckResourceAttr(resourceName, "aws_service_access_principals.#", "0"), resource.TestCheckResourceAttr(resourceName, "enabled_policy_types.#", "1"), ), }, @@ -411,6 +456,15 @@ resource "aws_organizations_organization" "test" { `, policyType1) } +func testAccOrganizationConfig_enabledPolicyTypeWithServiceAccessPrincipals(policyType1, serviceAccessPrincipals string) string { + return fmt.Sprintf(` +resource "aws_organizations_organization" "test" { + aws_service_access_principals = [%[2]q] + enabled_policy_types = [%[1]q] +} +`, policyType1, serviceAccessPrincipals) +} + func testAccOrganizationConfig_featureSet(featureSet string) string { return fmt.Sprintf(` resource "aws_organizations_organization" "test" { diff --git a/internal/service/pipes/pipe.go b/internal/service/pipes/pipe.go index 075de74a8f67..a7fe2abfb8b1 100644 --- a/internal/service/pipes/pipe.go +++ b/internal/service/pipes/pipe.go @@ -25,7 +25,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -208,7 +208,7 @@ func resourcePipeRead(ctx context.Context, d *schema.ResourceData, meta any) dia d.Set(names.AttrDescription, output.Description) d.Set("desired_state", output.DesiredState) d.Set("enrichment", output.Enrichment) - if v := output.EnrichmentParameters; !types.IsZero(v) { + if v := output.EnrichmentParameters; !inttypes.IsZero(v) { if err := d.Set("enrichment_parameters", []any{flattenPipeEnrichmentParameters(v)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting enrichment_parameters: %s", err) } @@ -216,7 +216,7 @@ func resourcePipeRead(ctx context.Context, d *schema.ResourceData, meta any) dia d.Set("enrichment_parameters", nil) } d.Set("kms_key_identifier", output.KmsKeyIdentifier) - if v := output.LogConfiguration; !types.IsZero(v) { + if v := output.LogConfiguration; !inttypes.IsZero(v) { if err := d.Set("log_configuration", []any{flattenPipeLogConfiguration(v)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting log_configuration: %s", err) } @@ -227,7 +227,7 @@ func resourcePipeRead(ctx context.Context, d *schema.ResourceData, meta any) dia d.Set(names.AttrNamePrefix, create.NamePrefixFromName(aws.ToString(output.Name))) d.Set(names.AttrRoleARN, output.RoleArn) d.Set(names.AttrSource, output.Source) - if v := output.SourceParameters; !types.IsZero(v) { + if v := output.SourceParameters; !inttypes.IsZero(v) { if err := d.Set("source_parameters", []any{flattenPipeSourceParameters(v)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting source_parameters: %s", err) } @@ -235,7 +235,7 @@ func resourcePipeRead(ctx context.Context, d *schema.ResourceData, meta any) dia d.Set("source_parameters", nil) } d.Set(names.AttrTarget, output.Target) - if v := output.TargetParameters; !types.IsZero(v) { + if v := output.TargetParameters; !inttypes.IsZero(v) { if err := d.Set("target_parameters", []any{flattenPipeTargetParameters(v)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting target_parameters: %s", err) } diff --git a/internal/service/quicksight/account_settings.go b/internal/service/quicksight/account_settings.go index 1a26edfc96cb..b7be5c2af00c 100644 --- a/internal/service/quicksight/account_settings.go +++ b/internal/service/quicksight/account_settings.go @@ -28,7 +28,6 @@ import ( ) // @FrameworkResource("aws_quicksight_account_settings", name="Account Settings") -// @Region(global=true) func newAccountSettingsResource(_ context.Context) (resource.ResourceWithConfigure, error) { r := &accountSettingsResource{} @@ -38,10 +37,6 @@ func newAccountSettingsResource(_ context.Context) (resource.ResourceWithConfigu return r, nil } -const ( - ResNameAccountSettings = "Account Settings" -) - type accountSettingsResource struct { framework.ResourceWithModel[accountSettingsResourceModel] framework.WithNoOpDelete @@ -224,6 +219,7 @@ func findAccountSettingsByID(ctx context.Context, conn *quicksight.Client, id st } type accountSettingsResourceModel struct { + framework.WithRegionModel AWSAccountID types.String `tfsdk:"aws_account_id"` DefaultNamespace types.String `tfsdk:"default_namespace"` TerminationProtectionEnabled types.Bool `tfsdk:"termination_protection_enabled"` diff --git a/internal/service/quicksight/data_set_data_source_tags_gen_test.go b/internal/service/quicksight/data_set_data_source_tags_gen_test.go index b86d41fd066e..202bf8116d15 100644 --- a/internal/service/quicksight/data_set_data_source_tags_gen_test.go +++ b/internal/service/quicksight/data_set_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfquicksight "github.com/hashicorp/terraform-provider-aws/internal/service/quicksight" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccQuickSightDataSetDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *t } func expectFullDataSetDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfquicksight.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfquicksight.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), knownValue) } diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index fd49181ece5e..435dc2490c50 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -27,7 +27,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.Ser Factory: newAccountSettingsResource, TypeName: "aws_quicksight_account_settings", Name: "Account Settings", - Region: unique.Make(inttypes.ResourceRegionDisabled()), + Region: unique.Make(inttypes.ResourceRegionDefault()), }, { Factory: newCustomPermissionsResource, diff --git a/internal/service/ram/principal_association.go b/internal/service/ram/principal_association.go index a0bafd97bc52..39e072476789 100644 --- a/internal/service/ram/principal_association.go +++ b/internal/service/ram/principal_association.go @@ -24,7 +24,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -103,7 +103,7 @@ func resourcePrincipalAssociationCreate(ctx context.Context, d *schema.ResourceD d.SetId(id) // AWS Account ID principals need to be accepted to become ASSOCIATED. - if itypes.IsAWSAccountID(principal) { + if inttypes.IsAWSAccountID(principal) { return append(diags, resourcePrincipalAssociationRead(ctx, d, meta)...) } diff --git a/internal/service/rds/cluster.go b/internal/service/rds/cluster.go index 8e0b44716039..d1ae448b1801 100644 --- a/internal/service/rds/cluster.go +++ b/internal/service/rds/cluster.go @@ -31,7 +31,7 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -2144,7 +2144,7 @@ func statusDBCluster(ctx context.Context, conn *rds.Client, id string, waitNoPen status := aws.ToString(output.Status) - if status == clusterStatusAvailable && waitNoPendingModifiedValues && !itypes.IsZero(output.PendingModifiedValues) { + if status == clusterStatusAvailable && waitNoPendingModifiedValues && !inttypes.IsZero(output.PendingModifiedValues) { status = clusterStatusAvailableWithPendingModifiedValues } diff --git a/internal/service/rds/consts.go b/internal/service/rds/consts.go index ee4fbdbb078b..1c2e7fa511da 100644 --- a/internal/service/rds/consts.go +++ b/internal/service/rds/consts.go @@ -111,7 +111,9 @@ const ( instanceStatusStarting = "starting" instanceStatusStopped = "stopped" instanceStatusStopping = "stopping" + instanceStatusStorageConfigUpgrade = "storage-config-upgrade" instanceStatusStorageFull = "storage-full" + instanceStatusStorageInitialization = "storage-initialization" instanceStatusStorageOptimization = "storage-optimization" instanceStatusUpgrading = "upgrading" ) diff --git a/internal/service/rds/instance.go b/internal/service/rds/instance.go index bba122a47706..8c7e3d77c07f 100644 --- a/internal/service/rds/instance.go +++ b/internal/service/rds/instance.go @@ -2913,7 +2913,9 @@ func waitDBInstanceAvailable(ctx context.Context, conn *rds.Client, id string, t instanceStatusResettingMasterCredentials, instanceStatusStarting, instanceStatusStopping, + instanceStatusStorageConfigUpgrade, instanceStatusStorageFull, + instanceStatusStorageInitialization, instanceStatusUpgrading, }, Target: []string{instanceStatusAvailable, instanceStatusStorageOptimization}, @@ -3085,8 +3087,9 @@ func statusBlueGreenDeployment(conn *rds.Client, id string) retry.StateRefreshFu func waitBlueGreenDeploymentAvailable(ctx context.Context, conn *rds.Client, id string, timeout time.Duration, optFns ...tfresource.OptionsFunc) (*types.BlueGreenDeployment, error) { options := tfresource.Options{ - PollInterval: 10 * time.Second, - Delay: 1 * time.Minute, + PollInterval: 10 * time.Second, + Delay: 1 * time.Minute, + ContinuousTargetOccurence: 3, } for _, fn := range optFns { fn(&options) diff --git a/internal/service/rds/instance_data_source_tags_gen_test.go b/internal/service/rds/instance_data_source_tags_gen_test.go index cc154b456b85..1fe80be19a72 100644 --- a/internal/service/rds/instance_data_source_tags_gen_test.go +++ b/internal/service/rds/instance_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfrds "github.com/hashicorp/terraform-provider-aws/internal/service/rds" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccRDSDBInstanceDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testi } func expectFullDBInstanceDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfrds.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfrds.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: "db_instance_arn", }), knownValue) } diff --git a/internal/service/rds/instance_test.go b/internal/service/rds/instance_test.go index c71372e93732..f19fe17b4ccb 100644 --- a/internal/service/rds/instance_test.go +++ b/internal/service/rds/instance_test.go @@ -6617,7 +6617,7 @@ func TestAccRDSInstance_BlueGreenDeployment_updateParameterGroup(t *testing.T) { CheckDestroy: testAccCheckDBInstanceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccInstanceConfig_BlueGreenDeployment_basic(rName), + Config: testAccInstanceConfig_BlueGreenDeployment_basic(rName, false), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckDBInstanceExists(ctx, resourceName, &v1), resource.TestCheckResourceAttr(resourceName, "backup_retention_period", "1"), @@ -6625,7 +6625,60 @@ func TestAccRDSInstance_BlueGreenDeployment_updateParameterGroup(t *testing.T) { ), }, { - Config: testAccInstanceConfig_BlueGreenDeployment_parameterGroup(rName), + Config: testAccInstanceConfig_BlueGreenDeployment_parameterGroup(rName, false), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDBInstanceExists(ctx, resourceName, &v2), + testAccCheckDBInstanceRecreated(&v1, &v2), + resource.TestCheckResourceAttrPair(resourceName, names.AttrParameterGroupName, parameterGroupResourceName, names.AttrName), + resource.TestCheckResourceAttr(resourceName, "blue_green_update.0.enabled", acctest.CtTrue), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrApplyImmediately, + names.AttrFinalSnapshotIdentifier, + names.AttrPassword, + "skip_final_snapshot", + "delete_automated_backups", + "latest_restorable_time", // This causes intermittent failures when the value increments + "blue_green_update", + }, + }, + }, + }) +} + +func TestAccRDSInstance_BlueGreenDeployment_updateParameterGroupNonTFamilyInstances(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v1, v2 types.DBInstance + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_db_instance.test" + parameterGroupResourceName := "aws_db_parameter_group.test" + parameterGroupDataSource := "data.aws_db_parameter_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RDSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDBInstanceDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfig_BlueGreenDeployment_basic(rName, true), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDBInstanceExists(ctx, resourceName, &v1), + resource.TestCheckResourceAttr(resourceName, "backup_retention_period", "1"), + resource.TestCheckResourceAttrPair(resourceName, names.AttrParameterGroupName, parameterGroupDataSource, names.AttrName), + ), + }, + { + Config: testAccInstanceConfig_BlueGreenDeployment_parameterGroup(rName, true), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckDBInstanceExists(ctx, resourceName, &v2), testAccCheckDBInstanceRecreated(&v1, &v2), @@ -14166,10 +14219,14 @@ resource "aws_db_instance" "test" { `, tfrds.InstanceEngineMySQL, "general-public-license", "standard", halfMainInstClass, rName)) } -func testAccInstanceConfig_BlueGreenDeployment_parameterGroup(rName string) string { +func testAccInstanceConfig_BlueGreenDeployment_parameterGroup(rName string, excludeTFamilyInstances bool) string { + instanceConfig := testAccInstanceConfig_orderableClassMySQL() + if excludeTFamilyInstances { + instanceConfig = strings.Replace(instanceConfig, "db.t", "frodo", -1) + } return acctest.ConfigCompose( acctest.ConfigRandomPassword(), - testAccInstanceConfig_orderableClassMySQL(), + instanceConfig, fmt.Sprintf(` resource "aws_db_instance" "test" { identifier = %[1]q @@ -14232,10 +14289,14 @@ resource "aws_db_instance" "test" { `, rName, tagKey1, tagValue1)) } -func testAccInstanceConfig_BlueGreenDeployment_basic(rName string) string { +func testAccInstanceConfig_BlueGreenDeployment_basic(rName string, excludeTFamilyInstances bool) string { + instanceConfig := testAccInstanceConfig_orderableClassMySQL() + if excludeTFamilyInstances { + instanceConfig = strings.Replace(instanceConfig, "db.t", "frodo", -1) + } return acctest.ConfigCompose( acctest.ConfigRandomPassword(), - testAccInstanceConfig_orderableClassMySQL(), + instanceConfig, fmt.Sprintf(` data "aws_db_parameter_group" "test" { name = "default.${data.aws_rds_engine_version.default.parameter_group_family}" diff --git a/internal/service/redshift/cluster.go b/internal/service/redshift/cluster.go index 091b59400ab7..81d5750c7326 100644 --- a/internal/service/redshift/cluster.go +++ b/internal/service/redshift/cluster.go @@ -38,6 +38,8 @@ import ( // @SDKResource("aws_redshift_cluster", name="Cluster") // @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.Cluster") +// @Testing(importIgnore="final_snapshot_identifier;master_password;skip_final_snapshot;apply_immediately") func resourceCluster() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceClusterCreate, diff --git a/internal/service/redshift/cluster_data_source.go b/internal/service/redshift/cluster_data_source.go index eaae67c362dc..e157b5ae0fc7 100644 --- a/internal/service/redshift/cluster_data_source.go +++ b/internal/service/redshift/cluster_data_source.go @@ -22,6 +22,7 @@ import ( // @SDKDataSource("aws_redshift_cluster", name="Cluster") // @Tags +// @Testing(tagsIdentifierAttribute="arn") func dataSourceCluster() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceClusterRead, diff --git a/internal/service/redshift/cluster_data_source_tags_gen_test.go b/internal/service/redshift/cluster_data_source_tags_gen_test.go new file mode 100644 index 000000000000..052c2bb2955a --- /dev/null +++ b/internal/service/redshift/cluster_data_source_tags_gen_test.go @@ -0,0 +1,211 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "context" + "testing" + "unique" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + tfredshift "github.com/hashicorp/terraform-provider-aws/internal/service/redshift" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftClusterDataSource_tags(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + }) +} + +func TestAccRedshiftClusterDataSource_tags_NullMap(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccRedshiftClusterDataSource_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccRedshiftClusterDataSource_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/data.tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + }) +} + +func TestAccRedshiftClusterDataSource_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/data.tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullClusterDataSourceTags(ctx, dataSourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + }) +} + +func TestAccRedshiftClusterDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/data.tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + expectFullClusterDataSourceTags(ctx, dataSourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func expectFullClusterDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfredshift.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }), knownValue) +} diff --git a/internal/service/redshift/cluster_snapshot.go b/internal/service/redshift/cluster_snapshot.go index 56bfa6528b28..0f1a9b07f014 100644 --- a/internal/service/redshift/cluster_snapshot.go +++ b/internal/service/redshift/cluster_snapshot.go @@ -22,6 +22,7 @@ import ( // @SDKResource("aws_redshift_cluster_snapshot", name="Cluster Snapshot") // @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.Snapshot") func resourceClusterSnapshot() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceClusterSnapshotCreate, diff --git a/internal/service/redshift/cluster_snapshot_tags_gen_test.go b/internal/service/redshift/cluster_snapshot_tags_gen_test.go new file mode 100644 index 000000000000..3dae9292c382 --- /dev/null +++ b/internal/service/redshift/cluster_snapshot_tags_gen_test.go @@ -0,0 +1,2293 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftClusterSnapshot_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftClusterSnapshot_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Snapshot + resourceName := "aws_redshift_cluster_snapshot.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ClusterSnapshot/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterSnapshotExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/cluster_snapshot_test.go b/internal/service/redshift/cluster_snapshot_test.go index a737844e11cd..eb4259de912a 100644 --- a/internal/service/redshift/cluster_snapshot_test.go +++ b/internal/service/redshift/cluster_snapshot_test.go @@ -64,52 +64,6 @@ func TestAccRedshiftClusterSnapshot_basic(t *testing.T) { }) } -func TestAccRedshiftClusterSnapshot_tags(t *testing.T) { - ctx := acctest.Context(t) - var v awstypes.Snapshot - resourceName := "aws_redshift_cluster_snapshot.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterSnapshotDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccClusterSnapshotConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckClusterSnapshotExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccClusterSnapshotConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckClusterSnapshotExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccClusterSnapshotConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckClusterSnapshotExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftClusterSnapshot_disappears(t *testing.T) { ctx := acctest.Context(t) var v awstypes.Snapshot @@ -203,29 +157,3 @@ resource "aws_redshift_cluster_snapshot" "test" { } `, rName, retention)) } - -func testAccClusterSnapshotConfig_tags1(rName, tagKey1, tagValue1 string) string { - return acctest.ConfigCompose(testAccClusterConfig_basic(rName), fmt.Sprintf(` -resource "aws_redshift_cluster_snapshot" "test" { - cluster_identifier = aws_redshift_cluster.test.cluster_identifier - snapshot_identifier = %[1]q - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1)) -} - -func testAccClusterSnapshotConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(testAccClusterConfig_basic(rName), fmt.Sprintf(` -resource "aws_redshift_cluster_snapshot" "test" { - cluster_identifier = aws_redshift_cluster.test.cluster_identifier - snapshot_identifier = %[1]q - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) -} diff --git a/internal/service/redshift/cluster_tags_gen_test.go b/internal/service/redshift/cluster_tags_gen_test.go new file mode 100644 index 000000000000..99d683e14238 --- /dev/null +++ b/internal/service/redshift/cluster_tags_gen_test.go @@ -0,0 +1,2386 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftCluster_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrFinalSnapshotIdentifier, "master_password", "skip_final_snapshot", names.AttrApplyImmediately, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftCluster_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Cluster + resourceName := "aws_redshift_cluster.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckClusterDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Cluster/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckClusterExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/cluster_test.go b/internal/service/redshift/cluster_test.go index f5d700156625..fb3b8f5f529a 100644 --- a/internal/service/redshift/cluster_test.go +++ b/internal/service/redshift/cluster_test.go @@ -422,58 +422,6 @@ func TestAccRedshiftCluster_updateNodeType(t *testing.T) { }) } -func TestAccRedshiftCluster_tags(t *testing.T) { - ctx := acctest.Context(t) - var v awstypes.Cluster - resourceName := "aws_redshift_cluster.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckClusterDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccClusterConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckClusterExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - names.AttrFinalSnapshotIdentifier, - "master_password", - "skip_final_snapshot", - names.AttrApplyImmediately, - }, - }, - { - Config: testAccClusterConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckClusterExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccClusterConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckClusterExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftCluster_masterUsername(t *testing.T) { ctx := acctest.Context(t) var v1, v2 awstypes.Cluster @@ -1615,47 +1563,6 @@ resource "aws_redshift_cluster" "test" { `, rName) } -func testAccClusterConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_redshift_cluster" "test" { - cluster_identifier = %[1]q - database_name = "mydb" - encrypted = true - master_username = "foo" - master_password = "Mustbe8characters" - node_type = "ra3.large" - automated_snapshot_retention_period = 7 - allow_version_upgrade = false - skip_final_snapshot = true - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccClusterConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_redshift_cluster" "test" { - cluster_identifier = %[1]q - database_name = "mydb" - encrypted = true - master_username = "foo" - master_password = "Mustbe8characters" - node_type = "ra3.large" - automated_snapshot_retention_period = 7 - allow_version_upgrade = false - skip_final_snapshot = true - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} - func testAccClusterConfig_publiclyAccessible(rName string, publiclyAccessible bool) string { return acctest.ConfigCompose( acctest.ConfigVPCWithSubnets(rName, 3), diff --git a/internal/service/redshift/event_subscription.go b/internal/service/redshift/event_subscription.go index 4a2a2fd9cdcb..b5d8bcb3ec22 100644 --- a/internal/service/redshift/event_subscription.go +++ b/internal/service/redshift/event_subscription.go @@ -29,6 +29,7 @@ import ( // @SDKResource("aws_redshift_event_subscription", name="Event Subscription") // @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.EventSubscription") func resourceEventSubscription() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEventSubscriptionCreate, diff --git a/internal/service/redshift/event_subscription_tags_gen_test.go b/internal/service/redshift/event_subscription_tags_gen_test.go new file mode 100644 index 000000000000..65b4f0c5ab75 --- /dev/null +++ b/internal/service/redshift/event_subscription_tags_gen_test.go @@ -0,0 +1,2293 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftEventSubscription_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftEventSubscription_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.EventSubscription + resourceName := "aws_redshift_event_subscription.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/EventSubscription/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEventSubscriptionExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/event_subscription_test.go b/internal/service/redshift/event_subscription_test.go index 433fa090ad3b..b03d23441d35 100644 --- a/internal/service/redshift/event_subscription_test.go +++ b/internal/service/redshift/event_subscription_test.go @@ -148,52 +148,6 @@ func TestAccRedshiftEventSubscription_categoryUpdate(t *testing.T) { }) } -func TestAccRedshiftEventSubscription_tags(t *testing.T) { - ctx := acctest.Context(t) - var v awstypes.EventSubscription - resourceName := "aws_redshift_event_subscription.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckEventSubscriptionDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccEventSubscriptionConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckEventSubscriptionExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccEventSubscriptionConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckEventSubscriptionExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccEventSubscriptionConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckEventSubscriptionExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftEventSubscription_disappears(t *testing.T) { ctx := acctest.Context(t) var v awstypes.EventSubscription @@ -378,56 +332,3 @@ resource "aws_redshift_event_subscription" "test" { } `, rName) } - -func testAccEventSubscriptionConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_sns_topic" "test" { - name = %[1]q -} - -resource "aws_redshift_event_subscription" "test" { - name = %[1]q - sns_topic_arn = aws_sns_topic.test.arn - source_type = "cluster" - severity = "INFO" - - event_categories = [ - "configuration", - "management", - "monitoring", - "security", - ] - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccEventSubscriptionConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_sns_topic" "test" { - name = %[1]q -} - -resource "aws_redshift_event_subscription" "test" { - name = %[1]q - sns_topic_arn = aws_sns_topic.test.arn - source_type = "cluster" - severity = "INFO" - - event_categories = [ - "configuration", - "management", - "monitoring", - "security", - ] - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} diff --git a/internal/service/redshift/generate.go b/internal/service/redshift/generate.go index da6609fd2b09..2ba7117b768f 100644 --- a/internal/service/redshift/generate.go +++ b/internal/service/redshift/generate.go @@ -3,6 +3,8 @@ //go:generate go run ../../generate/tags/main.go -ServiceTagsSlice -TagOp=CreateTags -TagInIDElem=ResourceName -UntagOp=DeleteTags -UpdateTags //go:generate go run ../../generate/servicepackage/main.go +//go:generate go run ../../generate/tagstests/main.go +//go:generate go run ../../generate/identitytests/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. package redshift diff --git a/internal/service/redshift/hsm_client_certificate_tags_gen_test.go b/internal/service/redshift/hsm_client_certificate_tags_gen_test.go new file mode 100644 index 000000000000..8a473bb5e751 --- /dev/null +++ b/internal/service/redshift/hsm_client_certificate_tags_gen_test.go @@ -0,0 +1,2271 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftHSMClientCertificate_tags(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftHSMClientCertificate_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_client_certificate.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMClientCertificate/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMClientCertificateExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/hsm_client_certificate_test.go b/internal/service/redshift/hsm_client_certificate_test.go index bd375b2c9ffa..b2663de8e5ea 100644 --- a/internal/service/redshift/hsm_client_certificate_test.go +++ b/internal/service/redshift/hsm_client_certificate_test.go @@ -49,50 +49,6 @@ func TestAccRedshiftHSMClientCertificate_basic(t *testing.T) { }) } -func TestAccRedshiftHSMClientCertificate_tags(t *testing.T) { - ctx := acctest.Context(t) - resourceName := "aws_redshift_hsm_client_certificate.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckHSMClientCertificateDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccHSMClientCertificateConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckHSMClientCertificateExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccHSMClientCertificateConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckHSMClientCertificateExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, { - Config: testAccHSMClientCertificateConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckHSMClientCertificateExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftHSMClientCertificate_disappears(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_redshift_hsm_client_certificate.test" @@ -168,28 +124,3 @@ resource "aws_redshift_hsm_client_certificate" "test" { } `, rName) } - -func testAccHSMClientCertificateConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_redshift_hsm_client_certificate" "test" { - hsm_client_certificate_identifier = %[1]q - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccHSMClientCertificateConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_redshift_hsm_client_certificate" "test" { - hsm_client_certificate_identifier = %[1]q - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} diff --git a/internal/service/redshift/hsm_configuration.go b/internal/service/redshift/hsm_configuration.go index 8bb10a0b5a64..bf21414c0032 100644 --- a/internal/service/redshift/hsm_configuration.go +++ b/internal/service/redshift/hsm_configuration.go @@ -24,6 +24,7 @@ import ( // @SDKResource("aws_redshift_hsm_configuration", name="HSM Configuration") // @Tags(identifierAttribute="arn") +// @Testing(importIgnore="hsm_partition_password;hsm_server_public_certificate") func resourceHSMConfiguration() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceHSMConfigurationCreate, diff --git a/internal/service/redshift/hsm_configuration_tags_gen_test.go b/internal/service/redshift/hsm_configuration_tags_gen_test.go new file mode 100644 index 000000000000..2cc744d519d2 --- /dev/null +++ b/internal/service/redshift/hsm_configuration_tags_gen_test.go @@ -0,0 +1,2364 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftHSMConfiguration_tags(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "hsm_partition_password", "hsm_server_public_certificate", + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftHSMConfiguration_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_hsm_configuration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/HSMConfiguration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckHSMConfigurationExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/hsm_configuration_test.go b/internal/service/redshift/hsm_configuration_test.go index b837b639dc4c..ca52a5fc5136 100644 --- a/internal/service/redshift/hsm_configuration_test.go +++ b/internal/service/redshift/hsm_configuration_test.go @@ -49,51 +49,6 @@ func TestAccRedshiftHSMConfiguration_basic(t *testing.T) { }) } -func TestAccRedshiftHSMConfiguration_tags(t *testing.T) { - ctx := acctest.Context(t) - resourceName := "aws_redshift_hsm_configuration.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckHSMConfigurationDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccHSMConfigurationConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckHSMConfigurationExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"hsm_partition_password", "hsm_server_public_certificate"}, - }, - { - Config: testAccHSMConfigurationConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckHSMConfigurationExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, { - Config: testAccHSMConfigurationConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckHSMConfigurationExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftHSMConfiguration_disappears(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_redshift_hsm_configuration.test" @@ -174,38 +129,3 @@ resource "aws_redshift_hsm_configuration" "test" { } `, rName) } - -func testAccHSMConfigurationConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_redshift_hsm_configuration" "test" { - description = %[1]q - hsm_configuration_identifier = %[1]q - hsm_ip_address = "10.0.0.1" - hsm_partition_name = "aws" - hsm_partition_password = %[1]q - hsm_server_public_certificate = %[1]q - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccHSMConfigurationConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_redshift_hsm_configuration" "test" { - description = %[1]q - hsm_configuration_identifier = %[1]q - hsm_ip_address = "10.0.0.1" - hsm_partition_name = "aws" - hsm_partition_password = %[1]q - hsm_server_public_certificate = %[1]q - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} diff --git a/internal/service/redshift/integration.go b/internal/service/redshift/integration.go index da88179fca28..e73f28960ff2 100644 --- a/internal/service/redshift/integration.go +++ b/internal/service/redshift/integration.go @@ -12,7 +12,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/redshift" awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier" @@ -31,7 +30,9 @@ import ( // @FrameworkResource("aws_redshift_integration", name="Integration") // @Tags(identifierAttribute="arn") -// @Testing(tagsTest=false) +// @ArnIdentity +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.Integration") +// @Testing(preIdentityVersion="6.19.0") func newIntegrationResource(context.Context) (resource.ResourceWithConfigure, error) { r := &integrationResource{} @@ -45,6 +46,7 @@ func newIntegrationResource(context.Context) (resource.ResourceWithConfigure, er type integrationResource struct { framework.ResourceWithModel[integrationResourceModel] framework.WithTimeouts + framework.WithImportByIdentity } func (r *integrationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { @@ -255,10 +257,6 @@ func (r *integrationResource) Delete(ctx context.Context, request resource.Delet } } -func (r *integrationResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrARN), request, response) -} - func integrationError(v awstypes.IntegrationError) error { return fmt.Errorf("%s: %s", aws.ToString(v.ErrorCode), aws.ToString(v.ErrorMessage)) } diff --git a/internal/service/redshift/integration_identity_gen_test.go b/internal/service/redshift/integration_identity_gen_test.go new file mode 100644 index 000000000000..b49b85d624d2 --- /dev/null +++ b/internal/service/redshift/integration_identity_gen_test.go @@ -0,0 +1,340 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftIntegration_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftIntegration_Identity_RegionOverride(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_integration.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command with appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.CrossRegionAttrImportStateIdFunc(resourceName, names.AttrARN), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + + // Step 3: Import command without appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + + // Step 4: Import block with Import ID and appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.CrossRegionAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + + // Step 5: Import block with Import ID and no appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + + // Step 6: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + }, + }) +} + +// Resource Identity was added after v6.19.0 +func TestAccRedshiftIntegration_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic_v6.19.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + }, + }) +} + +// Resource Identity was added after v6.19.0 +func TestAccRedshiftIntegration_Identity_ExistingResource_NoRefresh_NoChange(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{ + NoRefresh: true, + }, + }, + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic_v6.19.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + }, + }) +} diff --git a/internal/service/redshift/integration_tags_gen_test.go b/internal/service/redshift/integration_tags_gen_test.go new file mode 100644 index 000000000000..43b4cc83885d --- /dev/null +++ b/internal/service/redshift/integration_tags_gen_test.go @@ -0,0 +1,2341 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftIntegration_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + "tags.resourcekey1", // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey(acctest.CtKey1)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftIntegration_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.Integration + resourceName := "aws_redshift_integration.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckIntegrationDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Integration/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIntegrationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/integration_test.go b/internal/service/redshift/integration_test.go index 57cdac2381cd..8fc8e98b1131 100644 --- a/internal/service/redshift/integration_test.go +++ b/internal/service/redshift/integration_test.go @@ -12,11 +12,8 @@ import ( awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/plancheck" - "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfredshift "github.com/hashicorp/terraform-provider-aws/internal/service/redshift" @@ -225,86 +222,6 @@ func TestAccRedshiftIntegration_sourceUsesS3Bucket(t *testing.T) { }) } -func TestAccRedshiftIntegration_tags(t *testing.T) { - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - - ctx := acctest.Context(t) - var integration awstypes.Integration - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_redshift_integration.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - acctest.PreCheckPartitionHasService(t, names.RedshiftEndpointID) - testAccPreCheck(ctx, t) - }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckIntegrationDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccIntegrationConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIntegrationExists(ctx, resourceName, &integration), - ), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), - }, - }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ - acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), - })), - }, - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateIdFunc: testAccIntegrationImportStateIDFunc(resourceName), - ImportStateVerifyIdentifierAttribute: names.AttrARN, - }, - { - Config: testAccIntegrationConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIntegrationExists(ctx, resourceName, &integration), - ), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - }, - }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ - acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), - acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), - })), - }, - }, - { - Config: testAccIntegrationConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckIntegrationExists(ctx, resourceName, &integration), - ), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - }, - }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ - acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), - })), - }, - }, - }, - }) -} - func testAccCheckIntegrationDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftClient(ctx) @@ -379,31 +296,59 @@ func testAccPreCheck(ctx context.Context, t *testing.T) { } func testAccIntegrationConfig_base(rName string) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 3), fmt.Sprintf(` -data "aws_caller_identity" "current" {} -data "aws_partition" "current" {} + return acctest.ConfigCompose( + acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = %[1]q +} -resource "aws_security_group" "test" { - name = %[1]q - vpc_id = aws_vpc.test.id +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = %[1]q + base_capacity = 8 - ingress { - protocol = -1 - self = true - from_port = 0 - to_port = 0 - } + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} +`, rName)) +} - tags = { - Name = %[1]q - } +func testAccIntegrationConfig_source_DynamoDBTable(rName string) string { + return acctest.ConfigCompose( + testAccIntegrationConfig_base(rName), fmt.Sprintf(` +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) } resource "aws_dynamodb_table" "test" { @@ -465,92 +410,12 @@ resource "aws_dynamodb_resource_policy" "test" { ] }) } - -resource "aws_s3_bucket" "test" { - bucket = %[1]q -} - -resource "aws_s3_bucket_public_access_block" "test" { - bucket = aws_s3_bucket.test.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} - -resource "aws_s3_bucket_policy" "test" { - bucket = aws_s3_bucket.test.id - - policy = jsonencode({ - Version = "2008-10-17", - Statement = [ - { - Effect = "Allow", - Principal = { - Service = "redshift.amazonaws.com" - }, - Action : [ - "s3:GetBucketNotification", - "s3:PutBucketNotification", - "s3:GetBucketLocation" - ], - Resource = aws_s3_bucket.test.arn - } - ] - }) -} - -resource "aws_redshiftserverless_namespace" "test" { - namespace_name = %[1]q -} - -resource "aws_redshiftserverless_workgroup" "test" { - namespace_name = aws_redshiftserverless_namespace.test.namespace_name - workgroup_name = %[1]q - base_capacity = 8 - - publicly_accessible = false - subnet_ids = aws_subnet.test[*].id - - config_parameter { - parameter_key = "enable_case_sensitive_identifier" - parameter_value = "true" - } - config_parameter { - parameter_key = "auto_mv" - parameter_value = "true" - } - config_parameter { - parameter_key = "datestyle" - parameter_value = "ISO, MDY" - } - config_parameter { - parameter_key = "enable_user_activity_logging" - parameter_value = "true" - } - config_parameter { - parameter_key = "max_query_execution_time" - parameter_value = "14400" - } - config_parameter { - parameter_key = "query_group" - parameter_value = "default" - } - config_parameter { - parameter_key = "require_ssl" - parameter_value = "true" - } - config_parameter { - parameter_key = "search_path" - parameter_value = "$user, public" - } - config_parameter { - parameter_key = "use_fips_ssl" - parameter_value = "false" - } +`, rName)) } +func testAccIntegrationConfig_source_S3Bucket(rName string) string { + return acctest.ConfigCompose( + testAccIntegrationConfig_base(rName), fmt.Sprintf(` # The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. # Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. resource "aws_redshift_resource_policy" "test" { @@ -558,19 +423,6 @@ resource "aws_redshift_resource_policy" "test" { policy = jsonencode({ Version = "2012-10-17" Statement = [ - { - Effect = "Allow" - Principal = { - Service = "redshift.amazonaws.com" - } - Action = "redshift:AuthorizeInboundIntegration" - Resource = aws_redshiftserverless_namespace.test.arn - Condition = { - StringEquals = { - "aws:SourceArn" = aws_dynamodb_table.test.arn - } - } - }, { Effect = "Allow" Principal = { @@ -595,19 +447,53 @@ resource "aws_redshift_resource_policy" "test" { ] }) } + +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_bucket_public_access_block" "test" { + bucket = aws_s3_bucket.test.bucket + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_policy" "test" { + bucket = aws_s3_bucket.test.bucket + + policy = jsonencode({ + Version = "2008-10-17", + Statement = [ + { + Effect = "Allow", + Principal = { + Service = "redshift.amazonaws.com" + }, + Action : [ + "s3:GetBucketNotification", + "s3:PutBucketNotification", + "s3:GetBucketLocation" + ], + Resource = aws_s3_bucket.test.arn + } + ] + }) +} `, rName)) } func testAccIntegrationConfig_basic(rName string) string { - return acctest.ConfigCompose(testAccIntegrationConfig_base(rName), fmt.Sprintf(` + return acctest.ConfigCompose( + testAccIntegrationConfig_source_DynamoDBTable(rName), fmt.Sprintf(` resource "aws_redshift_integration" "test" { integration_name = %[1]q source_arn = aws_dynamodb_table.test.arn target_arn = aws_redshiftserverless_namespace.test.arn depends_on = [ - aws_dynamodb_table.test, - aws_redshiftserverless_namespace.test, aws_redshiftserverless_workgroup.test, aws_redshift_resource_policy.test, aws_dynamodb_resource_policy.test, @@ -617,7 +503,8 @@ resource "aws_redshift_integration" "test" { } func testAccIntegrationConfig_optional(rName string) string { - return acctest.ConfigCompose(testAccIntegrationConfig_base(rName), fmt.Sprintf(` + return acctest.ConfigCompose( + testAccIntegrationConfig_source_DynamoDBTable(rName), fmt.Sprintf(` resource "aws_kms_key" "test" { description = %[1]q deletion_window_in_days = 10 @@ -673,8 +560,6 @@ resource "aws_redshift_integration" "test" { } depends_on = [ - aws_dynamodb_table.test, - aws_redshiftserverless_namespace.test, aws_redshiftserverless_workgroup.test, aws_redshift_resource_policy.test, aws_dynamodb_resource_policy.test, @@ -684,7 +569,8 @@ resource "aws_redshift_integration" "test" { } func testAccIntegrationConfig_sourceUsesS3Bucket(rName, description, integrationName string) string { - return acctest.ConfigCompose(testAccIntegrationConfig_base(rName), fmt.Sprintf(` + return acctest.ConfigCompose( + testAccIntegrationConfig_source_S3Bucket(rName), fmt.Sprintf(` resource "aws_redshift_integration" "test" { description = %[1]q integration_name = %[2]q @@ -692,8 +578,6 @@ resource "aws_redshift_integration" "test" { target_arn = aws_redshiftserverless_namespace.test.arn depends_on = [ - aws_s3_bucket.test, - aws_redshiftserverless_namespace.test, aws_redshiftserverless_workgroup.test, aws_redshift_resource_policy.test, aws_s3_bucket_policy.test, @@ -701,48 +585,3 @@ resource "aws_redshift_integration" "test" { } `, description, integrationName)) } - -func testAccIntegrationConfig_tags1(rName, tag1Key, tag1Value string) string { - return acctest.ConfigCompose(testAccIntegrationConfig_base(rName), fmt.Sprintf(` -resource "aws_redshift_integration" "test" { - integration_name = %[1]q - source_arn = aws_dynamodb_table.test.arn - target_arn = aws_redshiftserverless_namespace.test.arn - - tags = { - %[2]q = %[3]q - } - - depends_on = [ - aws_dynamodb_table.test, - aws_redshiftserverless_namespace.test, - aws_redshiftserverless_workgroup.test, - aws_redshift_resource_policy.test, - aws_dynamodb_resource_policy.test, - ] -} -`, rName, tag1Key, tag1Value)) -} - -func testAccIntegrationConfig_tags2(rName, tag1Key, tag1Value, tag2Key, tag2Value string) string { - return acctest.ConfigCompose(testAccIntegrationConfig_base(rName), fmt.Sprintf(` -resource "aws_redshift_integration" "test" { - integration_name = %[1]q - source_arn = aws_dynamodb_table.test.arn - target_arn = aws_redshiftserverless_namespace.test.arn - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } - - depends_on = [ - aws_dynamodb_table.test, - aws_redshiftserverless_namespace.test, - aws_redshiftserverless_workgroup.test, - aws_redshift_resource_policy.test, - aws_dynamodb_resource_policy.test, - ] -} -`, rName, tag1Key, tag1Value, tag2Key, tag2Value)) -} diff --git a/internal/service/redshift/parameter_group.go b/internal/service/redshift/parameter_group.go index b712d3ec4b43..cc95374c1a16 100644 --- a/internal/service/redshift/parameter_group.go +++ b/internal/service/redshift/parameter_group.go @@ -30,6 +30,7 @@ import ( // @SDKResource("aws_redshift_parameter_group", name="Parameter Group") // @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.ClusterParameterGroup") func resourceParameterGroup() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceParameterGroupCreate, diff --git a/internal/service/redshift/parameter_group_tags_gen_test.go b/internal/service/redshift/parameter_group_tags_gen_test.go new file mode 100644 index 000000000000..fdcd5345c05a --- /dev/null +++ b/internal/service/redshift/parameter_group_tags_gen_test.go @@ -0,0 +1,2293 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftParameterGroup_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftParameterGroup_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterParameterGroup + resourceName := "aws_redshift_parameter_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckParameterGroupDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/ParameterGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckParameterGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/parameter_group_test.go b/internal/service/redshift/parameter_group_test.go index 7dd4f02a4968..69b79dbc65eb 100644 --- a/internal/service/redshift/parameter_group_test.go +++ b/internal/service/redshift/parameter_group_test.go @@ -145,53 +145,6 @@ func TestAccRedshiftParameterGroup_update(t *testing.T) { }) } -func TestAccRedshiftParameterGroup_tags(t *testing.T) { - ctx := acctest.Context(t) - var v awstypes.ClusterParameterGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_redshift_parameter_group.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckParameterGroupDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccParameterGroupConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckParameterGroupExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "Test parameter group for terraform"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccParameterGroupConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckParameterGroupExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccParameterGroupConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckParameterGroupExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func testAccCheckParameterGroupDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftClient(ctx) @@ -275,32 +228,3 @@ resource "aws_redshift_parameter_group" "test" { } `, rName) } - -func testAccParameterGroupConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_redshift_parameter_group" "test" { - name = %[1]q - family = "redshift-1.0" - description = "Test parameter group for terraform" - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccParameterGroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_redshift_parameter_group" "test" { - name = %[1]q - family = "redshift-1.0" - description = "Test parameter group for terraform" - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} diff --git a/internal/service/redshift/service_package_gen.go b/internal/service/redshift/service_package_gen.go index f5bfe9ca75e6..3051901dcc55 100644 --- a/internal/service/redshift/service_package_gen.go +++ b/internal/service/redshift/service_package_gen.go @@ -55,7 +55,11 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.Ser Tags: unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrARN, }), - Region: unique.Make(inttypes.ResourceRegionDefault()), + Region: unique.Make(inttypes.ResourceRegionDefault()), + Identity: inttypes.RegionalARNIdentity(), + Import: inttypes.FrameworkImport{ + WrappedImport: true, + }, }, { Factory: newLoggingResource, diff --git a/internal/service/redshift/snapshot_copy_grant_tags_gen_test.go b/internal/service/redshift/snapshot_copy_grant_tags_gen_test.go new file mode 100644 index 000000000000..9755c32fb186 --- /dev/null +++ b/internal/service/redshift/snapshot_copy_grant_tags_gen_test.go @@ -0,0 +1,2271 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftSnapshotCopyGrant_tags(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotCopyGrant_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_snapshot_copy_grant.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotCopyGrant/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotCopyGrantExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/snapshot_copy_grant_test.go b/internal/service/redshift/snapshot_copy_grant_test.go index de79582a2eb7..4c45e7e47700 100644 --- a/internal/service/redshift/snapshot_copy_grant_test.go +++ b/internal/service/redshift/snapshot_copy_grant_test.go @@ -70,51 +70,6 @@ func TestAccRedshiftSnapshotCopyGrant_disappears(t *testing.T) { }) } -func TestAccRedshiftSnapshotCopyGrant_tags(t *testing.T) { - ctx := acctest.Context(t) - resourceName := "aws_redshift_snapshot_copy_grant.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckSnapshotCopyGrantDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccSnapshotCopyGrantConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckSnapshotCopyGrantExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccSnapshotCopyGrantConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckSnapshotCopyGrantExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccSnapshotCopyGrantConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckSnapshotCopyGrantExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func testAccCheckSnapshotCopyGrantDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftClient(ctx) @@ -163,28 +118,3 @@ resource "aws_redshift_snapshot_copy_grant" "test" { } `, rName) } - -func testAccSnapshotCopyGrantConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_redshift_snapshot_copy_grant" "test" { - snapshot_copy_grant_name = %[1]q - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccSnapshotCopyGrantConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_redshift_snapshot_copy_grant" "test" { - snapshot_copy_grant_name = %[1]q - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} diff --git a/internal/service/redshift/snapshot_schedule.go b/internal/service/redshift/snapshot_schedule.go index 602c057c7fd5..5a6f329c9b9c 100644 --- a/internal/service/redshift/snapshot_schedule.go +++ b/internal/service/redshift/snapshot_schedule.go @@ -26,6 +26,8 @@ import ( // @SDKResource("aws_redshift_snapshot_schedule", name="Snapshot Schedule") // @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.SnapshotSchedule") +// @Testing(importIgnore="force_destroy") func resourceSnapshotSchedule() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceSnapshotScheduleCreate, diff --git a/internal/service/redshift/snapshot_schedule_tags_gen_test.go b/internal/service/redshift/snapshot_schedule_tags_gen_test.go new file mode 100644 index 000000000000..3a9119eda82b --- /dev/null +++ b/internal/service/redshift/snapshot_schedule_tags_gen_test.go @@ -0,0 +1,2386 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftSnapshotSchedule_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + names.AttrForceDestroy, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSnapshotSchedule_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.SnapshotSchedule + resourceName := "aws_redshift_snapshot_schedule.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SnapshotSchedule/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/snapshot_schedule_test.go b/internal/service/redshift/snapshot_schedule_test.go index d4606fb73a14..1edcd1104546 100644 --- a/internal/service/redshift/snapshot_schedule_test.go +++ b/internal/service/redshift/snapshot_schedule_test.go @@ -83,55 +83,6 @@ func TestAccRedshiftSnapshotSchedule_disappears(t *testing.T) { }) } -func TestAccRedshiftSnapshotSchedule_tags(t *testing.T) { - ctx := acctest.Context(t) - var v awstypes.SnapshotSchedule - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_redshift_snapshot_schedule.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckSnapshotScheduleDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccSnapshotScheduleConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - names.AttrForceDestroy, - }, - }, - { - Config: testAccSnapshotScheduleConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccSnapshotScheduleConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckSnapshotScheduleExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftSnapshotSchedule_identifierGenerated(t *testing.T) { ctx := acctest.Context(t) var v awstypes.SnapshotSchedule @@ -393,37 +344,6 @@ resource "aws_redshift_snapshot_schedule" "test" { `, rName) } -func testAccSnapshotScheduleConfig_tags1(rName, tagKey1, tagValue1 string) string { - return fmt.Sprintf(` -resource "aws_redshift_snapshot_schedule" "test" { - identifier = %[1]q - definitions = [ - "rate(12 hours)", - ] - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1) -} - -func testAccSnapshotScheduleConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return fmt.Sprintf(` -resource "aws_redshift_snapshot_schedule" "test" { - identifier = %[1]q - definitions = [ - "rate(12 hours)", - ] - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) -} - func testAccSnapshotScheduleConfig_identifierGenerated() string { return ` resource "aws_redshift_snapshot_schedule" "test" { diff --git a/internal/service/redshift/subnet_group.go b/internal/service/redshift/subnet_group.go index 7117c8e06127..dc2a5c2ab598 100644 --- a/internal/service/redshift/subnet_group.go +++ b/internal/service/redshift/subnet_group.go @@ -26,6 +26,7 @@ import ( // @SDKResource("aws_redshift_subnet_group", name="Subnet Group") // @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/redshift/types;awstypes;awstypes.ClusterSubnetGroup") func resourceSubnetGroup() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceSubnetGroupCreate, diff --git a/internal/service/redshift/subnet_group_data_source.go b/internal/service/redshift/subnet_group_data_source.go index 3350a69e7a8c..43248812570c 100644 --- a/internal/service/redshift/subnet_group_data_source.go +++ b/internal/service/redshift/subnet_group_data_source.go @@ -19,6 +19,7 @@ import ( // @SDKDataSource("aws_redshift_subnet_group", name="Subnet Group") // @Tags +// @Testing(tagsIdentifierAttribute="arn") func dataSourceSubnetGroup() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceSubnetGroupRead, diff --git a/internal/service/redshift/subnet_group_data_source_tags_gen_test.go b/internal/service/redshift/subnet_group_data_source_tags_gen_test.go new file mode 100644 index 000000000000..7cd56da9d749 --- /dev/null +++ b/internal/service/redshift/subnet_group_data_source_tags_gen_test.go @@ -0,0 +1,211 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "context" + "testing" + "unique" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + tfredshift "github.com/hashicorp/terraform-provider-aws/internal/service/redshift" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftSubnetGroupDataSource_tags(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroupDataSource_tags_NullMap(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroupDataSource_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/data.tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroupDataSource_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/data.tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroupDataSource_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/data.tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullSubnetGroupDataSourceTags(ctx, dataSourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroupDataSource_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + dataSourceName := "data.aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/data.tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(dataSourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + expectFullSubnetGroupDataSourceTags(ctx, dataSourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func expectFullSubnetGroupDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfredshift.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }), knownValue) +} diff --git a/internal/service/redshift/subnet_group_tags_gen_test.go b/internal/service/redshift/subnet_group_tags_gen_test.go new file mode 100644 index 000000000000..809fa25e758e --- /dev/null +++ b/internal/service/redshift/subnet_group_tags_gen_test.go @@ -0,0 +1,2293 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftSubnetGroup_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftSubnetGroup_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v awstypes.ClusterSubnetGroup + resourceName := "aws_redshift_subnet_group.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/SubnetGroup/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckSubnetGroupExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/subnet_group_test.go b/internal/service/redshift/subnet_group_test.go index 027ced439593..4220058491ad 100644 --- a/internal/service/redshift/subnet_group_test.go +++ b/internal/service/redshift/subnet_group_test.go @@ -142,52 +142,6 @@ func TestAccRedshiftSubnetGroup_updateSubnetIDs(t *testing.T) { }) } -func TestAccRedshiftSubnetGroup_tags(t *testing.T) { - ctx := acctest.Context(t) - var v awstypes.ClusterSubnetGroup - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_redshift_subnet_group.test" - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckSubnetGroupDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccSubnetGroupConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckSubnetGroupExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccSubnetGroupConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckSubnetGroupExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccSubnetGroupConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckSubnetGroupExists(ctx, resourceName, &v), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func testAccCheckSubnetGroupDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftClient(ctx) @@ -258,33 +212,6 @@ resource "aws_redshift_subnet_group" "test" { `, rName)) } -func testAccSubnetGroupConfig_tags1(rName, tagKey1, tagValue1 string) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` -resource "aws_redshift_subnet_group" "test" { - name = %[1]q - subnet_ids = aws_subnet.test[*].id - - tags = { - %[2]q = %[3]q - } -} -`, rName, tagKey1, tagValue1)) -} - -func testAccSubnetGroupConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` -resource "aws_redshift_subnet_group" "test" { - name = %[1]q - subnet_ids = aws_subnet.test[*].id - - tags = { - %[2]q = %[3]q - %[4]q = %[5]q - } -} -`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) -} - func testAccSubnetGroupConfig_updateIDs(rName string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 3), fmt.Sprintf(` resource "aws_redshift_subnet_group" "test" { diff --git a/internal/service/redshift/tags.go b/internal/service/redshift/tags.go new file mode 100644 index 000000000000..48037bbed471 --- /dev/null +++ b/internal/service/redshift/tags.go @@ -0,0 +1,45 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package redshift + +import ( + "context" + + "github.com/YakDriver/smarterr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/redshift" + awstypes "github.com/aws/aws-sdk-go-v2/service/redshift/types" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/types/option" +) + +// ListTags lists redshift service tags and sets them in Context. +// It is called from outside this package. +func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { + conn := meta.(*conns.AWSClient).RedshiftClient(ctx) + + input := redshift.DescribeTagsInput{ + ResourceName: aws.String(identifier), + } + output, err := conn.DescribeTags(ctx, &input) + if err != nil { + return smarterr.NewError(err) + } + + awsTags := make([]awstypes.Tag, 0, len(output.TaggedResources)) + for _, tag := range output.TaggedResources { + if tag.Tag != nil { + awsTags = append(awsTags, *tag.Tag) + } + } + + tags := keyValueTags(ctx, awsTags) + + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(tags) + } + + return nil +} diff --git a/internal/service/redshift/tags_gen_test.go b/internal/service/redshift/tags_gen_test.go new file mode 100644 index 000000000000..92c20bbec787 --- /dev/null +++ b/internal/service/redshift/tags_gen_test.go @@ -0,0 +1,20 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + tfredshift "github.com/hashicorp/terraform-provider-aws/internal/service/redshift" +) + +func expectFullResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullResourceTags(tfredshift.ServicePackage(ctx), resourceAddress, knownValue) +} + +func expectFullDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullDataSourceTags(tfredshift.ServicePackage(ctx), resourceAddress, knownValue) +} diff --git a/internal/service/redshift/testdata/Cluster/data.tags/main_gen.tf b/internal/service/redshift/testdata/Cluster/data.tags/main_gen.tf new file mode 100644 index 000000000000..4976e4ca5ab9 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/data.tags/main_gen.tf @@ -0,0 +1,32 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# tflint-ignore: terraform_unused_declarations +data "aws_redshift_cluster" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/Cluster/data.tags_defaults/main_gen.tf b/internal/service/redshift/testdata/Cluster/data.tags_defaults/main_gen.tf new file mode 100644 index 000000000000..1f277d5e9eeb --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/data.tags_defaults/main_gen.tf @@ -0,0 +1,43 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +# tflint-ignore: terraform_unused_declarations +data "aws_redshift_cluster" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/Cluster/data.tags_ignore/main_gen.tf b/internal/service/redshift/testdata/Cluster/data.tags_ignore/main_gen.tf new file mode 100644 index 000000000000..c5826072b703 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/data.tags_ignore/main_gen.tf @@ -0,0 +1,52 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +# tflint-ignore: terraform_unused_declarations +data "aws_redshift_cluster" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/Cluster/tags/main_gen.tf b/internal/service/redshift/testdata/Cluster/tags/main_gen.tf new file mode 100644 index 000000000000..544f803c9953 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/tags/main_gen.tf @@ -0,0 +1,27 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/Cluster/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/Cluster/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..e1b5bd501d44 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/tagsComputed1/main_gen.tf @@ -0,0 +1,31 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/Cluster/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/Cluster/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..ea76d74a3c72 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/tagsComputed2/main_gen.tf @@ -0,0 +1,42 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/Cluster/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/Cluster/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..4a61734ce655 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/tags_defaults/main_gen.tf @@ -0,0 +1,38 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/Cluster/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/Cluster/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..7ccc7532ebd7 --- /dev/null +++ b/internal/service/redshift/testdata/Cluster/tags_ignore/main_gen.tf @@ -0,0 +1,47 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/ClusterSnapshot/tags/main_gen.tf b/internal/service/redshift/testdata/ClusterSnapshot/tags/main_gen.tf new file mode 100644 index 000000000000..0b3258de4927 --- /dev/null +++ b/internal/service/redshift/testdata/ClusterSnapshot/tags/main_gen.tf @@ -0,0 +1,34 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_cluster_snapshot" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + snapshot_identifier = var.rName + + tags = var.resource_tags +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/ClusterSnapshot/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/ClusterSnapshot/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..824b50112da5 --- /dev/null +++ b/internal/service/redshift/testdata/ClusterSnapshot/tagsComputed1/main_gen.tf @@ -0,0 +1,38 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_cluster_snapshot" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + snapshot_identifier = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/ClusterSnapshot/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/ClusterSnapshot/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..98a43082ba57 --- /dev/null +++ b/internal/service/redshift/testdata/ClusterSnapshot/tagsComputed2/main_gen.tf @@ -0,0 +1,49 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_cluster_snapshot" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + snapshot_identifier = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/ClusterSnapshot/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/ClusterSnapshot/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..c2acdd190d9c --- /dev/null +++ b/internal/service/redshift/testdata/ClusterSnapshot/tags_defaults/main_gen.tf @@ -0,0 +1,45 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_cluster_snapshot" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + snapshot_identifier = var.rName + + tags = var.resource_tags +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/ClusterSnapshot/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/ClusterSnapshot/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..ff2687dd6e4d --- /dev/null +++ b/internal/service/redshift/testdata/ClusterSnapshot/tags_ignore/main_gen.tf @@ -0,0 +1,54 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_cluster_snapshot" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + snapshot_identifier = var.rName + + tags = var.resource_tags +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/EventSubscription/tags/main_gen.tf b/internal/service/redshift/testdata/EventSubscription/tags/main_gen.tf new file mode 100644 index 000000000000..3b638164c693 --- /dev/null +++ b/internal/service/redshift/testdata/EventSubscription/tags/main_gen.tf @@ -0,0 +1,26 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_event_subscription" "test" { + name = var.rName + sns_topic_arn = aws_sns_topic.test.arn + + tags = var.resource_tags +} + +resource "aws_sns_topic" "test" { + name = var.rName +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/EventSubscription/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/EventSubscription/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..29420d4bff8f --- /dev/null +++ b/internal/service/redshift/testdata/EventSubscription/tagsComputed1/main_gen.tf @@ -0,0 +1,30 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_event_subscription" "test" { + name = var.rName + sns_topic_arn = aws_sns_topic.test.arn + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "aws_sns_topic" "test" { + name = var.rName +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/EventSubscription/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/EventSubscription/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..576243cda841 --- /dev/null +++ b/internal/service/redshift/testdata/EventSubscription/tagsComputed2/main_gen.tf @@ -0,0 +1,41 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_event_subscription" "test" { + name = var.rName + sns_topic_arn = aws_sns_topic.test.arn + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "aws_sns_topic" "test" { + name = var.rName +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/EventSubscription/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/EventSubscription/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..14e091f62e80 --- /dev/null +++ b/internal/service/redshift/testdata/EventSubscription/tags_defaults/main_gen.tf @@ -0,0 +1,37 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_event_subscription" "test" { + name = var.rName + sns_topic_arn = aws_sns_topic.test.arn + + tags = var.resource_tags +} + +resource "aws_sns_topic" "test" { + name = var.rName +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/EventSubscription/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/EventSubscription/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..ad091a35d507 --- /dev/null +++ b/internal/service/redshift/testdata/EventSubscription/tags_ignore/main_gen.tf @@ -0,0 +1,46 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_event_subscription" "test" { + name = var.rName + sns_topic_arn = aws_sns_topic.test.arn + + tags = var.resource_tags +} + +resource "aws_sns_topic" "test" { + name = var.rName +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMClientCertificate/tags/main_gen.tf b/internal/service/redshift/testdata/HSMClientCertificate/tags/main_gen.tf new file mode 100644 index 000000000000..8eed2f623d01 --- /dev/null +++ b/internal/service/redshift/testdata/HSMClientCertificate/tags/main_gen.tf @@ -0,0 +1,21 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_hsm_client_certificate" "test" { + hsm_client_certificate_identifier = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/HSMClientCertificate/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/HSMClientCertificate/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..56ffa1adb994 --- /dev/null +++ b/internal/service/redshift/testdata/HSMClientCertificate/tagsComputed1/main_gen.tf @@ -0,0 +1,25 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_hsm_client_certificate" "test" { + hsm_client_certificate_identifier = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMClientCertificate/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/HSMClientCertificate/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..4723b4d6ba6c --- /dev/null +++ b/internal/service/redshift/testdata/HSMClientCertificate/tagsComputed2/main_gen.tf @@ -0,0 +1,36 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_hsm_client_certificate" "test" { + hsm_client_certificate_identifier = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMClientCertificate/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/HSMClientCertificate/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..090e45c4fd3b --- /dev/null +++ b/internal/service/redshift/testdata/HSMClientCertificate/tags_defaults/main_gen.tf @@ -0,0 +1,32 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_hsm_client_certificate" "test" { + hsm_client_certificate_identifier = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMClientCertificate/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/HSMClientCertificate/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..4c17c2a2d9ac --- /dev/null +++ b/internal/service/redshift/testdata/HSMClientCertificate/tags_ignore/main_gen.tf @@ -0,0 +1,41 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_hsm_client_certificate" "test" { + hsm_client_certificate_identifier = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMConfiguration/tags/main_gen.tf b/internal/service/redshift/testdata/HSMConfiguration/tags/main_gen.tf new file mode 100644 index 000000000000..d2cbc8058c48 --- /dev/null +++ b/internal/service/redshift/testdata/HSMConfiguration/tags/main_gen.tf @@ -0,0 +1,26 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_hsm_configuration" "test" { + description = var.rName + hsm_configuration_identifier = var.rName + hsm_ip_address = "10.0.0.1" + hsm_partition_name = "aws" + hsm_partition_password = var.rName + hsm_server_public_certificate = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/HSMConfiguration/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/HSMConfiguration/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..efb833e2ef21 --- /dev/null +++ b/internal/service/redshift/testdata/HSMConfiguration/tagsComputed1/main_gen.tf @@ -0,0 +1,30 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_hsm_configuration" "test" { + description = var.rName + hsm_configuration_identifier = var.rName + hsm_ip_address = "10.0.0.1" + hsm_partition_name = "aws" + hsm_partition_password = var.rName + hsm_server_public_certificate = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMConfiguration/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/HSMConfiguration/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..dd2d446e2d78 --- /dev/null +++ b/internal/service/redshift/testdata/HSMConfiguration/tagsComputed2/main_gen.tf @@ -0,0 +1,41 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_hsm_configuration" "test" { + description = var.rName + hsm_configuration_identifier = var.rName + hsm_ip_address = "10.0.0.1" + hsm_partition_name = "aws" + hsm_partition_password = var.rName + hsm_server_public_certificate = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMConfiguration/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/HSMConfiguration/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..032152dff0d6 --- /dev/null +++ b/internal/service/redshift/testdata/HSMConfiguration/tags_defaults/main_gen.tf @@ -0,0 +1,37 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_hsm_configuration" "test" { + description = var.rName + hsm_configuration_identifier = var.rName + hsm_ip_address = "10.0.0.1" + hsm_partition_name = "aws" + hsm_partition_password = var.rName + hsm_server_public_certificate = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/HSMConfiguration/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/HSMConfiguration/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..c09df0ae3bd4 --- /dev/null +++ b/internal/service/redshift/testdata/HSMConfiguration/tags_ignore/main_gen.tf @@ -0,0 +1,46 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_hsm_configuration" "test" { + description = var.rName + hsm_configuration_identifier = var.rName + hsm_ip_address = "10.0.0.1" + hsm_partition_name = "aws" + hsm_partition_password = var.rName + hsm_server_public_certificate = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/Integration/basic/main_gen.tf b/internal/service/redshift/testdata/Integration/basic/main_gen.tf new file mode 100644 index 000000000000..3f77c0123a7d --- /dev/null +++ b/internal/service/redshift/testdata/Integration/basic/main_gen.tf @@ -0,0 +1,162 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/Integration/basic_v6.19.0/main_gen.tf b/internal/service/redshift/testdata/Integration/basic_v6.19.0/main_gen.tf new file mode 100644 index 000000000000..3bf836640278 --- /dev/null +++ b/internal/service/redshift/testdata/Integration/basic_v6.19.0/main_gen.tf @@ -0,0 +1,172 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.19.0" + } + } +} + +provider "aws" {} diff --git a/internal/service/redshift/testdata/Integration/region_override/main_gen.tf b/internal/service/redshift/testdata/Integration/region_override/main_gen.tf new file mode 100644 index 000000000000..449e060ef24a --- /dev/null +++ b/internal/service/redshift/testdata/Integration/region_override/main_gen.tf @@ -0,0 +1,186 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_integration" "test" { + region = var.region + + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + region = var.region + + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + region = var.region + + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + region = var.region + + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + region = var.region + + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + region = var.region + + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + region = var.region + + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + region = var.region + + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + region = var.region + + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "region" { + description = "Region to deploy resource in" + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/Integration/tags/main_gen.tf b/internal/service/redshift/testdata/Integration/tags/main_gen.tf new file mode 100644 index 000000000000..9b5fe84453d5 --- /dev/null +++ b/internal/service/redshift/testdata/Integration/tags/main_gen.tf @@ -0,0 +1,171 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] + + tags = var.resource_tags +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/Integration/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/Integration/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..6d75013366bc --- /dev/null +++ b/internal/service/redshift/testdata/Integration/tagsComputed1/main_gen.tf @@ -0,0 +1,175 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/Integration/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/Integration/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..22f9e7ed9bd6 --- /dev/null +++ b/internal/service/redshift/testdata/Integration/tagsComputed2/main_gen.tf @@ -0,0 +1,186 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/Integration/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/Integration/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..f85724ce44f7 --- /dev/null +++ b/internal/service/redshift/testdata/Integration/tags_defaults/main_gen.tf @@ -0,0 +1,182 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] + + tags = var.resource_tags +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/Integration/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/Integration/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..7be037e256e3 --- /dev/null +++ b/internal/service/redshift/testdata/Integration/tags_ignore/main_gen.tf @@ -0,0 +1,191 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_integration" "test" { + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] + + tags = var.resource_tags +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/ParameterGroup/tags/main_gen.tf b/internal/service/redshift/testdata/ParameterGroup/tags/main_gen.tf new file mode 100644 index 000000000000..f7223022d07f --- /dev/null +++ b/internal/service/redshift/testdata/ParameterGroup/tags/main_gen.tf @@ -0,0 +1,22 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_parameter_group" "test" { + name = var.rName + family = "redshift-1.0" + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/ParameterGroup/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/ParameterGroup/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..ee483352ba57 --- /dev/null +++ b/internal/service/redshift/testdata/ParameterGroup/tagsComputed1/main_gen.tf @@ -0,0 +1,26 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_parameter_group" "test" { + name = var.rName + family = "redshift-1.0" + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/ParameterGroup/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/ParameterGroup/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..41bcc6fde63b --- /dev/null +++ b/internal/service/redshift/testdata/ParameterGroup/tagsComputed2/main_gen.tf @@ -0,0 +1,37 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_parameter_group" "test" { + name = var.rName + family = "redshift-1.0" + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/ParameterGroup/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/ParameterGroup/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..d310da73b04c --- /dev/null +++ b/internal/service/redshift/testdata/ParameterGroup/tags_defaults/main_gen.tf @@ -0,0 +1,33 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_parameter_group" "test" { + name = var.rName + family = "redshift-1.0" + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/ParameterGroup/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/ParameterGroup/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..5b16a3fba935 --- /dev/null +++ b/internal/service/redshift/testdata/ParameterGroup/tags_ignore/main_gen.tf @@ -0,0 +1,42 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_parameter_group" "test" { + name = var.rName + family = "redshift-1.0" + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotCopyGrant/tags/main_gen.tf b/internal/service/redshift/testdata/SnapshotCopyGrant/tags/main_gen.tf new file mode 100644 index 000000000000..d030eb726c34 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotCopyGrant/tags/main_gen.tf @@ -0,0 +1,21 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_snapshot_copy_grant" "test" { + snapshot_copy_grant_name = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/SnapshotCopyGrant/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/SnapshotCopyGrant/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..3f87a528a0ee --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotCopyGrant/tagsComputed1/main_gen.tf @@ -0,0 +1,25 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_snapshot_copy_grant" "test" { + snapshot_copy_grant_name = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotCopyGrant/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/SnapshotCopyGrant/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..0058342199c2 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotCopyGrant/tagsComputed2/main_gen.tf @@ -0,0 +1,36 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_snapshot_copy_grant" "test" { + snapshot_copy_grant_name = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotCopyGrant/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/SnapshotCopyGrant/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..c5af59302f63 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotCopyGrant/tags_defaults/main_gen.tf @@ -0,0 +1,32 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_snapshot_copy_grant" "test" { + snapshot_copy_grant_name = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotCopyGrant/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/SnapshotCopyGrant/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..8b48ce9ab076 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotCopyGrant/tags_ignore/main_gen.tf @@ -0,0 +1,41 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_snapshot_copy_grant" "test" { + snapshot_copy_grant_name = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotSchedule/tags/main_gen.tf b/internal/service/redshift/testdata/SnapshotSchedule/tags/main_gen.tf new file mode 100644 index 000000000000..016149393a66 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotSchedule/tags/main_gen.tf @@ -0,0 +1,24 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_snapshot_schedule" "test" { + identifier = var.rName + definitions = [ + "rate(12 hours)", + ] + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/SnapshotSchedule/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/SnapshotSchedule/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..89d332a1ebcf --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotSchedule/tagsComputed1/main_gen.tf @@ -0,0 +1,28 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_snapshot_schedule" "test" { + identifier = var.rName + definitions = [ + "rate(12 hours)", + ] + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotSchedule/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/SnapshotSchedule/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..54e9255957b8 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotSchedule/tagsComputed2/main_gen.tf @@ -0,0 +1,39 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_snapshot_schedule" "test" { + identifier = var.rName + definitions = [ + "rate(12 hours)", + ] + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotSchedule/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/SnapshotSchedule/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..e3fdd502de1c --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotSchedule/tags_defaults/main_gen.tf @@ -0,0 +1,35 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_snapshot_schedule" "test" { + identifier = var.rName + definitions = [ + "rate(12 hours)", + ] + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SnapshotSchedule/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/SnapshotSchedule/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..697975236c22 --- /dev/null +++ b/internal/service/redshift/testdata/SnapshotSchedule/tags_ignore/main_gen.tf @@ -0,0 +1,44 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_snapshot_schedule" "test" { + identifier = var.rName + definitions = [ + "rate(12 hours)", + ] + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SubnetGroup/data.tags/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/data.tags/main_gen.tf new file mode 100644 index 000000000000..ac07e6d41a6a --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/data.tags/main_gen.tf @@ -0,0 +1,57 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# tflint-ignore: terraform_unused_declarations +data "aws_redshift_subnet_group" "test" { + name = aws_redshift_subnet_group.test.name +} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = var.resource_tags +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/SubnetGroup/data.tags_defaults/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/data.tags_defaults/main_gen.tf new file mode 100644 index 000000000000..2a0daa6f0bff --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/data.tags_defaults/main_gen.tf @@ -0,0 +1,68 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +# tflint-ignore: terraform_unused_declarations +data "aws_redshift_subnet_group" "test" { + name = aws_redshift_subnet_group.test.name +} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = var.resource_tags +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SubnetGroup/data.tags_ignore/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/data.tags_ignore/main_gen.tf new file mode 100644 index 000000000000..54e332412f06 --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/data.tags_ignore/main_gen.tf @@ -0,0 +1,77 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +# tflint-ignore: terraform_unused_declarations +data "aws_redshift_subnet_group" "test" { + name = aws_redshift_subnet_group.test.name +} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = var.resource_tags +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SubnetGroup/tags/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/tags/main_gen.tf new file mode 100644 index 000000000000..54f2a907aebf --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/tags/main_gen.tf @@ -0,0 +1,52 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = var.resource_tags +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/SubnetGroup/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..037b71bb82a7 --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/tagsComputed1/main_gen.tf @@ -0,0 +1,56 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/SubnetGroup/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..12d543900d26 --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/tagsComputed2/main_gen.tf @@ -0,0 +1,67 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/SubnetGroup/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..b1f007b0db2b --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/tags_defaults/main_gen.tf @@ -0,0 +1,63 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = var.resource_tags +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/SubnetGroup/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/SubnetGroup/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..9f021c657e54 --- /dev/null +++ b/internal/service/redshift/testdata/SubnetGroup/tags_ignore/main_gen.tf @@ -0,0 +1,72 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_subnet_group" "test" { + name = var.rName + subnet_ids = aws_subnet.test[*].id + + tags = var.resource_tags +} + +# acctest.ConfigVPCWithSubnets(rName, 2) + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test" { + count = 2 + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) +} + +# acctest.ConfigAvailableAZsNoOptInDefaultExclude + +data "aws_availability_zones" "available" { + exclude_zone_ids = local.default_exclude_zone_ids + state = "available" + + filter { + name = "opt-in-status" + values = ["opt-in-not-required"] + } +} + +locals { + default_exclude_zone_ids = ["usw2-az4", "usgw1-az2"] +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/UsageLimit/tags/main_gen.tf b/internal/service/redshift/testdata/UsageLimit/tags/main_gen.tf new file mode 100644 index 000000000000..36b83ef27dd0 --- /dev/null +++ b/internal/service/redshift/testdata/UsageLimit/tags/main_gen.tf @@ -0,0 +1,36 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_redshift_usage_limit" "test" { + cluster_identifier = aws_redshift_cluster.test.id + feature_type = "concurrency-scaling" + limit_type = "time" + amount = 60 + + tags = var.resource_tags +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/redshift/testdata/UsageLimit/tagsComputed1/main_gen.tf b/internal/service/redshift/testdata/UsageLimit/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..7f16fbcab3d8 --- /dev/null +++ b/internal/service/redshift/testdata/UsageLimit/tagsComputed1/main_gen.tf @@ -0,0 +1,40 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_usage_limit" "test" { + cluster_identifier = aws_redshift_cluster.test.id + feature_type = "concurrency-scaling" + limit_type = "time" + amount = 60 + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/UsageLimit/tagsComputed2/main_gen.tf b/internal/service/redshift/testdata/UsageLimit/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..e0174be674f0 --- /dev/null +++ b/internal/service/redshift/testdata/UsageLimit/tagsComputed2/main_gen.tf @@ -0,0 +1,51 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_redshift_usage_limit" "test" { + cluster_identifier = aws_redshift_cluster.test.id + feature_type = "concurrency-scaling" + limit_type = "time" + amount = 60 + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/redshift/testdata/UsageLimit/tags_defaults/main_gen.tf b/internal/service/redshift/testdata/UsageLimit/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..e99d193c8616 --- /dev/null +++ b/internal/service/redshift/testdata/UsageLimit/tags_defaults/main_gen.tf @@ -0,0 +1,47 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_redshift_usage_limit" "test" { + cluster_identifier = aws_redshift_cluster.test.id + feature_type = "concurrency-scaling" + limit_type = "time" + amount = 60 + + tags = var.resource_tags +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/UsageLimit/tags_ignore/main_gen.tf b/internal/service/redshift/testdata/UsageLimit/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..b2e6a0a85ac1 --- /dev/null +++ b/internal/service/redshift/testdata/UsageLimit/tags_ignore/main_gen.tf @@ -0,0 +1,56 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_redshift_usage_limit" "test" { + cluster_identifier = aws_redshift_cluster.test.id + feature_type = "concurrency-scaling" + limit_type = "time" + amount = 60 + + tags = var.resource_tags +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/redshift/testdata/tmpl/cluster_data_source.gtpl b/internal/service/redshift/testdata/tmpl/cluster_data_source.gtpl new file mode 100644 index 000000000000..d470e6374849 --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/cluster_data_source.gtpl @@ -0,0 +1,3 @@ +data "aws_redshift_cluster" "test" { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier +} diff --git a/internal/service/redshift/testdata/tmpl/cluster_snapshot_tags.gtpl b/internal/service/redshift/testdata/tmpl/cluster_snapshot_tags.gtpl new file mode 100644 index 000000000000..cb4088998281 --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/cluster_snapshot_tags.gtpl @@ -0,0 +1,19 @@ +resource "aws_redshift_cluster_snapshot" "test" { +{{- template "region" }} + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + snapshot_identifier = var.rName +{{- template "tags" . }} +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { +{{- template "region" }} + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} diff --git a/internal/service/redshift/testdata/tmpl/cluster_tags.gtpl b/internal/service/redshift/testdata/tmpl/cluster_tags.gtpl new file mode 100644 index 000000000000..6b836ce628d2 --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/cluster_tags.gtpl @@ -0,0 +1,11 @@ +resource "aws_redshift_cluster" "test" { +{{- template "region" }} + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +{{- template "tags" . }} +} diff --git a/internal/service/redshift/testdata/tmpl/event_subscription_tags.gtpl b/internal/service/redshift/testdata/tmpl/event_subscription_tags.gtpl new file mode 100644 index 000000000000..262cdde708ed --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/event_subscription_tags.gtpl @@ -0,0 +1,11 @@ +resource "aws_redshift_event_subscription" "test" { +{{- template "region" }} + name = var.rName + sns_topic_arn = aws_sns_topic.test.arn +{{- template "tags" . }} +} + +resource "aws_sns_topic" "test" { +{{- template "region" }} + name = var.rName +} diff --git a/internal/service/redshift/testdata/tmpl/hsm_client_certificate_tags.gtpl b/internal/service/redshift/testdata/tmpl/hsm_client_certificate_tags.gtpl new file mode 100644 index 000000000000..481c4650f1e2 --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/hsm_client_certificate_tags.gtpl @@ -0,0 +1,5 @@ +resource "aws_redshift_hsm_client_certificate" "test" { +{{- template "region" }} + hsm_client_certificate_identifier = var.rName +{{- template "tags" . }} +} diff --git a/internal/service/redshift/testdata/tmpl/hsm_configuration_tags.gtpl b/internal/service/redshift/testdata/tmpl/hsm_configuration_tags.gtpl new file mode 100644 index 000000000000..971a5e32c08a --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/hsm_configuration_tags.gtpl @@ -0,0 +1,10 @@ +resource "aws_redshift_hsm_configuration" "test" { +{{- template "region" }} + description = var.rName + hsm_configuration_identifier = var.rName + hsm_ip_address = "10.0.0.1" + hsm_partition_name = "aws" + hsm_partition_password = var.rName + hsm_server_public_certificate = var.rName +{{- template "tags" . }} +} diff --git a/internal/service/redshift/testdata/tmpl/integration_tags.gtpl b/internal/service/redshift/testdata/tmpl/integration_tags.gtpl new file mode 100644 index 000000000000..240c3bd58b2e --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/integration_tags.gtpl @@ -0,0 +1,132 @@ +resource "aws_redshift_integration" "test" { +{{- template "region" }} + integration_name = var.rName + source_arn = aws_dynamodb_table.test.arn + target_arn = aws_redshiftserverless_namespace.test.arn + + depends_on = [ + aws_redshiftserverless_workgroup.test, + aws_redshift_resource_policy.test, + aws_dynamodb_resource_policy.test, + ] +{{- template "tags" . }} +} + +# testAccIntegrationConfig_source_DynamoDBTable + +# The "aws_redshiftserverless_resource_policy" resource doesn't support the following action types. +# Therefore we need to use the "aws_redshift_resource_policy" resource for RedShift-serverless instead. +resource "aws_redshift_resource_policy" "test" { +{{- template "region" }} + resource_arn = aws_redshiftserverless_namespace.test.arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "redshift:AuthorizeInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + Condition = { + StringEquals = { + "aws:SourceArn" = aws_dynamodb_table.test.arn + } + } + }, + { + Effect = "Allow" + Principal = { + AWS = "arn:${data.aws_partition.current.partition}:iam::${data.aws_caller_identity.current.account_id}:root" + } + Action = "redshift:CreateInboundIntegration" + Resource = aws_redshiftserverless_namespace.test.arn + } + ] + }) +} + +resource "aws_dynamodb_table" "test" { +{{- template "region" }} + name = var.rName + read_capacity = 1 + write_capacity = 1 + hash_key = var.rName + + attribute { + name = var.rName + type = "S" + } + + point_in_time_recovery { + enabled = true + } +} + +resource "aws_dynamodb_resource_policy" "test" { +{{- template "region" }} + resource_arn = aws_dynamodb_table.test.arn + policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = [ + "dynamodb:ExportTableToPointInTime", + "dynamodb:DescribeTable" + ] + Resource = aws_dynamodb_table.test.arn + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + }, + { + Effect = "Allow" + Principal = { + Service = "redshift.amazonaws.com" + } + Action = "dynamodb:DescribeExport" + Resource = "${aws_dynamodb_table.test.arn}/export/*" + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnEquals = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:redshift:*:${data.aws_caller_identity.current.account_id}:integration:*" + } + } + } + ] + }) +} + +# testAccIntegrationConfig_base + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +resource "aws_redshiftserverless_namespace" "test" { +{{- template "region" }} + namespace_name = var.rName +} + +resource "aws_redshiftserverless_workgroup" "test" { +{{- template "region" }} + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = var.rName + base_capacity = 8 + + publicly_accessible = false + subnet_ids = aws_subnet.test[*].id +} + +{{ template "acctest.ConfigVPCWithSubnets" 2 }} diff --git a/internal/service/redshift/testdata/tmpl/parameter_group_tags.gtpl b/internal/service/redshift/testdata/tmpl/parameter_group_tags.gtpl new file mode 100644 index 000000000000..1be2f563829f --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/parameter_group_tags.gtpl @@ -0,0 +1,6 @@ +resource "aws_redshift_parameter_group" "test" { +{{- template "region" }} + name = var.rName + family = "redshift-1.0" +{{- template "tags" . }} +} diff --git a/internal/service/redshift/testdata/tmpl/snapshot_copy_grant_tags.gtpl b/internal/service/redshift/testdata/tmpl/snapshot_copy_grant_tags.gtpl new file mode 100644 index 000000000000..6dba11e15988 --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/snapshot_copy_grant_tags.gtpl @@ -0,0 +1,5 @@ +resource "aws_redshift_snapshot_copy_grant" "test" { +{{- template "region" }} + snapshot_copy_grant_name = var.rName +{{- template "tags" . }} +} diff --git a/internal/service/redshift/testdata/tmpl/snapshot_schedule_tags.gtpl b/internal/service/redshift/testdata/tmpl/snapshot_schedule_tags.gtpl new file mode 100644 index 000000000000..a53966ead606 --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/snapshot_schedule_tags.gtpl @@ -0,0 +1,8 @@ +resource "aws_redshift_snapshot_schedule" "test" { +{{- template "region" }} + identifier = var.rName + definitions = [ + "rate(12 hours)", + ] +{{- template "tags" . }} +} diff --git a/internal/service/redshift/testdata/tmpl/subnet_group_data_source.gtpl b/internal/service/redshift/testdata/tmpl/subnet_group_data_source.gtpl new file mode 100644 index 000000000000..53e09bb6a09b --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/subnet_group_data_source.gtpl @@ -0,0 +1,3 @@ +data "aws_redshift_subnet_group" "test" { + name = aws_redshift_subnet_group.test.name +} diff --git a/internal/service/redshift/testdata/tmpl/subnet_group_tags.gtpl b/internal/service/redshift/testdata/tmpl/subnet_group_tags.gtpl new file mode 100644 index 000000000000..11ccf039308a --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/subnet_group_tags.gtpl @@ -0,0 +1,8 @@ +resource "aws_redshift_subnet_group" "test" { +{{- template "region" }} + name = var.rName + subnet_ids = aws_subnet.test[*].id +{{- template "tags" . }} +} + +{{ template "acctest.ConfigVPCWithSubnets" 2 }} diff --git a/internal/service/redshift/testdata/tmpl/usage_limit_tags.gtpl b/internal/service/redshift/testdata/tmpl/usage_limit_tags.gtpl new file mode 100644 index 000000000000..c724a892e3be --- /dev/null +++ b/internal/service/redshift/testdata/tmpl/usage_limit_tags.gtpl @@ -0,0 +1,21 @@ +resource "aws_redshift_usage_limit" "test" { +{{- template "region" }} + cluster_identifier = aws_redshift_cluster.test.id + feature_type = "concurrency-scaling" + limit_type = "time" + amount = 60 +{{- template "tags" . }} +} + +# testAccClusterConfig_basic + +resource "aws_redshift_cluster" "test" { +{{- template "region" }} + cluster_identifier = var.rName + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} diff --git a/internal/service/redshift/usage_limit_tags_gen_test.go b/internal/service/redshift/usage_limit_tags_gen_test.go new file mode 100644 index 000000000000..60f44ef58d0d --- /dev/null +++ b/internal/service/redshift/usage_limit_tags_gen_test.go @@ -0,0 +1,2271 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package redshift_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccRedshiftUsageLimit_tags(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + // TODO: Should be known + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccRedshiftUsageLimit_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_redshift_usage_limit.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), + CheckDestroy: testAccCheckUsageLimitDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/UsageLimit/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckUsageLimitExists(ctx, resourceName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/redshift/usage_limit_test.go b/internal/service/redshift/usage_limit_test.go index 72f27643f30e..c830941b2380 100644 --- a/internal/service/redshift/usage_limit_test.go +++ b/internal/service/redshift/usage_limit_test.go @@ -64,50 +64,6 @@ func TestAccRedshiftUsageLimit_basic(t *testing.T) { }) } -func TestAccRedshiftUsageLimit_tags(t *testing.T) { - ctx := acctest.Context(t) - resourceName := "aws_redshift_usage_limit.test" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, - ErrorCheck: acctest.ErrorCheck(t, names.RedshiftServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckUsageLimitDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccUsageLimitConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), - Check: resource.ComposeTestCheckFunc( - testAccCheckUsageLimitExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccUsageLimitConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "2"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - { - Config: testAccUsageLimitConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), - Check: resource.ComposeTestCheckFunc( - testAccCheckUsageLimitExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "1"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), - ), - }, - }, - }) -} - func TestAccRedshiftUsageLimit_disappears(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_redshift_usage_limit.test" @@ -185,34 +141,3 @@ resource "aws_redshift_usage_limit" "test" { } `, amount)) } - -func testAccUsageLimitConfig_tags1(rName, tagKey1, tagValue1 string) string { - return acctest.ConfigCompose(testAccClusterConfig_basic(rName), fmt.Sprintf(` -resource "aws_redshift_usage_limit" "test" { - cluster_identifier = aws_redshift_cluster.test.id - feature_type = "concurrency-scaling" - limit_type = "time" - amount = 60 - - tags = { - %[1]q = %[2]q - } -} -`, tagKey1, tagValue1)) -} - -func testAccUsageLimitConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(testAccClusterConfig_basic(rName), fmt.Sprintf(` -resource "aws_redshift_usage_limit" "test" { - cluster_identifier = aws_redshift_cluster.test.id - feature_type = "concurrency-scaling" - limit_type = "time" - amount = 60 - - tags = { - %[1]q = %[2]q - %[3]q = %[4]q - } -} -`, tagKey1, tagValue1, tagKey2, tagValue2)) -} diff --git a/internal/service/route53/zone_data_source.go b/internal/service/route53/zone_data_source.go index afe49ed04a92..e36e25c6ca68 100644 --- a/internal/service/route53/zone_data_source.go +++ b/internal/service/route53/zone_data_source.go @@ -73,7 +73,6 @@ func dataSourceZone() *schema.Resource { names.AttrVPCID: { Type: schema.TypeString, Optional: true, - Computed: true, }, "zone_id": { Type: schema.TypeString, @@ -85,41 +84,86 @@ func dataSourceZone() *schema.Resource { } func dataSourceZoneRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - var diags diag.Diagnostics + var ( + diags diag.Diagnostics + zoneID, name, vpcID string + privateZone bool + zoneIDSet, nameSet, vpcIDSet bool + ) + conn := meta.(*conns.AWSClient).Route53Client(ctx) ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig(ctx) - name := d.Get(names.AttrName).(string) - zoneID, zoneIDExists := d.GetOk("zone_id") - vpcID, vpcIDExists := d.GetOk(names.AttrVPCID) + if v, ok := d.GetOk("zone_id"); ok { + zoneID, zoneIDSet = v.(string), ok + } + if v, ok := d.GetOk(names.AttrName); ok { + name, nameSet = v.(string), ok + } + if zoneIDSet && nameSet { + // Warning for backwards compatibility. + return sdkdiag.AppendWarningf(diags, "only one of `zone_id` or `name` may be set") + } + + if v, ok := d.GetOk(names.AttrVPCID); ok { + vpcID, vpcIDSet = v.(string), ok + privateZone = true + } + if v, ok := d.GetOk("private_zone"); ok { + privateZone = v.(bool) + } + if vpcIDSet && !privateZone { + // Warning for backwards compatibility. + return sdkdiag.AppendWarningf(diags, "`vpc_id` can only be set for private zones") + } + tags := tftags.New(ctx, d.Get(names.AttrTags).(map[string]any)).IgnoreAWS() - input := &route53.ListHostedZonesInput{} - var hostedZones []awstypes.HostedZone - pages := route53.NewListHostedZonesPaginator(conn, input) - for pages.HasMorePages() { - page, err := pages.NextPage(ctx) + var ( + hostedZone *awstypes.HostedZone + zoneTags tftags.KeyValueTags + ) + if zoneIDSet { + // Perform direct lookup on unique zoneID + foundZone, err := findHostedZoneByID(ctx, conn, zoneID) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading Route 53 Hosted Zones: %s", err) + return sdkdiag.AppendFromErr(diags, err) } + hostedZone = foundZone.HostedZone + } else { + // As name is not unique, we need to list all zones and filter + var hostedZones []awstypes.HostedZone + input := &route53.ListHostedZonesInput{} + pages := route53.NewListHostedZonesPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading Route 53 Hosted Zones: %s", err) + } - for _, hostedZone := range page.HostedZones { - hostedZoneID := cleanZoneID(aws.ToString(hostedZone.Id)) - if zoneIDExists && hostedZoneID == zoneID.(string) { - hostedZones = append(hostedZones, hostedZone) - // we check if the name is the same as requested and if private zone field is the same as requested or if there is a vpc_id - } else if (normalizeDomainName(aws.ToString(hostedZone.Name)) == normalizeDomainName(name)) && (hostedZone.Config.PrivateZone == d.Get("private_zone").(bool) || (hostedZone.Config.PrivateZone && vpcIDExists)) { - matchingVPC := false - if vpcIDExists { - hostedZone, err := findHostedZoneByID(ctx, conn, hostedZoneID) + for _, zone := range page.HostedZones { + // skip zone on explicit name mismatch + if nameSet && (normalizeDomainName(aws.ToString(zone.Name)) != normalizeDomainName(name)) { + continue + } + // skip zone on type mismatch + if zone.Config.PrivateZone != privateZone { + continue + } + + zoneID := cleanZoneID(aws.ToString(zone.Id)) + + matchingVPC := false + if vpcIDSet { + zoneDetails, err := findHostedZoneByID(ctx, conn, zoneID) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading Route 53 Hosted Zone (%s): %s", hostedZoneID, err) + return sdkdiag.AppendErrorf(diags, "reading Route 53 Hosted Zone (%s): %s", zoneID, err) } - for _, v := range hostedZone.VPCs { - if aws.ToString(v.VPCId) == vpcID.(string) { + for _, v := range zoneDetails.VPCs { + if aws.ToString(v.VPCId) == vpcID { matchingVPC = true break } @@ -130,26 +174,26 @@ func dataSourceZoneRead(ctx context.Context, d *schema.ResourceData, meta any) d matchingTags := true if len(tags) > 0 { - output, err := listTags(ctx, conn, hostedZoneID, string(awstypes.TagResourceTypeHostedzone)) - + var err error + zoneTags, err = listTags(ctx, conn, zoneID, string(awstypes.TagResourceTypeHostedzone)) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing Route 53 Hosted Zone (%s) tags: %s", hostedZoneID, err) + return sdkdiag.AppendErrorf(diags, "listing Route 53 Hosted Zone (%s) tags: %s", zoneID, err) } - matchingTags = output.ContainsAll(tags) + matchingTags = zoneTags.ContainsAll(tags) } if matchingTags && matchingVPC { - hostedZones = append(hostedZones, hostedZone) + hostedZones = append(hostedZones, zone) } } } - } - hostedZone, err := tfresource.AssertSingleValueResult(hostedZones) - - if err != nil { - return sdkdiag.AppendFromErr(diags, tfresource.SingularDataSourceFindError("Route 53 Hosted Zone", err)) + var err error + hostedZone, err = tfresource.AssertSingleValueResult(hostedZones) + if err != nil { + return sdkdiag.AppendFromErr(diags, tfresource.SingularDataSourceFindError("Route 53 Hosted Zone", err)) + } } hostedZoneID := cleanZoneID(aws.ToString(hostedZone.Id)) @@ -169,7 +213,6 @@ func dataSourceZoneRead(ctx context.Context, d *schema.ResourceData, meta any) d d.Set("zone_id", hostedZoneID) nameServers, err := findHostedZoneNameServers(ctx, conn, hostedZoneID, aws.ToString(hostedZone.Name)) - if err != nil { return sdkdiag.AppendFromErr(diags, err) } @@ -177,13 +220,15 @@ func dataSourceZoneRead(ctx context.Context, d *schema.ResourceData, meta any) d d.Set("name_servers", nameServers) d.Set("primary_name_server", nameServers[0]) - tags, err = listTags(ctx, conn, hostedZoneID, string(awstypes.TagResourceTypeHostedzone)) - - if err != nil { - return sdkdiag.AppendErrorf(diags, "listing Route 53 Hosted Zone (%s) tags: %s", hostedZoneID, err) + if zoneTags == nil { + tags, err := listTags(ctx, conn, hostedZoneID, string(awstypes.TagResourceTypeHostedzone)) + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing Route 53 Hosted Zone (%s) tags: %s", hostedZoneID, err) + } + zoneTags = tags } - if err := d.Set(names.AttrTags, tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + if err := d.Set(names.AttrTags, zoneTags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) } diff --git a/internal/service/route53/zone_data_source_test.go b/internal/service/route53/zone_data_source_test.go index 42b09f045aea..c68c9eb829de 100644 --- a/internal/service/route53/zone_data_source_test.go +++ b/internal/service/route53/zone_data_source_test.go @@ -130,6 +130,34 @@ func TestAccRoute53ZoneDataSource_tags(t *testing.T) { }) } +func TestAccRoute53ZoneDataSource_tagsOnly(t *testing.T) { + ctx := acctest.Context(t) + rInt := sdkacctest.RandInt() + resourceName := "aws_route53_zone.test" + dataSourceName := "data.aws_route53_zone.test" + + fqdn := acctest.RandomFQDomainName() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.Route53ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckZoneDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccZoneDataSourceConfig_tagsOnly(fqdn, rInt), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, names.AttrID, dataSourceName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, names.AttrName, dataSourceName, names.AttrName), + resource.TestCheckResourceAttrPair(resourceName, "name_servers.#", dataSourceName, "name_servers.#"), + resource.TestCheckResourceAttrPair(resourceName, "primary_name_server", dataSourceName, "primary_name_server"), + resource.TestCheckResourceAttrPair(resourceName, names.AttrTags, dataSourceName, names.AttrTags), + ), + }, + }, + }) +} + func TestAccRoute53ZoneDataSource_vpc(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() @@ -156,6 +184,32 @@ func TestAccRoute53ZoneDataSource_vpc(t *testing.T) { }) } +func TestAccRoute53ZoneDataSource_vpcOnly(t *testing.T) { + ctx := acctest.Context(t) + rInt := sdkacctest.RandInt() + resourceName := "aws_route53_zone.test" + dataSourceName := "data.aws_route53_zone.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.Route53ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckZoneDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccZoneDataSourceConfig_vpcOnly(rInt), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, names.AttrID, dataSourceName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, names.AttrName, dataSourceName, names.AttrName), + resource.TestCheckResourceAttrPair(resourceName, "name_servers.#", dataSourceName, "name_servers.#"), + resource.TestCheckResourceAttrPair(resourceName, "primary_name_server", dataSourceName, "primary_name_server"), + resource.TestCheckResourceAttrPair(resourceName, names.AttrTags, dataSourceName, names.AttrTags), + ), + }, + }, + }) +} + func TestAccRoute53ZoneDataSource_serviceDiscovery(t *testing.T) { ctx := acctest.Context(t) rInt := sdkacctest.RandInt() @@ -248,6 +302,28 @@ data "aws_route53_zone" "test" { `, fqdn, rInt) } +func testAccZoneDataSourceConfig_tagsOnly(fqdn string, rInt int) string { + return fmt.Sprintf(` +resource "aws_route53_zone" "test" { + name = %[1]q + + tags = { + Environment = "tf-acc-test-%[2]d" + Name = "tf-acc-test-%[2]d" + } +} + +data "aws_route53_zone" "test" { + tags = { + Environment = "tf-acc-test-%[2]d" + Name = "tf-acc-test-%[2]d" + } + + depends_on = [aws_route53_zone.test] +} +`, fqdn, rInt) +} + func testAccZoneDataSourceConfig_vpc(rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "test" { @@ -278,6 +354,36 @@ data "aws_route53_zone" "test" { `, rInt) } +func testAccZoneDataSourceConfig_vpcOnly(rInt int) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "terraform-testacc-r53-zone-data-source-%[1]d" + } +} + +resource "aws_route53_zone" "test" { + name = "test.acc-%[1]d." + + vpc { + vpc_id = aws_vpc.test.id + } + + tags = { + Environment = "dev-%[1]d" + } +} + +data "aws_route53_zone" "test" { + vpc_id = aws_vpc.test.id + + depends_on = [aws_route53_zone.test] +} +`, rInt) +} + func testAccZoneDataSourceConfig_serviceDiscovery(rInt int) string { return fmt.Sprintf(` resource "aws_vpc" "test" { diff --git a/internal/service/s3/bucket_notification.go b/internal/service/s3/bucket_notification.go index 48441d4dd1e4..69c8c6a859f0 100644 --- a/internal/service/s3/bucket_notification.go +++ b/internal/service/s3/bucket_notification.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -422,7 +422,7 @@ func findBucketNotificationConfiguration(ctx context.Context, conn *s3.Client, b return nil, err } - if itypes.IsZero(output) { + if inttypes.IsZero(output) { return nil, tfresource.NewEmptyResultError(input) } diff --git a/internal/service/s3/bucket_object.go b/internal/service/s3/bucket_object.go index 84953e82f4b6..18121bed696b 100644 --- a/internal/service/s3/bucket_object.go +++ b/internal/service/s3/bucket_object.go @@ -31,7 +31,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" "github.com/mitchellh/go-homedir" @@ -375,7 +375,7 @@ func resourceBucketObjectUpload(ctx context.Context, d *schema.ResourceData, met content := v.(string) // We can't do streaming decoding here (with base64.NewDecoder) because // the AWS SDK requires an io.ReadSeeker but a base64 decoder can't seek. - contentRaw, err := itypes.Base64Decode(content) + contentRaw, err := inttypes.Base64Decode(content) if err != nil { return sdkdiag.AppendErrorf(diags, "decoding content_base64: %s", err) } diff --git a/internal/service/s3/bucket_server_side_encryption_configuration.go b/internal/service/s3/bucket_server_side_encryption_configuration.go index 8c3eccbf72b3..9ce605db44e8 100644 --- a/internal/service/s3/bucket_server_side_encryption_configuration.go +++ b/internal/service/s3/bucket_server_side_encryption_configuration.go @@ -74,6 +74,14 @@ func resourceBucketServerSideEncryptionConfiguration() *schema.Resource { }, }, }, + "blocked_encryption_types": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateDiagFunc: enum.Validate[types.EncryptionType](), + }, + }, "bucket_key_enabled": { Type: schema.TypeBool, Optional: true, @@ -294,6 +302,10 @@ func expandServerSideEncryptionRules(l []any) []types.ServerSideEncryptionRule { rule.ApplyServerSideEncryptionByDefault = expandServerSideEncryptionByDefault(v) } + if v, ok := tfMap["blocked_encryption_types"].([]any); ok && len(v) > 0 { + rule.BlockedEncryptionTypes = expandBlockedEncryptionTypes(v) + } + if v, ok := tfMap["bucket_key_enabled"].(bool); ok { rule.BucketKeyEnabled = aws.Bool(v) } @@ -314,6 +326,12 @@ func flattenServerSideEncryptionRules(rules []types.ServerSideEncryptionRule) [] m["apply_server_side_encryption_by_default"] = flattenServerSideEncryptionByDefault(rule.ApplyServerSideEncryptionByDefault) } + if rule.BlockedEncryptionTypes != nil { + if flattened := flattenBlockedEncryptionTypes(rule.BlockedEncryptionTypes); flattened != nil { + m["blocked_encryption_types"] = flattened + } + } + if rule.BucketKeyEnabled != nil { m["bucket_key_enabled"] = aws.ToBool(rule.BucketKeyEnabled) } @@ -339,3 +357,31 @@ func flattenServerSideEncryptionByDefault(sse *types.ServerSideEncryptionByDefau return []any{m} } + +func expandBlockedEncryptionTypes(l []any) *types.BlockedEncryptionTypes { + if len(l) == 0 { + return nil + } + + var encryptionTypes []types.EncryptionType + for _, v := range l { + encryptionTypes = append(encryptionTypes, types.EncryptionType(v.(string))) + } + + return &types.BlockedEncryptionTypes{ + EncryptionType: encryptionTypes, + } +} + +func flattenBlockedEncryptionTypes(bet *types.BlockedEncryptionTypes) []any { + if bet == nil || len(bet.EncryptionType) == 0 { + return nil + } + + var result []any + for _, et := range bet.EncryptionType { + result = append(result, string(et)) + } + + return result +} diff --git a/internal/service/s3/bucket_server_side_encryption_configuration_test.go b/internal/service/s3/bucket_server_side_encryption_configuration_test.go index 2348d599d0cc..1994dd7e9fa2 100644 --- a/internal/service/s3/bucket_server_side_encryption_configuration_test.go +++ b/internal/service/s3/bucket_server_side_encryption_configuration_test.go @@ -53,6 +53,47 @@ func TestAccS3BucketServerSideEncryptionConfiguration_basic(t *testing.T) { }) } +func TestAccS3BucketServerSideEncryptionConfiguration_blockedEncryptionTypes(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_bucket_server_side_encryption_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: acctest.CheckDestroyNoop, + Steps: []resource.TestStep{ + { + Config: testAccBucketServerSideEncryptionConfigurationConfig_blockedEncryptionTypes(rName, `["SSE-C"]`), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckBucketServerSideEncryptionConfigurationExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, acctest.CtRulePound, "1"), + resource.TestCheckResourceAttr(resourceName, "rule.0.blocked_encryption_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.0.blocked_encryption_types.0", "SSE-C"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "rule.0.bucket_key_enabled", + }, + }, + { + Config: testAccBucketServerSideEncryptionConfigurationConfig_blockedEncryptionTypes(rName, `["NONE"]`), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckBucketServerSideEncryptionConfigurationExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, acctest.CtRulePound, "1"), + resource.TestCheckResourceAttr(resourceName, "rule.0.blocked_encryption_types.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.0.blocked_encryption_types.0", "NONE"), + ), + }, + }, + }) +} + func TestAccS3BucketServerSideEncryptionConfiguration_ApplySEEByDefault_AES256(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -634,6 +675,32 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "test" { `, rName, enabled) } +func testAccBucketServerSideEncryptionConfigurationConfig_blockedEncryptionTypes(rName, blockedTypes string) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = "KMS Key for Bucket %[1]s" + deletion_window_in_days = 10 +} + +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "test" { + bucket = aws_s3_bucket.test.bucket + + rule { + apply_server_side_encryption_by_default { + kms_master_key_id = aws_kms_key.test.id + sse_algorithm = "aws:kms" + } + bucket_key_enabled = true + blocked_encryption_types = %[2]s + } +} +`, rName, blockedTypes) +} + func testAccBucketServerSideEncryptionConfigurationConfig_migrateNoChange(rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { diff --git a/internal/service/s3/directory_bucket.go b/internal/service/s3/directory_bucket.go index bac6188beeb8..211e38f08738 100644 --- a/internal/service/s3/directory_bucket.go +++ b/internal/service/s3/directory_bucket.go @@ -190,7 +190,9 @@ func (r *directoryBucketResource) Read(ctx context.Context, request resource.Rea conn := r.Meta().S3ExpressClient(ctx) bucket := fwflex.StringValueFromFramework(ctx, data.ID) - output, err := findBucket(ctx, conn, bucket) + // https://github.com/hashicorp/terraform-provider-aws/issues/44095. + // Disable S3 Expression session authentication for HeadBucket. + output, err := findBucket(ctx, conn, bucket, func(o *s3.Options) { o.DisableS3ExpressSessionAuth = aws.Bool(true) }) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) diff --git a/internal/service/s3/object.go b/internal/service/s3/object.go index 40e19c67e059..05154c44258f 100644 --- a/internal/service/s3/object.go +++ b/internal/service/s3/object.go @@ -35,7 +35,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" "github.com/mitchellh/go-homedir" @@ -476,7 +476,7 @@ func resourceObjectUpload(ctx context.Context, d *schema.ResourceData, meta any) } else if v, ok := d.GetOk("content_base64"); ok { // We can't do streaming decoding here (with base64.NewDecoder) because // the AWS SDK requires an io.ReadSeeker but a base64 decoder can't seek. - v, err := itypes.Base64Decode(v.(string)) + v, err := inttypes.Base64Decode(v.(string)) if err != nil { return sdkdiag.AppendFromErr(diags, err) } diff --git a/internal/service/s3/tags.go b/internal/service/s3/tags.go index 94da8d8de8d8..325974e9a3cc 100644 --- a/internal/service/s3/tags.go +++ b/internal/service/s3/tags.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build !generate -// +build !generate package s3 diff --git a/internal/service/s3control/access_point_test.go b/internal/service/s3control/access_point_test.go index 515fc1183da6..da686675e299 100644 --- a/internal/service/s3control/access_point_test.go +++ b/internal/service/s3control/access_point_test.go @@ -321,7 +321,7 @@ func TestAccS3ControlAccessPoint_vpc(t *testing.T) { }) } -func TestAccS3ControlAccessPoint_directoryBucket_basic(t *testing.T) { +func TestAccS3ControlAccessPoint_DirectoryBucket_basic(t *testing.T) { ctx := acctest.Context(t) var v s3control.GetAccessPointOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -334,7 +334,7 @@ func TestAccS3ControlAccessPoint_directoryBucket_basic(t *testing.T) { CheckDestroy: testAccCheckAccessPointDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccAccessPointConfig_directoryBucket(rName), + Config: testAccAccessPointConfig_directoryBucketBasic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAccessPointExists(ctx, resourceName, &v), acctest.CheckResourceAttrAccountID(ctx, resourceName, names.AttrAccountID), @@ -413,6 +413,76 @@ func TestAccS3ControlAccessPoint_tags(t *testing.T) { }) } +func TestAccS3ControlAccessPoint_DirectoryBucket_tags(t *testing.T) { + ctx := acctest.Context(t) + var v s3control.GetAccessPointOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_s3_access_point.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.S3ControlServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAccessPointDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAccessPointConfig_directoryBucketTags1(rName, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPointExists(ctx, resourceName, &v), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAccessPointConfig_directoryBucketTags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPointExists(ctx, resourceName, &v), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + { + Config: testAccAccessPointConfig_directoryBucketTags1(rName, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAccessPointExists(ctx, resourceName, &v), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + }) +} + func testAccCheckAccessPointDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).S3ControlClient(ctx) @@ -706,7 +776,7 @@ resource "aws_s3_access_point" "test" { `, rName) } -func testAccAccessPointConfig_directoryBucket(rName string) string { +func testAccAccessPointConfig_baseDirectoryBucket(rName string) string { return acctest.ConfigCompose( acctest.ConfigAvailableAZsNoOptInExclude("use2-az2", "use1-az1", "use1-az2", "use1-az3", "usw2-az2", "aps1-az3", "apne1-az2", "euw1-az2"), fmt.Sprintf(` @@ -723,7 +793,11 @@ resource "aws_s3_directory_bucket" "test" { force_destroy = true } +`, rName)) +} +func testAccAccessPointConfig_directoryBucketBasic(rName string) string { + return acctest.ConfigCompose(testAccAccessPointConfig_baseDirectoryBucket(rName), fmt.Sprintf(` resource "aws_s3_access_point" "test" { bucket = aws_s3_directory_bucket.test.bucket name = "%[1]s--${local.location_name}--xa-s3" @@ -765,3 +839,30 @@ resource "aws_s3_access_point" "test" { } `, bucketName, accessPointName, tagKey1, tagValue1, tagKey2, tagValue2) } + +func testAccAccessPointConfig_directoryBucketTags1(rName, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose(testAccAccessPointConfig_baseDirectoryBucket(rName), fmt.Sprintf(` +resource "aws_s3_access_point" "test" { + bucket = aws_s3_directory_bucket.test.bucket + name = "%[1]s--${local.location_name}--xa-s3" + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccAccessPointConfig_directoryBucketTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose(testAccAccessPointConfig_baseDirectoryBucket(rName), fmt.Sprintf(` +resource "aws_s3_access_point" "test" { + bucket = aws_s3_directory_bucket.test.bucket + name = "%[1]s--${local.location_name}--xa-s3" + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} diff --git a/internal/service/s3control/directory_bucket_access_point_scope_test.go b/internal/service/s3control/directory_bucket_access_point_scope_test.go index 1cd066c317a8..877edec938be 100644 --- a/internal/service/s3control/directory_bucket_access_point_scope_test.go +++ b/internal/service/s3control/directory_bucket_access_point_scope_test.go @@ -188,7 +188,7 @@ func testAccCheckDirectoryBucketAccessPointScopeDestroy(ctx context.Context) res } func testAccAccessPointScopeConfig_basic(rName string) string { - return acctest.ConfigCompose(testAccAccessPointConfig_directoryBucket(rName), ` + return acctest.ConfigCompose(testAccAccessPointConfig_directoryBucketBasic(rName), ` data "aws_caller_identity" "current" {} resource "aws_s3control_directory_bucket_access_point_scope" "test" { @@ -204,7 +204,7 @@ resource "aws_s3control_directory_bucket_access_point_scope" "test" { } func testAccAccessPointScopeConfig_updated(rName string) string { - return acctest.ConfigCompose(testAccAccessPointConfig_directoryBucket(rName), ` + return acctest.ConfigCompose(testAccAccessPointConfig_directoryBucketBasic(rName), ` data "aws_caller_identity" "current" {} resource "aws_s3control_directory_bucket_access_point_scope" "test" { diff --git a/internal/service/s3tables/generate.go b/internal/service/s3tables/generate.go index 998536c74211..464bf3c54a45 100644 --- a/internal/service/s3tables/generate.go +++ b/internal/service/s3tables/generate.go @@ -2,6 +2,9 @@ // SPDX-License-Identifier: MPL-2.0 //go:generate go run ../../generate/servicepackage/main.go +//go:generate go run ../../generate/tags/main.go -ListTags -UpdateTags -ServiceTagsMap -KVTValues +//go:generate go run ../../generate/tagstests/main.go +//go:generate go run ../../generate/identitytests/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. package s3tables diff --git a/internal/service/s3tables/service_package_gen.go b/internal/service/s3tables/service_package_gen.go index 1db7296956b2..571434705df2 100644 --- a/internal/service/s3tables/service_package_gen.go +++ b/internal/service/s3tables/service_package_gen.go @@ -33,19 +33,33 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.Ser Factory: newTableResource, TypeName: "aws_s3tables_table", Name: "Table", - Region: unique.Make(inttypes.ResourceRegionDefault()), + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }), + Region: unique.Make(inttypes.ResourceRegionDefault()), }, { Factory: newTableBucketResource, TypeName: "aws_s3tables_table_bucket", Name: "Table Bucket", + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }), Region: unique.Make(inttypes.ResourceRegionDefault()), + Identity: inttypes.RegionalARNIdentity(), + Import: inttypes.FrameworkImport{ + WrappedImport: true, + }, }, { Factory: newTableBucketPolicyResource, TypeName: "aws_s3tables_table_bucket_policy", Name: "Table Bucket Policy", Region: unique.Make(inttypes.ResourceRegionDefault()), + Identity: inttypes.RegionalARNIdentityNamed("table_bucket_arn"), + Import: inttypes.FrameworkImport{ + WrappedImport: true, + }, }, { Factory: newTablePolicyResource, diff --git a/internal/service/s3tables/table.go b/internal/service/s3tables/table.go index fdf15d2f7cae..b9b919f65a05 100644 --- a/internal/service/s3tables/table.go +++ b/internal/service/s3tables/table.go @@ -36,11 +36,17 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/framework" fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) // @FrameworkResource("aws_s3tables_table", name="Table") +// @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/s3tables;s3tables.GetTableOutput") +// @Testing(importStateIdAttribute="arn") +// @Testing(importStateIdFunc="testAccTableImportStateIdFunc") +// @Testing(preCheck="testAccPreCheck") func newTableResource(_ context.Context) (resource.ResourceWithConfigure, error) { return &tableResource{}, nil } @@ -127,6 +133,8 @@ func (r *tableResource) Schema(ctx context.Context, request resource.SchemaReque stringplanmodifier.RequiresReplace(), }, }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), names.AttrType: schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.TableType](), Computed: true, @@ -247,6 +255,9 @@ func (r *tableResource) Create(ctx context.Context, request resource.CreateReque return } + // Additional fields. + input.Tags = getTagsIn(ctx) + // Handle metadata separately since it's an interface type. if !data.Metadata.IsNull() && !data.Metadata.IsUnknown() { metadataModel, diags := data.Metadata.ToPtr(ctx) @@ -742,6 +753,8 @@ type tableResourceModel struct { Namespace types.String `tfsdk:"namespace" autoflex:",noflatten"` // On read, Namespace is an array OwnerAccountID types.String `tfsdk:"owner_account_id"` TableBucketARN fwtypes.ARN `tfsdk:"table_bucket_arn"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` Type fwtypes.StringEnum[awstypes.TableType] `tfsdk:"type"` VersionToken types.String `tfsdk:"version_token"` WarehouseLocation types.String `tfsdk:"warehouse_location"` diff --git a/internal/service/s3tables/table_bucket.go b/internal/service/s3tables/table_bucket.go index 445550a5017c..35cce21494f7 100644 --- a/internal/service/s3tables/table_bucket.go +++ b/internal/service/s3tables/table_bucket.go @@ -30,17 +30,27 @@ import ( fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework/validators" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) // @FrameworkResource("aws_s3tables_table_bucket", name="Table Bucket") +// @ArnIdentity +// @ArnFormat("bucket/{name}") +// @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/s3tables;s3tables.GetTableBucketOutput") +// @Testing(importStateIdAttribute="arn") +// @Testing(importStateIdFunc="testAccTableBucketImportStateIdFunc") +// @Testing(preCheck="testAccPreCheck") +// @Testing(preIdentityVersion="6.19.0") func newTableBucketResource(_ context.Context) (resource.ResourceWithConfigure, error) { return &tableBucketResource{}, nil } type tableBucketResource struct { framework.ResourceWithModel[tableBucketResourceModel] + framework.WithImportByIdentity } func (r *tableBucketResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { @@ -105,6 +115,8 @@ func (r *tableBucketResource) Schema(ctx context.Context, request resource.Schem stringplanmodifier.UseStateForUnknown(), }, }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), }, } } @@ -125,6 +137,9 @@ func (r *tableBucketResource) Create(ctx context.Context, request resource.Creat return } + // Additional fields. + input.Tags = getTagsIn(ctx) + outputCTB, err := conn.CreateTableBucket(ctx, &input) if err != nil { @@ -432,7 +447,7 @@ func (r *tableBucketResource) Delete(ctx context.Context, request resource.Delet } func (r *tableBucketResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrARN), request, response) + r.WithImportByIdentity.ImportState(ctx, request, response) // Set force_destroy to false on import to prevent accidental deletion response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root(names.AttrForceDestroy), types.BoolValue(false))...) @@ -531,6 +546,8 @@ type tableBucketResourceModel struct { MaintenanceConfiguration fwtypes.ObjectValueOf[tableBucketMaintenanceConfigurationModel] `tfsdk:"maintenance_configuration" autoflex:"-"` Name types.String `tfsdk:"name"` OwnerAccountID types.String `tfsdk:"owner_account_id"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` } type encryptionConfigurationModel struct { KMSKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` diff --git a/internal/service/s3tables/table_bucket_identity_gen_test.go b/internal/service/s3tables/table_bucket_identity_gen_test.go new file mode 100644 index 000000000000..a9560c2519ee --- /dev/null +++ b/internal/service/s3tables/table_bucket_identity_gen_test.go @@ -0,0 +1,354 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package s3tables_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/s3tables" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccS3TablesTableBucket_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectRegionalARNFormat(resourceName, tfjsonpath.New(names.AttrARN), "s3tables", "bucket/{name}"), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_Identity_RegionOverride(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_s3tables_table_bucket.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectRegionalARNAlternateRegionFormat(resourceName, tfjsonpath.New(names.AttrARN), "s3tables", "bucket/{name}"), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + + // Step 2: Import command with appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.CrossRegionImportStateIdFuncAdapter(resourceName, testAccTableBucketImportStateIdFunc), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + + // Step 3: Import command without appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + + // Step 4: Import block with Import ID and appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.CrossRegionImportStateIdFuncAdapter(resourceName, testAccTableBucketImportStateIdFunc), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + + // Step 5: Import block with Import ID and no appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + + // Step 6: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + }, + }, + }) +} + +// Resource Identity was added after v6.19.0 +func TestAccS3TablesTableBucket_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic_v6.19.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + names.AttrARN: knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New(names.AttrARN)), + }, + }, + }, + }) +} + +// Resource Identity was added after v6.19.0 +func TestAccS3TablesTableBucket_Identity_ExistingResource_NoRefresh_NoChange(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{ + NoRefresh: true, + }, + }, + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic_v6.19.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + }, + }) +} diff --git a/internal/service/s3tables/table_bucket_policy.go b/internal/service/s3tables/table_bucket_policy.go index 86db3d3b077a..112833cdf054 100644 --- a/internal/service/s3tables/table_bucket_policy.go +++ b/internal/service/s3tables/table_bucket_policy.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/s3tables" awstypes "github.com/aws/aws-sdk-go-v2/service/s3tables/types" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -25,12 +24,18 @@ import ( ) // @FrameworkResource("aws_s3tables_table_bucket_policy", name="Table Bucket Policy") +// @ArnIdentity("table_bucket_arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/s3tables;s3tables.GetTableBucketPolicyOutput") +// @Testing(preCheck="testAccPreCheck") +// @Testing(preIdentityVersion="6.19.0") +// @Testing(importIgnore="resource_policy") func newTableBucketPolicyResource(_ context.Context) (resource.ResourceWithConfigure, error) { return &tableBucketPolicyResource{}, nil } type tableBucketPolicyResource struct { framework.ResourceWithModel[tableBucketPolicyResourceModel] + framework.WithImportByIdentity } func (r *tableBucketPolicyResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { @@ -161,10 +166,6 @@ func (r *tableBucketPolicyResource) Delete(ctx context.Context, request resource } } -func (r *tableBucketPolicyResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("table_bucket_arn"), request, response) -} - func findTableBucketPolicyByARN(ctx context.Context, conn *s3tables.Client, tableBucketARN string) (*s3tables.GetTableBucketPolicyOutput, error) { input := s3tables.GetTableBucketPolicyInput{ TableBucketARN: aws.String(tableBucketARN), diff --git a/internal/service/s3tables/table_bucket_policy_identity_gen_test.go b/internal/service/s3tables/table_bucket_policy_identity_gen_test.go new file mode 100644 index 000000000000..03b9a26ebf6b --- /dev/null +++ b/internal/service/s3tables/table_bucket_policy_identity_gen_test.go @@ -0,0 +1,371 @@ +// Code generated by internal/generate/identitytests/main.go; DO NOT EDIT. + +package s3tables_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/s3tables" + "github.com/hashicorp/terraform-plugin-testing/config" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccS3TablesTableBucketPolicy_Identity_Basic(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketPolicyOutput + resourceName := "aws_s3tables_table_bucket_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketPolicyDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketPolicyExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + "table_bucket_arn": knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New("table_bucket_arn")), + }, + }, + + // Step 2: Import command + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "table_bucket_arn"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "table_bucket_arn", + ImportStateVerifyIgnore: []string{ + "resource_policy", + }, + }, + + // Step 3: Import block with Import ID + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "table_bucket_arn"), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("table_bucket_arn"), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + ExpectNonEmptyPlan: true, + }, + + // Step 4: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("table_bucket_arn"), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccS3TablesTableBucketPolicy_Identity_RegionOverride(t *testing.T) { + ctx := acctest.Context(t) + + resourceName := "aws_s3tables_table_bucket_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: acctest.CheckDestroyNoop, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + "table_bucket_arn": knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New("table_bucket_arn")), + }, + }, + + // Step 2: Import command with appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.CrossRegionAttrImportStateIdFunc(resourceName, "table_bucket_arn"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "table_bucket_arn", + ImportStateVerifyIgnore: []string{ + "resource_policy", + }, + }, + + // Step 3: Import command without appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ImportStateKind: resource.ImportCommandWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "table_bucket_arn"), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "table_bucket_arn", + ImportStateVerifyIgnore: []string{ + "resource_policy", + }, + }, + + // Step 4: Import block with Import ID and appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.CrossRegionAttrImportStateIdFunc(resourceName, "table_bucket_arn"), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("table_bucket_arn"), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + ExpectNonEmptyPlan: true, + }, + + // Step 5: Import block with Import ID and no appended "@" + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithID, + ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, "table_bucket_arn"), + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("table_bucket_arn"), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + ExpectNonEmptyPlan: true, + }, + + // Step 6: Import block with Resource Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/region_override/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "region": config.StringVariable(acctest.AlternateRegion()), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New("table_bucket_arn"), knownvalue.NotNull()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.AlternateRegion())), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +// Resource Identity was added after v6.19.0 +func TestAccS3TablesTableBucketPolicy_Identity_ExistingResource(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketPolicyOutput + resourceName := "aws_s3tables_table_bucket_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketPolicyDestroy(ctx), + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic_v6.19.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketPolicyExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectIdentity(resourceName, map[string]knownvalue.Check{ + "table_bucket_arn": knownvalue.NotNull(), + }), + statecheck.ExpectIdentityValueMatchesState(resourceName, tfjsonpath.New("table_bucket_arn")), + }, + }, + }, + }) +} + +// Resource Identity was added after v6.19.0 +func TestAccS3TablesTableBucketPolicy_Identity_ExistingResource_NoRefresh_NoChange(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketPolicyOutput + resourceName := "aws_s3tables_table_bucket_policy.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketPolicyDestroy(ctx), + AdditionalCLIOptions: &resource.AdditionalCLIOptions{ + Plan: resource.PlanOptions{ + NoRefresh: true, + }, + }, + Steps: []resource.TestStep{ + // Step 1: Create pre-Identity + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic_v6.19.0/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketPolicyExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + + // Step 2: Current version + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucketPolicy/basic/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + tfstatecheck.ExpectNoIdentity(resourceName), + }, + }, + }, + }) +} diff --git a/internal/service/s3tables/table_bucket_tags_gen_test.go b/internal/service/s3tables/table_bucket_tags_gen_test.go new file mode 100644 index 000000000000..cf5f439ae57f --- /dev/null +++ b/internal/service/s3tables/table_bucket_tags_gen_test.go @@ -0,0 +1,2404 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package s3tables_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/s3tables" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccS3TablesTableBucket_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + "tags.resourcekey1", // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey(acctest.CtKey1)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccS3TablesTableBucket_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableBucketOutput + resourceName := "aws_s3tables_table_bucket.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableBucketDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/TableBucket/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableBucketExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/s3tables/table_bucket_test.go b/internal/service/s3tables/table_bucket_test.go index e6584e324228..3a00dbec2954 100644 --- a/internal/service/s3tables/table_bucket_test.go +++ b/internal/service/s3tables/table_bucket_test.go @@ -61,12 +61,13 @@ func TestAccS3TablesTableBucket_basic(t *testing.T) { names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled), }), })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), }, }, { ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: names.AttrARN, ImportStateVerifyIgnore: []string{names.AttrForceDestroy}, @@ -143,7 +144,7 @@ func TestAccS3TablesTableBucket_encryptionConfiguration(t *testing.T) { { ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: names.AttrARN, ImportStateVerifyIgnore: []string{names.AttrForceDestroy}, @@ -214,7 +215,7 @@ func TestAccS3TablesTableBucket_maintenanceConfiguration(t *testing.T) { { ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: names.AttrARN, ImportStateVerifyIgnore: []string{names.AttrForceDestroy}, @@ -239,7 +240,7 @@ func TestAccS3TablesTableBucket_maintenanceConfiguration(t *testing.T) { { ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: names.AttrARN, ImportStateVerifyIgnore: []string{names.AttrForceDestroy}, @@ -264,7 +265,7 @@ func TestAccS3TablesTableBucket_maintenanceConfiguration(t *testing.T) { { ResourceName: resourceName, ImportState: true, - ImportStateIdFunc: acctest.AttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateIdFunc: testAccTableBucketImportStateIdFunc(resourceName), ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: names.AttrARN, ImportStateVerifyIgnore: []string{names.AttrForceDestroy}, @@ -413,6 +414,10 @@ func testAccCheckTableBucketExists(ctx context.Context, n string, v *s3tables.Ge } } +func testAccTableBucketImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return acctest.AttrImportStateIdFunc(resourceName, names.AttrARN) +} + func testAccTableBucketConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_s3tables_table_bucket" "test" { diff --git a/internal/service/s3tables/table_tags_gen_test.go b/internal/service/s3tables/table_tags_gen_test.go new file mode 100644 index 000000000000..1e657e6c6f61 --- /dev/null +++ b/internal/service/s3tables/table_tags_gen_test.go @@ -0,0 +1,2404 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package s3tables_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/s3tables" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccS3TablesTable_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + ImportStateVerifyIgnore: []string{ + "tags.resourcekey1", // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey(acctest.CtKey1)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccTableImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccS3TablesTable_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v s3tables.GetTableOutput + resourceName := "aws_s3tables_table.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.S3TablesServiceID), + CheckDestroy: testAccCheckTableDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/Table/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckTableExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/s3tables/table_test.go b/internal/service/s3tables/table_test.go index 77539b6fbde3..8186ca88463a 100644 --- a/internal/service/s3tables/table_test.go +++ b/internal/service/s3tables/table_test.go @@ -32,11 +32,11 @@ import ( func TestAccS3TablesTable_basic(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") resourceName := "aws_s3tables_table.test" resource.ParallelTest(t, resource.TestCase{ @@ -49,7 +49,7 @@ func TestAccS3TablesTable_basic(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_basic(rName, namespace, bucketName), + Config: testAccTableConfig_basic(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "s3tables", regexache.MustCompile("bucket/"+bucketName+"/table/"+verify.UUIDRegexPattern+"$")), @@ -59,7 +59,7 @@ func TestAccS3TablesTable_basic(t *testing.T) { resource.TestCheckNoResourceAttr(resourceName, "metadata_location"), resource.TestCheckResourceAttrPair(resourceName, "modified_at", resourceName, names.AttrCreatedAt), resource.TestCheckNoResourceAttr(resourceName, "modified_by"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, tableName), resource.TestCheckResourceAttrPair(resourceName, names.AttrNamespace, "aws_s3tables_namespace.test", names.AttrNamespace), acctest.CheckResourceAttrAccountID(ctx, resourceName, names.AttrOwnerAccountID), resource.TestCheckResourceAttrPair(resourceName, "table_bucket_arn", "aws_s3tables_table_bucket.test", names.AttrARN), @@ -89,6 +89,7 @@ func TestAccS3TablesTable_basic(t *testing.T) { names.AttrStatus: tfknownvalue.StringExact(awstypes.MaintenanceStatusEnabled), }), })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), }, }, { @@ -104,11 +105,11 @@ func TestAccS3TablesTable_basic(t *testing.T) { func TestAccS3TablesTable_disappears(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") resourceName := "aws_s3tables_table.test" resource.ParallelTest(t, resource.TestCase{ @@ -121,7 +122,7 @@ func TestAccS3TablesTable_disappears(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_basic(rName, namespace, bucketName), + Config: testAccTableConfig_basic(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfs3tables.ResourceTable, resourceName), @@ -139,12 +140,13 @@ func TestAccS3TablesTable_disappears(t *testing.T) { func TestAccS3TablesTable_rename(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rNameUpdated := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + tableNameUpdated := strings.ReplaceAll(rNameUpdated, "-", "_") resourceName := "aws_s3tables_table.test" createdAtNoChange := statecheck.CompareValue(compare.ValuesSame()) @@ -164,10 +166,10 @@ func TestAccS3TablesTable_rename(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_basic(rName, namespace, bucketName), + Config: testAccTableConfig_basic(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, tableName), ), ConfigStateChecks: []statecheck.StateCheck{ createdAtNoChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrCreatedAt)), @@ -179,17 +181,17 @@ func TestAccS3TablesTable_rename(t *testing.T) { }, }, { - Config: testAccTableConfig_basic(rNameUpdated, namespace, bucketName), + Config: testAccTableConfig_basic(tableNameUpdated, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), + resource.TestCheckResourceAttr(resourceName, names.AttrName, tableNameUpdated), resource.TestCheckResourceAttrSet(resourceName, "modified_at"), acctest.CheckResourceAttrAccountID(ctx, resourceName, "modified_by"), ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rNameUpdated)), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(tableNameUpdated)), }, PostApplyPreRefresh: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -220,12 +222,13 @@ func TestAccS3TablesTable_rename(t *testing.T) { func TestAccS3TablesTable_updateNamespace(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - namespaceUpdated := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + nsNameUpdated := strings.ReplaceAll(rNameUpdated, "-", "_") resourceName := "aws_s3tables_table.test" createdAtNoChange := statecheck.CompareValue(compare.ValuesSame()) @@ -245,10 +248,10 @@ func TestAccS3TablesTable_updateNamespace(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_basic(rName, namespace, bucketName), + Config: testAccTableConfig_basic(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), - resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, namespace), + resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, nsName), ), ConfigStateChecks: []statecheck.StateCheck{ createdAtNoChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrCreatedAt)), @@ -260,17 +263,17 @@ func TestAccS3TablesTable_updateNamespace(t *testing.T) { }, }, { - Config: testAccTableConfig_basic(rName, namespaceUpdated, bucketName), + Config: testAccTableConfig_basic(tableName, nsNameUpdated, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), - resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, namespaceUpdated), + resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, nsNameUpdated), resource.TestCheckResourceAttrSet(resourceName, "modified_at"), acctest.CheckResourceAttrAccountID(ctx, resourceName, "modified_by"), ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrNamespace), knownvalue.StringExact(namespaceUpdated)), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrNamespace), knownvalue.StringExact(nsNameUpdated)), }, PostApplyPreRefresh: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -301,13 +304,14 @@ func TestAccS3TablesTable_updateNamespace(t *testing.T) { func TestAccS3TablesTable_updateNameAndNamespace(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - namespaceUpdated := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rNameUpdated := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + nsNameUpdated := strings.ReplaceAll(rNameUpdated, "-", "_") + tableNameUpdated := strings.ReplaceAll(rNameUpdated, "-", "_") resourceName := "aws_s3tables_table.test" createdAtNoChange := statecheck.CompareValue(compare.ValuesSame()) @@ -327,11 +331,11 @@ func TestAccS3TablesTable_updateNameAndNamespace(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_basic(rName, namespace, bucketName), + Config: testAccTableConfig_basic(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, namespace), + resource.TestCheckResourceAttr(resourceName, names.AttrName, tableName), + resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, nsName), ), ConfigStateChecks: []statecheck.StateCheck{ createdAtNoChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrCreatedAt)), @@ -343,19 +347,19 @@ func TestAccS3TablesTable_updateNameAndNamespace(t *testing.T) { }, }, { - Config: testAccTableConfig_basic(rNameUpdated, namespaceUpdated, bucketName), + Config: testAccTableConfig_basic(tableNameUpdated, nsNameUpdated, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), - resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, namespaceUpdated), + resource.TestCheckResourceAttr(resourceName, names.AttrName, tableNameUpdated), + resource.TestCheckResourceAttr(resourceName, names.AttrNamespace, nsNameUpdated), resource.TestCheckResourceAttrSet(resourceName, "modified_at"), acctest.CheckResourceAttrAccountID(ctx, resourceName, "modified_by"), ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rNameUpdated)), - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrNamespace), knownvalue.StringExact(namespaceUpdated)), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(tableNameUpdated)), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrNamespace), knownvalue.StringExact(nsNameUpdated)), }, PostApplyPreRefresh: []plancheck.PlanCheck{ plancheck.ExpectEmptyPlan(), @@ -386,11 +390,11 @@ func TestAccS3TablesTable_updateNameAndNamespace(t *testing.T) { func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") resourceName := "aws_s3tables_table.test" resource.ParallelTest(t, resource.TestCase{ @@ -403,7 +407,7 @@ func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_maintenanceConfiguration(rName, namespace, bucketName, 64, 24, 2), + Config: testAccTableConfig_maintenanceConfiguration(tableName, nsName, bucketName, 64, 24, 2), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), ), @@ -433,7 +437,7 @@ func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccTableConfig_maintenanceConfiguration(rName, namespace, bucketName, 128, 48, 1), + Config: testAccTableConfig_maintenanceConfiguration(tableName, nsName, bucketName, 128, 48, 1), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), ), @@ -468,11 +472,11 @@ func TestAccS3TablesTable_maintenanceConfiguration(t *testing.T) { func TestAccS3TablesTable_encryptionConfiguration(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") resourceName := "aws_s3tables_table.test" resource.ParallelTest(t, resource.TestCase{ @@ -485,7 +489,7 @@ func TestAccS3TablesTable_encryptionConfiguration(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_encryptionConfiguration(rName, namespace, bucketName), + Config: testAccTableConfig_encryptionConfiguration(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "s3tables", regexache.MustCompile("bucket/"+bucketName+"/table/"+verify.UUIDRegexPattern+"$")), @@ -495,7 +499,7 @@ func TestAccS3TablesTable_encryptionConfiguration(t *testing.T) { resource.TestCheckNoResourceAttr(resourceName, "metadata_location"), resource.TestCheckResourceAttrPair(resourceName, "modified_at", resourceName, names.AttrCreatedAt), resource.TestCheckNoResourceAttr(resourceName, "modified_by"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, tableName), resource.TestCheckResourceAttrPair(resourceName, names.AttrNamespace, "aws_s3tables_namespace.test", names.AttrNamespace), acctest.CheckResourceAttrAccountID(ctx, resourceName, names.AttrOwnerAccountID), resource.TestCheckResourceAttrPair(resourceName, "table_bucket_arn", "aws_s3tables_table_bucket.test", names.AttrARN), @@ -542,11 +546,11 @@ func TestAccS3TablesTable_encryptionConfiguration(t *testing.T) { func TestAccS3TablesTable_metadata(t *testing.T) { ctx := acctest.Context(t) - var table s3tables.GetTableOutput - bucketName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - namespace := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") - rName := strings.ReplaceAll(sdkacctest.RandomWithPrefix(acctest.ResourcePrefix), "-", "_") + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + bucketName := rName + nsName := strings.ReplaceAll(rName, "-", "_") + tableName := strings.ReplaceAll(rName, "-", "_") resourceName := "aws_s3tables_table.test" resource.ParallelTest(t, resource.TestCase{ @@ -559,7 +563,7 @@ func TestAccS3TablesTable_metadata(t *testing.T) { CheckDestroy: testAccCheckTableDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccTableConfig_metadata(rName, namespace, bucketName), + Config: testAccTableConfig_metadata(tableName, nsName, bucketName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckTableExists(ctx, resourceName, &table), resource.TestCheckResourceAttr(resourceName, "metadata.0.iceberg.0.schema.0.field.#", "3"), @@ -658,17 +662,10 @@ func testAccTableImportStateIdFunc(resourceName string) resource.ImportStateIdFu } } -func testAccTableConfig_basic(rName, namespace, bucketName string) string { +func testAccTableConfig_base(nsName, bucketName string) string { return fmt.Sprintf(` -resource "aws_s3tables_table" "test" { - name = %[1]q - namespace = aws_s3tables_namespace.test.namespace - table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn - format = "ICEBERG" -} - resource "aws_s3tables_namespace" "test" { - namespace = %[2]q + namespace = %[1]q table_bucket_arn = aws_s3tables_table_bucket.test.arn lifecycle { @@ -677,13 +674,24 @@ resource "aws_s3tables_namespace" "test" { } resource "aws_s3tables_table_bucket" "test" { - name = %[3]q + name = %[2]q } -`, rName, namespace, bucketName) +`, nsName, bucketName) } -func testAccTableConfig_maintenanceConfiguration(rName, namespace, bucketName string, targetSize, maxSnapshotAge, minSnapshots int32) string { - return fmt.Sprintf(` +func testAccTableConfig_basic(tableName, nsName, bucketName string) string { + return acctest.ConfigCompose(testAccTableConfig_base(nsName, bucketName), fmt.Sprintf(` +resource "aws_s3tables_table" "test" { + name = %[1]q + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" +} +`, tableName)) +} + +func testAccTableConfig_maintenanceConfiguration(tableName, nsName, bucketName string, targetSize, maxSnapshotAge, minSnapshots int32) string { + return acctest.ConfigCompose(testAccTableConfig_base(nsName, bucketName), fmt.Sprintf(` resource "aws_s3tables_table" "test" { name = %[1]q namespace = aws_s3tables_namespace.test.namespace @@ -693,36 +701,23 @@ resource "aws_s3tables_table" "test" { maintenance_configuration = { iceberg_compaction = { settings = { - target_file_size_mb = %[4]d + target_file_size_mb = %[2]d } status = "enabled" } iceberg_snapshot_management = { settings = { - max_snapshot_age_hours = %[5]d - min_snapshots_to_keep = %[6]d + max_snapshot_age_hours = %[3]d + min_snapshots_to_keep = %[4]d } status = "enabled" } } } - -resource "aws_s3tables_namespace" "test" { - namespace = %[2]q - table_bucket_arn = aws_s3tables_table_bucket.test.arn - - lifecycle { - create_before_destroy = true - } -} - -resource "aws_s3tables_table_bucket" "test" { - name = %[3]q -} -`, rName, namespace, bucketName, targetSize, maxSnapshotAge, minSnapshots) +`, tableName, targetSize, maxSnapshotAge, minSnapshots)) } -func testAccTableConfig_encryptionConfiguration(rName, namespace, bucketName string) string { +func testAccTableConfig_encryptionConfiguration(tableName, nsName, bucketName string) string { return fmt.Sprintf(` resource "aws_s3tables_table" "test" { name = %[1]q @@ -794,13 +789,11 @@ data "aws_iam_policy_document" "key_policy" { resource "aws_kms_key" "test2" { deletion_window_in_days = 7 } - - -`, rName, namespace, bucketName) +`, tableName, nsName, bucketName) } -func testAccTableConfig_metadata(rName, namespace, bucketName string) string { - return fmt.Sprintf(` +func testAccTableConfig_metadata(tableName, nsName, bucketName string) string { + return acctest.ConfigCompose(testAccTableConfig_base(nsName, bucketName), fmt.Sprintf(` resource "aws_s3tables_table" "test" { name = %[1]q namespace = aws_s3tables_namespace.test.namespace @@ -828,18 +821,5 @@ resource "aws_s3tables_table" "test" { } } } - -resource "aws_s3tables_namespace" "test" { - namespace = %[2]q - table_bucket_arn = aws_s3tables_table_bucket.test.arn - - lifecycle { - create_before_destroy = true - } -} - -resource "aws_s3tables_table_bucket" "test" { - name = %[3]q -} -`, rName, namespace, bucketName) +`, tableName)) } diff --git a/internal/service/s3tables/tags_gen.go b/internal/service/s3tables/tags_gen.go new file mode 100644 index 000000000000..9c2769aea79b --- /dev/null +++ b/internal/service/s3tables/tags_gen.go @@ -0,0 +1,128 @@ +// Code generated by internal/generate/tags/main.go; DO NOT EDIT. +package s3tables + +import ( + "context" + + "github.com/YakDriver/smarterr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/s3tables" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/logging" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/types/option" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// listTags lists s3tables service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func listTags(ctx context.Context, conn *s3tables.Client, identifier string, optFns ...func(*s3tables.Options)) (tftags.KeyValueTags, error) { + input := s3tables.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(ctx, &input, optFns...) + + if err != nil { + return tftags.New(ctx, nil), smarterr.NewError(err) + } + + return keyValueTags(ctx, output.Tags), nil +} + +// ListTags lists s3tables service tags and set them in Context. +// It is called from outside this package. +func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { + tags, err := listTags(ctx, meta.(*conns.AWSClient).S3TablesClient(ctx), identifier) + + if err != nil { + return smarterr.NewError(err) + } + + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(tags) + } + + return nil +} + +// map[string]string handling + +// svcTags returns s3tables service tags. +func svcTags(tags tftags.KeyValueTags) map[string]string { + return tags.Map() +} + +// keyValueTags creates tftags.KeyValueTags from s3tables service tags. +func keyValueTags(ctx context.Context, tags map[string]string) tftags.KeyValueTags { + return tftags.New(ctx, tags) +} + +// getTagsIn returns s3tables service tags from Context. +// nil is returned if there are no input tags. +func getTagsIn(ctx context.Context) map[string]string { + if inContext, ok := tftags.FromContext(ctx); ok { + if tags := svcTags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { + return tags + } + } + + return nil +} + +// setTagsOut sets s3tables service tags in Context. +func setTagsOut(ctx context.Context, tags map[string]string) { + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(keyValueTags(ctx, tags)) + } +} + +// updateTags updates s3tables service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func updateTags(ctx context.Context, conn *s3tables.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*s3tables.Options)) error { + oldTags := tftags.New(ctx, oldTagsMap) + newTags := tftags.New(ctx, newTagsMap) + + ctx = tflog.SetField(ctx, logging.KeyResourceId, identifier) + + removedTags := oldTags.Removed(newTags) + removedTags = removedTags.IgnoreSystem(names.S3Tables) + if len(removedTags) > 0 { + input := s3tables.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: removedTags.Keys(), + } + + _, err := conn.UntagResource(ctx, &input, optFns...) + + if err != nil { + return smarterr.NewError(err) + } + } + + updatedTags := oldTags.Updated(newTags) + updatedTags = updatedTags.IgnoreSystem(names.S3Tables) + if len(updatedTags) > 0 { + input := s3tables.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: svcTags(updatedTags), + } + + _, err := conn.TagResource(ctx, &input, optFns...) + + if err != nil { + return smarterr.NewError(err) + } + } + + return nil +} + +// UpdateTags updates s3tables service tags. +// It is called from outside this package. +func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { + return updateTags(ctx, meta.(*conns.AWSClient).S3TablesClient(ctx), identifier, oldTags, newTags) +} diff --git a/internal/service/s3tables/tags_gen_test.go b/internal/service/s3tables/tags_gen_test.go new file mode 100644 index 000000000000..8216dd0d9a9a --- /dev/null +++ b/internal/service/s3tables/tags_gen_test.go @@ -0,0 +1,16 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package s3tables_test + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" + tfs3tables "github.com/hashicorp/terraform-provider-aws/internal/service/s3tables" +) + +func expectFullResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { + return tfstatecheck.ExpectFullResourceTags(tfs3tables.ServicePackage(ctx), resourceAddress, knownValue) +} diff --git a/internal/service/s3tables/testdata/Table/tags/main_gen.tf b/internal/service/s3tables/testdata/Table/tags/main_gen.tf new file mode 100644 index 000000000000..e17b941ede7e --- /dev/null +++ b/internal/service/s3tables/testdata/Table/tags/main_gen.tf @@ -0,0 +1,36 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table" "test" { + name = replace(var.rName, "-", "_") + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" + + tags = var.resource_tags +} + +resource "aws_s3tables_namespace" "test" { + namespace = replace(var.rName, "-", "_") + table_bucket_arn = aws_s3tables_table_bucket.test.arn + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/s3tables/testdata/Table/tagsComputed1/main_gen.tf b/internal/service/s3tables/testdata/Table/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..9a80f7511c68 --- /dev/null +++ b/internal/service/s3tables/testdata/Table/tagsComputed1/main_gen.tf @@ -0,0 +1,40 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_s3tables_table" "test" { + name = replace(var.rName, "-", "_") + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "aws_s3tables_namespace" "test" { + namespace = replace(var.rName, "-", "_") + table_bucket_arn = aws_s3tables_table_bucket.test.arn + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/Table/tagsComputed2/main_gen.tf b/internal/service/s3tables/testdata/Table/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..9cbdb86d67e8 --- /dev/null +++ b/internal/service/s3tables/testdata/Table/tagsComputed2/main_gen.tf @@ -0,0 +1,51 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_s3tables_table" "test" { + name = replace(var.rName, "-", "_") + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "aws_s3tables_namespace" "test" { + namespace = replace(var.rName, "-", "_") + table_bucket_arn = aws_s3tables_table_bucket.test.arn + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/Table/tags_defaults/main_gen.tf b/internal/service/s3tables/testdata/Table/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..268cbec1e126 --- /dev/null +++ b/internal/service/s3tables/testdata/Table/tags_defaults/main_gen.tf @@ -0,0 +1,47 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_s3tables_table" "test" { + name = replace(var.rName, "-", "_") + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" + + tags = var.resource_tags +} + +resource "aws_s3tables_namespace" "test" { + namespace = replace(var.rName, "-", "_") + table_bucket_arn = aws_s3tables_table_bucket.test.arn + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/s3tables/testdata/Table/tags_ignore/main_gen.tf b/internal/service/s3tables/testdata/Table/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..650b9c1e09f4 --- /dev/null +++ b/internal/service/s3tables/testdata/Table/tags_ignore/main_gen.tf @@ -0,0 +1,56 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_s3tables_table" "test" { + name = replace(var.rName, "-", "_") + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" + + tags = var.resource_tags +} + +resource "aws_s3tables_namespace" "test" { + namespace = replace(var.rName, "-", "_") + table_bucket_arn = aws_s3tables_table_bucket.test.arn + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucket/basic/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/basic/main_gen.tf new file mode 100644 index 000000000000..cfa6e00a9352 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/basic/main_gen.tf @@ -0,0 +1,12 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucket/basic_v6.19.0/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/basic_v6.19.0/main_gen.tf new file mode 100644 index 000000000000..4d7b2a59010d --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/basic_v6.19.0/main_gen.tf @@ -0,0 +1,22 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.19.0" + } + } +} + +provider "aws" {} diff --git a/internal/service/s3tables/testdata/TableBucket/region_override/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/region_override/main_gen.tf new file mode 100644 index 000000000000..331fa152c128 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/region_override/main_gen.tf @@ -0,0 +1,20 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket" "test" { + region = var.region + + name = var.rName +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "region" { + description = "Region to deploy resource in" + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucket/tags/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/tags/main_gen.tf new file mode 100644 index 000000000000..8eddc2261308 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/tags/main_gen.tf @@ -0,0 +1,21 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/s3tables/testdata/TableBucket/tagsComputed1/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..8fa095bfc73f --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/tagsComputed1/main_gen.tf @@ -0,0 +1,25 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucket/tagsComputed2/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..db7013a56b02 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/tagsComputed2/main_gen.tf @@ -0,0 +1,36 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucket/tags_defaults/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..0828c43edf53 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/tags_defaults/main_gen.tf @@ -0,0 +1,32 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucket/tags_ignore/main_gen.tf b/internal/service/s3tables/testdata/TableBucket/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..892a536aa7c7 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucket/tags_ignore/main_gen.tf @@ -0,0 +1,41 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucketPolicy/basic/main_gen.tf b/internal/service/s3tables/testdata/TableBucketPolicy/basic/main_gen.tf new file mode 100644 index 000000000000..cd7c6617997b --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucketPolicy/basic/main_gen.tf @@ -0,0 +1,30 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket_policy" "test" { + resource_policy = data.aws_iam_policy_document.test.json + table_bucket_arn = aws_s3tables_table_bucket.test.arn +} + +data "aws_iam_policy_document" "test" { + statement { + actions = ["s3tables:*"] + principals { + type = "AWS" + identifiers = [data.aws_caller_identity.current.account_id] + } + resources = ["${aws_s3tables_table_bucket.test.arn}/*"] + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} + +data "aws_caller_identity" "current" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/TableBucketPolicy/basic_v6.19.0/main_gen.tf b/internal/service/s3tables/testdata/TableBucketPolicy/basic_v6.19.0/main_gen.tf new file mode 100644 index 000000000000..7186ba59cbbc --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucketPolicy/basic_v6.19.0/main_gen.tf @@ -0,0 +1,40 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket_policy" "test" { + resource_policy = data.aws_iam_policy_document.test.json + table_bucket_arn = aws_s3tables_table_bucket.test.arn +} + +data "aws_iam_policy_document" "test" { + statement { + actions = ["s3tables:*"] + principals { + type = "AWS" + identifiers = [data.aws_caller_identity.current.account_id] + } + resources = ["${aws_s3tables_table_bucket.test.arn}/*"] + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} + +data "aws_caller_identity" "current" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "6.19.0" + } + } +} + +provider "aws" {} diff --git a/internal/service/s3tables/testdata/TableBucketPolicy/region_override/main_gen.tf b/internal/service/s3tables/testdata/TableBucketPolicy/region_override/main_gen.tf new file mode 100644 index 000000000000..5c0018122674 --- /dev/null +++ b/internal/service/s3tables/testdata/TableBucketPolicy/region_override/main_gen.tf @@ -0,0 +1,40 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_s3tables_table_bucket_policy" "test" { + region = var.region + + resource_policy = data.aws_iam_policy_document.test.json + table_bucket_arn = aws_s3tables_table_bucket.test.arn +} + +data "aws_iam_policy_document" "test" { + statement { + actions = ["s3tables:*"] + principals { + type = "AWS" + identifiers = [data.aws_caller_identity.current.account_id] + } + resources = ["${aws_s3tables_table_bucket.test.arn}/*"] + } +} + +resource "aws_s3tables_table_bucket" "test" { + region = var.region + + name = var.rName +} + +data "aws_caller_identity" "current" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "region" { + description = "Region to deploy resource in" + type = string + nullable = false +} diff --git a/internal/service/s3tables/testdata/tmpl/table_bucket_basic.gtpl b/internal/service/s3tables/testdata/tmpl/table_bucket_basic.gtpl new file mode 100644 index 000000000000..4fbb6811ec4c --- /dev/null +++ b/internal/service/s3tables/testdata/tmpl/table_bucket_basic.gtpl @@ -0,0 +1,4 @@ +resource "aws_s3tables_table_bucket" "test" { +{{- template "region" }} + name = var.rName +} diff --git a/internal/service/s3tables/testdata/tmpl/table_bucket_policy_basic.gtpl b/internal/service/s3tables/testdata/tmpl/table_bucket_policy_basic.gtpl new file mode 100644 index 000000000000..f1e527d1575f --- /dev/null +++ b/internal/service/s3tables/testdata/tmpl/table_bucket_policy_basic.gtpl @@ -0,0 +1,23 @@ +resource "aws_s3tables_table_bucket_policy" "test" { +{{- template "region" }} + resource_policy = data.aws_iam_policy_document.test.json + table_bucket_arn = aws_s3tables_table_bucket.test.arn +} + +data "aws_iam_policy_document" "test" { + statement { + actions = ["s3tables:*"] + principals { + type = "AWS" + identifiers = [data.aws_caller_identity.current.account_id] + } + resources = ["${aws_s3tables_table_bucket.test.arn}/*"] + } +} + +resource "aws_s3tables_table_bucket" "test" { +{{- template "region" }} + name = var.rName +} + +data "aws_caller_identity" "current" {} diff --git a/internal/service/s3tables/testdata/tmpl/table_bucket_tags.gtpl b/internal/service/s3tables/testdata/tmpl/table_bucket_tags.gtpl new file mode 100644 index 000000000000..69bd966bb33e --- /dev/null +++ b/internal/service/s3tables/testdata/tmpl/table_bucket_tags.gtpl @@ -0,0 +1,6 @@ +resource "aws_s3tables_table_bucket" "test" { +{{- template "region" }} + name = var.rName + +{{- template "tags" . }} +} diff --git a/internal/service/s3tables/testdata/tmpl/table_tags.gtpl b/internal/service/s3tables/testdata/tmpl/table_tags.gtpl new file mode 100644 index 000000000000..1dadd878e9a3 --- /dev/null +++ b/internal/service/s3tables/testdata/tmpl/table_tags.gtpl @@ -0,0 +1,22 @@ +resource "aws_s3tables_table" "test" { +{{- template "region" }} + name = replace(var.rName, "-", "_") + namespace = aws_s3tables_namespace.test.namespace + table_bucket_arn = aws_s3tables_namespace.test.table_bucket_arn + format = "ICEBERG" + +{{- template "tags" . }} +} + +resource "aws_s3tables_namespace" "test" { + namespace = replace(var.rName, "-", "_") + table_bucket_arn = aws_s3tables_table_bucket.test.arn + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_s3tables_table_bucket" "test" { + name = var.rName +} \ No newline at end of file diff --git a/internal/service/sagemaker/endpoint.go b/internal/service/sagemaker/endpoint.go index 913514279e1a..4b01978ad04a 100644 --- a/internal/service/sagemaker/endpoint.go +++ b/internal/service/sagemaker/endpoint.go @@ -302,9 +302,11 @@ func resourceEndpointUpdate(ctx context.Context, d *schema.ResourceData, meta an conn := meta.(*conns.AWSClient).SageMakerClient(ctx) if d.HasChanges("endpoint_config_name", "deployment_config") { + _, n := d.GetChange("endpoint_config_name") + input := &sagemaker.UpdateEndpointInput{ EndpointName: aws.String(d.Id()), - EndpointConfigName: aws.String(d.Get("endpoint_config_name").(string)), + EndpointConfigName: aws.String(n.(string)), } if v, ok := d.GetOk("deployment_config"); ok && (len(v.([]any)) > 0) { diff --git a/internal/service/sagemaker/endpoint_configuration.go b/internal/service/sagemaker/endpoint_configuration.go index c64f2ad67fc0..193aa6c83dec 100644 --- a/internal/service/sagemaker/endpoint_configuration.go +++ b/internal/service/sagemaker/endpoint_configuration.go @@ -6,6 +6,7 @@ package sagemaker import ( "context" "log" + "strings" "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" @@ -251,6 +252,12 @@ func resourceEndpointConfiguration() *schema.Resource { ConflictsWith: []string{names.AttrName}, ValidateFunc: validPrefix, }, + names.AttrExecutionRoleARN: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, "production_variants": { Type: schema.TypeList, Required: true, @@ -318,6 +325,19 @@ func resourceEndpointConfiguration() *schema.Resource { ForceNew: true, ValidateFunc: validation.FloatAtLeast(0), Default: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // Suppress diff when model_name is empty (Inference Components) + // AWS returns nil but schema has default of 1 (there for backwards compatibility) + if strings.Contains(k, "production_variants") || strings.Contains(k, "shadow_production_variants") { + parts := strings.Split(k, ".") + if len(parts) >= 2 { + prefix := strings.Join(parts[:len(parts)-1], ".") + modelName := d.Get(prefix + ".model_name").(string) + return modelName == "" + } + } + return false + }, }, names.AttrInstanceType: { Type: schema.TypeString, @@ -333,7 +353,7 @@ func resourceEndpointConfiguration() *schema.Resource { }, "model_name": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, }, "routing_config": { @@ -490,6 +510,19 @@ func resourceEndpointConfiguration() *schema.Resource { ForceNew: true, ValidateFunc: validation.FloatAtLeast(0), Default: 1, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // Suppress diff when model_name is empty (Inference Components) + // AWS returns nil but schema has default of 1 (there for backwards compatibility) + if strings.Contains(k, "production_variants") || strings.Contains(k, "shadow_production_variants") { + parts := strings.Split(k, ".") + if len(parts) >= 2 { + prefix := strings.Join(parts[:len(parts)-1], ".") + modelName := d.Get(prefix + ".model_name").(string) + return modelName == "" + } + } + return false + }, }, names.AttrInstanceType: { Type: schema.TypeString, @@ -505,7 +538,7 @@ func resourceEndpointConfiguration() *schema.Resource { }, "model_name": { Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: true, }, "routing_config": { @@ -679,6 +712,10 @@ func resourceEndpointConfigurationCreate(ctx context.Context, d *schema.Resource Tags: getTagsIn(ctx), } + if v, ok := d.GetOk(names.AttrExecutionRoleARN); ok { + createOpts.ExecutionRoleArn = aws.String(v.(string)) + } + if v, ok := d.GetOk(names.AttrKMSKeyARN); ok { createOpts.KmsKeyId = aws.String(v.(string)) } @@ -724,6 +761,7 @@ func resourceEndpointConfigurationRead(ctx context.Context, d *schema.ResourceDa d.Set(names.AttrARN, endpointConfig.EndpointConfigArn) d.Set(names.AttrName, endpointConfig.EndpointConfigName) d.Set(names.AttrNamePrefix, create.NamePrefixFromName(aws.ToString(endpointConfig.EndpointConfigName))) + d.Set(names.AttrExecutionRoleARN, endpointConfig.ExecutionRoleArn) d.Set(names.AttrKMSKeyARN, endpointConfig.KmsKeyId) if err := d.Set("production_variants", flattenProductionVariants(endpointConfig.ProductionVariants)); err != nil { @@ -806,8 +844,25 @@ func expandProductionVariants(configured []any) []awstypes.ProductionVariant { for _, lRaw := range configured { data := lRaw.(map[string]any) - l := awstypes.ProductionVariant{ - ModelName: aws.String(data["model_name"].(string)), + l := awstypes.ProductionVariant{} + + // Traditional endpoint: set ModelName + // IC endpoint: omit ModelName + // Special traditional/IC handling + if v, ok := data["model_name"].(string); ok && v != "" { + l.ModelName = aws.String(v) + + // Traditional endpoint: set InitialVariantWeight + // IC endpoint: must not be set but pre-existing default value of 1 + if v, ok := data["initial_variant_weight"].(float64); ok { + l.InitialVariantWeight = aws.Float32(float32(v)) + } + + // Traditional endpoint: set EnableSSMAccess + // IC endpoints: must not be set + if v, ok := data["enable_ssm_access"].(bool); ok { + l.EnableSSMAccess = aws.Bool(v) + } } if v, ok := data["initial_instance_count"].(int); ok && v > 0 { @@ -836,10 +891,6 @@ func expandProductionVariants(configured []any) []awstypes.ProductionVariant { l.VariantName = aws.String(id.UniqueId()) } - if v, ok := data["initial_variant_weight"].(float64); ok { - l.InitialVariantWeight = aws.Float32(float32(v)) - } - if v, ok := data["accelerator_type"].(string); ok && v != "" { l.AcceleratorType = awstypes.ProductionVariantAcceleratorType(v) } @@ -856,10 +907,6 @@ func expandProductionVariants(configured []any) []awstypes.ProductionVariant { l.CoreDumpConfig = expandCoreDumpConfig(v) } - if v, ok := data["enable_ssm_access"].(bool); ok { - l.EnableSSMAccess = aws.Bool(v) - } - if v, ok := data["managed_instance_scaling"].([]any); ok && len(v) > 0 { l.ManagedInstanceScaling = expandManagedInstanceScaling(v) } @@ -879,12 +926,25 @@ func flattenProductionVariants(list []awstypes.ProductionVariant) []map[string]a for _, i := range list { l := map[string]any{ - "accelerator_type": i.AcceleratorType, - names.AttrInstanceType: i.InstanceType, - "inference_ami_version": i.InferenceAmiVersion, - "initial_variant_weight": aws.ToFloat32(i.InitialVariantWeight), - "model_name": aws.ToString(i.ModelName), - "variant_name": aws.ToString(i.VariantName), + "accelerator_type": i.AcceleratorType, + names.AttrInstanceType: i.InstanceType, + "inference_ami_version": i.InferenceAmiVersion, + "variant_name": aws.ToString(i.VariantName), + } + + // Traditional endpoints have model_name set + // Inference Component endpoints do not have model_name set + // Special handling + if i.ModelName != nil && aws.ToString(i.ModelName) != "" { + l["model_name"] = aws.ToString(i.ModelName) + + if i.InitialVariantWeight != nil { + l["initial_variant_weight"] = aws.ToFloat32(i.InitialVariantWeight) + } + + if i.EnableSSMAccess != nil { + l["enable_ssm_access"] = aws.ToBool(i.EnableSSMAccess) + } } if i.InitialInstanceCount != nil { @@ -915,10 +975,6 @@ func flattenProductionVariants(list []awstypes.ProductionVariant) []map[string]a l["core_dump_config"] = flattenCoreDumpConfig(i.CoreDumpConfig) } - if i.EnableSSMAccess != nil { - l["enable_ssm_access"] = aws.ToBool(i.EnableSSMAccess) - } - if i.ManagedInstanceScaling != nil { l["managed_instance_scaling"] = flattenManagedInstanceScaling(i.ManagedInstanceScaling) } diff --git a/internal/service/sagemaker/endpoint_configuration_test.go b/internal/service/sagemaker/endpoint_configuration_test.go index 753f82681527..ad4c67e22847 100644 --- a/internal/service/sagemaker/endpoint_configuration_test.go +++ b/internal/service/sagemaker/endpoint_configuration_test.go @@ -63,6 +63,38 @@ func TestAccSageMakerEndpointConfiguration_basic(t *testing.T) { }) } +func TestAccSageMakerEndpointConfiguration_ProductionVariants_optionalModelName(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sagemaker_endpoint_configuration.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.SageMakerServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEndpointConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccEndpointConfigurationConfig_ProductionVariants_optionalModelName(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEndpointConfigurationExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "production_variants.#", "1"), + resource.TestCheckResourceAttr(resourceName, "production_variants.0.variant_name", "variant-1"), + resource.TestCheckResourceAttr(resourceName, "production_variants.0.model_name", ""), + resource.TestCheckResourceAttr(resourceName, "production_variants.0.initial_instance_count", "1"), + resource.TestCheckResourceAttr(resourceName, "production_variants.0.instance_type", "ml.g5.xlarge"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccSageMakerEndpointConfiguration_nameGenerated(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -912,7 +944,7 @@ func TestAccSageMakerEndpointConfiguration_upgradeToEnableSSMAccess(t *testing.T }) } -func TestAccSageMakerEndpointConfiguration_productionVariantsManagedInstanceScaling(t *testing.T) { +func TestAccSageMakerEndpointConfiguration_ProductionVariants_managedInstanceScaling(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sagemaker_endpoint_configuration.test" @@ -947,7 +979,7 @@ func TestAccSageMakerEndpointConfiguration_productionVariantsManagedInstanceScal }) } -func TestAccSageMakerEndpointConfiguration_productionVariantsManagedInstanceScalingZero(t *testing.T) { +func TestAccSageMakerEndpointConfiguration_ProductionVariants_managedInstanceScalingZero(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_sagemaker_endpoint_configuration.test" @@ -1903,3 +1935,43 @@ resource "aws_sagemaker_endpoint_configuration" "test" { } `, rName, min)) } + +func testAccEndpointConfigurationConfig_ProductionVariants_optionalModelName(rName string) string { + return fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "sagemaker.amazonaws.com" + } + }, + ] + }) +} + +resource "aws_iam_role_policy_attachment" "test" { + role = aws_iam_role.test.name + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonSageMakerFullAccess" +} + +resource "aws_sagemaker_endpoint_configuration" "test" { + name = %[1]q + execution_role_arn = aws_iam_role.test.arn + + production_variants { + variant_name = "variant-1" + initial_instance_count = 1 + instance_type = "ml.g5.xlarge" + } + + depends_on = [aws_iam_role_policy_attachment.test] +} +`, rName) +} diff --git a/internal/service/sagemaker/model.go b/internal/service/sagemaker/model.go index 6ae9810e152f..2978f094f513 100644 --- a/internal/service/sagemaker/model.go +++ b/internal/service/sagemaker/model.go @@ -129,11 +129,25 @@ func resourceModel() *schema.Resource { Required: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "s3_uri": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validModelDataURL, + "compression_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.ModelCompressionType](), + }, + "model_access_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "accept_eula": { + Type: schema.TypeBool, + Required: true, + ForceNew: true, + }, + }, + }, }, "s3_data_type": { Type: schema.TypeString, @@ -141,6 +155,34 @@ func resourceModel() *schema.Resource { ForceNew: true, ValidateDiagFunc: enum.Validate[awstypes.S3ModelDataType](), }, + "s3_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validModelDataURL, + }, + }, + }, + }, + }, + }, + }, + "additional_model_data_source": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "s3_data_source": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ "compression_type": { Type: schema.TypeString, Required: true, @@ -150,6 +192,7 @@ func resourceModel() *schema.Resource { "model_access_config": { Type: schema.TypeList, Optional: true, + ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -161,6 +204,18 @@ func resourceModel() *schema.Resource { }, }, }, + "s3_data_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.S3ModelDataType](), + }, + "s3_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validModelDataURL, + }, }, }, }, @@ -312,11 +367,26 @@ func resourceModel() *schema.Resource { Required: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "s3_uri": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validModelDataURL, + "compression_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.ModelCompressionType](), + }, + "model_access_config": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "accept_eula": { + Type: schema.TypeBool, + Required: true, + ForceNew: true, + }, + }, + }, }, "s3_data_type": { Type: schema.TypeString, @@ -324,6 +394,34 @@ func resourceModel() *schema.Resource { ForceNew: true, ValidateDiagFunc: enum.Validate[awstypes.S3ModelDataType](), }, + "s3_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validModelDataURL, + }, + }, + }, + }, + }, + }, + }, + "additional_model_data_source": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "s3_data_source": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ "compression_type": { Type: schema.TypeString, Required: true, @@ -345,6 +443,18 @@ func resourceModel() *schema.Resource { }, }, }, + "s3_data_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.S3ModelDataType](), + }, + "s3_uri": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validModelDataURL, + }, }, }, }, @@ -563,12 +673,12 @@ func findModelByName(ctx context.Context, conn *sagemaker.Client, name string) ( return output, nil } -func expandVPCConfigRequest(l []any) *awstypes.VpcConfig { - if len(l) == 0 { +func expandVPCConfigRequest(tfList []any) *awstypes.VpcConfig { + if len(tfList) == 0 { return nil } - m := l[0].(map[string]any) + m := tfList[0].(map[string]any) return &awstypes.VpcConfig{ SecurityGroupIds: flex.ExpandStringValueSet(m[names.AttrSecurityGroupIDs].(*schema.Set)), @@ -576,119 +686,131 @@ func expandVPCConfigRequest(l []any) *awstypes.VpcConfig { } } -func flattenVPCConfigResponse(vpcConfig *awstypes.VpcConfig) []map[string]any { - if vpcConfig == nil { - return []map[string]any{} - } +func expandContainer(tfMap map[string]any) *awstypes.ContainerDefinition { + apiObject := awstypes.ContainerDefinition{} - m := map[string]any{ - names.AttrSecurityGroupIDs: flex.FlattenStringValueSet(vpcConfig.SecurityGroupIds), - names.AttrSubnets: flex.FlattenStringValueSet(vpcConfig.Subnets), + if v, ok := tfMap["image"]; ok && v.(string) != "" { + apiObject.Image = aws.String(v.(string)) } - - return []map[string]any{m} -} - -func expandContainer(m map[string]any) *awstypes.ContainerDefinition { - container := awstypes.ContainerDefinition{} - - if v, ok := m["image"]; ok && v.(string) != "" { - container.Image = aws.String(v.(string)) + if v, ok := tfMap[names.AttrMode]; ok && v.(string) != "" { + apiObject.Mode = awstypes.ContainerMode(v.(string)) } - - if v, ok := m[names.AttrMode]; ok && v.(string) != "" { - container.Mode = awstypes.ContainerMode(v.(string)) + if v, ok := tfMap["container_hostname"]; ok && v.(string) != "" { + apiObject.ContainerHostname = aws.String(v.(string)) } - - if v, ok := m["container_hostname"]; ok && v.(string) != "" { - container.ContainerHostname = aws.String(v.(string)) + if v, ok := tfMap["model_data_url"]; ok && v.(string) != "" { + apiObject.ModelDataUrl = aws.String(v.(string)) } - if v, ok := m["model_data_url"]; ok && v.(string) != "" { - container.ModelDataUrl = aws.String(v.(string)) + if v, ok := tfMap["model_package_name"]; ok && v.(string) != "" { + apiObject.ModelPackageName = aws.String(v.(string)) } - if v, ok := m["model_package_name"]; ok && v.(string) != "" { - container.ModelPackageName = aws.String(v.(string)) + if v, ok := tfMap["model_data_source"]; ok { + apiObject.ModelDataSource = expandModelDataSource(v.([]any)) } - if v, ok := m["model_data_source"]; ok { - container.ModelDataSource = expandModelDataSource(v.([]any)) + if v, ok := tfMap["additional_model_data_source"]; ok { + apiObject.AdditionalModelDataSources = expandAdditionalModelDataSources(v.([]any)) } - if v, ok := m[names.AttrEnvironment].(map[string]any); ok && len(v) > 0 { - container.Environment = flex.ExpandStringValueMap(v) + if v, ok := tfMap[names.AttrEnvironment].(map[string]any); ok && len(v) > 0 { + apiObject.Environment = flex.ExpandStringValueMap(v) } - - if v, ok := m["image_config"]; ok { - container.ImageConfig = expandModelImageConfig(v.([]any)) + if v, ok := tfMap["image_config"]; ok { + apiObject.ImageConfig = expandModelImageConfig(v.([]any)) + } + if v, ok := tfMap["inference_specification_name"]; ok && v.(string) != "" { + apiObject.InferenceSpecificationName = aws.String(v.(string)) + } + if v, ok := tfMap["multi_model_config"].([]any); ok && len(v) > 0 { + apiObject.MultiModelConfig = expandMultiModelConfig(v) } - if v, ok := m["inference_specification_name"]; ok && v.(string) != "" { - container.InferenceSpecificationName = aws.String(v.(string)) + return &apiObject +} + +func expandModelDataSource(tfList []any) *awstypes.ModelDataSource { + if len(tfList) == 0 { + return nil } - if v, ok := m["multi_model_config"].([]any); ok && len(v) > 0 { - container.MultiModelConfig = expandMultiModelConfig(v) + tfMap := tfList[0].(map[string]any) + + apiObject := awstypes.ModelDataSource{} + if v, ok := tfMap["s3_data_source"]; ok { + apiObject.S3DataSource = expandS3ModelDataSource(v.([]any)) } - return &container + return &apiObject } -func expandModelDataSource(l []any) *awstypes.ModelDataSource { - if len(l) == 0 { +func expandAdditionalModelDataSources(tfList []any) []awstypes.AdditionalModelDataSource { + if len(tfList) == 0 { return nil } - modelDataSource := awstypes.ModelDataSource{} + apiObjects := make([]awstypes.AdditionalModelDataSource, 0, len(tfList)) + for _, m := range tfList { + tfMap, ok := m.(map[string]any) + if !ok { + continue + } + apiObjects = append(apiObjects, expandAdditionalModelDataSource(tfMap)) + } - m := l[0].(map[string]any) + return apiObjects +} - if v, ok := m["s3_data_source"]; ok { - modelDataSource.S3DataSource = expandS3ModelDataSource(v.([]any)) +func expandAdditionalModelDataSource(tfMap map[string]any) awstypes.AdditionalModelDataSource { + apiObject := awstypes.AdditionalModelDataSource{} + + if v, ok := tfMap["channel_name"]; ok && v.(string) != "" { + apiObject.ChannelName = aws.String(v.(string)) + } + if v, ok := tfMap["s3_data_source"]; ok { + apiObject.S3DataSource = expandS3ModelDataSource(v.([]any)) } - return &modelDataSource + return apiObject } -func expandS3ModelDataSource(l []any) *awstypes.S3ModelDataSource { - if len(l) == 0 { +func expandS3ModelDataSource(tfList []any) *awstypes.S3ModelDataSource { + if len(tfList) == 0 { return nil } - s3ModelDataSource := awstypes.S3ModelDataSource{} - - m := l[0].(map[string]any) + m := tfList[0].(map[string]any) + apiObject := awstypes.S3ModelDataSource{} if v, ok := m["s3_uri"]; ok && v.(string) != "" { - s3ModelDataSource.S3Uri = aws.String(v.(string)) + apiObject.S3Uri = aws.String(v.(string)) } if v, ok := m["s3_data_type"]; ok && v.(string) != "" { - s3ModelDataSource.S3DataType = awstypes.S3ModelDataType(v.(string)) + apiObject.S3DataType = awstypes.S3ModelDataType(v.(string)) } if v, ok := m["compression_type"]; ok && v.(string) != "" { - s3ModelDataSource.CompressionType = awstypes.ModelCompressionType(v.(string)) + apiObject.CompressionType = awstypes.ModelCompressionType(v.(string)) } - if v, ok := m["model_access_config"].([]any); ok && len(v) > 0 { - s3ModelDataSource.ModelAccessConfig = expandModelAccessConfig(v) + apiObject.ModelAccessConfig = expandModelAccessConfig(v) } - return &s3ModelDataSource + return &apiObject } -func expandModelImageConfig(l []any) *awstypes.ImageConfig { - if len(l) == 0 { +func expandModelImageConfig(tfList []any) *awstypes.ImageConfig { + if len(tfList) == 0 { return nil } - m := l[0].(map[string]any) + m := tfList[0].(map[string]any) - imageConfig := &awstypes.ImageConfig{ + apiObject := &awstypes.ImageConfig{ RepositoryAccessMode: awstypes.RepositoryAccessMode(m["repository_access_mode"].(string)), } if v, ok := m["repository_auth_config"].([]any); ok && len(v) > 0 && v[0] != nil { - imageConfig.RepositoryAuthConfig = expandRepositoryAuthConfig(v[0].(map[string]any)) + apiObject.RepositoryAuthConfig = expandRepositoryAuthConfig(v[0].(map[string]any)) } - return imageConfig + return apiObject } func expandRepositoryAuthConfig(tfMap map[string]any) *awstypes.RepositoryAuthConfig { @@ -706,141 +828,181 @@ func expandRepositoryAuthConfig(tfMap map[string]any) *awstypes.RepositoryAuthCo } func expandContainers(a []any) []awstypes.ContainerDefinition { - containers := make([]awstypes.ContainerDefinition, 0, len(a)) + apiObjects := make([]awstypes.ContainerDefinition, 0, len(a)) for _, m := range a { - containers = append(containers, *expandContainer(m.(map[string]any))) + apiObjects = append(apiObjects, *expandContainer(m.(map[string]any))) } - return containers + return apiObjects } -func expandModelAccessConfig(l []any) *awstypes.ModelAccessConfig { - if len(l) == 0 { +func expandModelAccessConfig(tfList []any) *awstypes.ModelAccessConfig { + if len(tfList) == 0 { return nil } - m := l[0].(map[string]any) - - modelAccessConfig := &awstypes.ModelAccessConfig{} + m := tfList[0].(map[string]any) + apiObject := &awstypes.ModelAccessConfig{} if v, ok := m["accept_eula"].(bool); ok { - modelAccessConfig.AcceptEula = aws.Bool(v) + apiObject.AcceptEula = aws.Bool(v) } - return modelAccessConfig + return apiObject } -func expandMultiModelConfig(l []any) *awstypes.MultiModelConfig { - if len(l) == 0 { +func expandMultiModelConfig(tfList []any) *awstypes.MultiModelConfig { + if len(tfList) == 0 { return nil } - m := l[0].(map[string]any) - - multiModelConfig := &awstypes.MultiModelConfig{} + m := tfList[0].(map[string]any) + apiObject := &awstypes.MultiModelConfig{} if v, ok := m["model_cache_setting"].(string); ok && v != "" { - multiModelConfig.ModelCacheSetting = awstypes.ModelCacheSetting(v) + apiObject.ModelCacheSetting = awstypes.ModelCacheSetting(v) } - return multiModelConfig + return apiObject } -func flattenContainer(container *awstypes.ContainerDefinition) []any { - if container == nil { - return []any{} +func expandModelInferenceExecutionConfig(tfList []any) *awstypes.InferenceExecutionConfig { + if len(tfList) == 0 { + return nil } - cfg := make(map[string]any) + m := tfList[0].(map[string]any) + apiObject := &awstypes.InferenceExecutionConfig{ + Mode: awstypes.InferenceExecutionMode(m[names.AttrMode].(string)), + } + + return apiObject +} - if container.Image != nil { - cfg["image"] = aws.ToString(container.Image) +func flattenVPCConfigResponse(apiObject *awstypes.VpcConfig) []map[string]any { + if apiObject == nil { + return []map[string]any{} } - cfg[names.AttrMode] = container.Mode + tfMap := map[string]any{ + names.AttrSecurityGroupIDs: flex.FlattenStringValueSet(apiObject.SecurityGroupIds), + names.AttrSubnets: flex.FlattenStringValueSet(apiObject.Subnets), + } + + return []map[string]any{tfMap} +} - if container.ContainerHostname != nil { - cfg["container_hostname"] = aws.ToString(container.ContainerHostname) +func flattenContainer(apiObject *awstypes.ContainerDefinition) []any { + if apiObject == nil { + return []any{} } - if container.ModelDataUrl != nil { - cfg["model_data_url"] = aws.ToString(container.ModelDataUrl) + + tfMap := map[string]any{ + names.AttrMode: apiObject.Mode, } - if container.ModelDataSource != nil { - cfg["model_data_source"] = flattenModelDataSource(container.ModelDataSource) + + if apiObject.Image != nil { + tfMap["image"] = aws.ToString(apiObject.Image) } - if container.ModelPackageName != nil { - cfg["model_package_name"] = aws.ToString(container.ModelPackageName) + if apiObject.ContainerHostname != nil { + tfMap["container_hostname"] = aws.ToString(apiObject.ContainerHostname) } - if container.Environment != nil { - cfg[names.AttrEnvironment] = aws.StringMap(container.Environment) + if apiObject.ModelDataUrl != nil { + tfMap["model_data_url"] = aws.ToString(apiObject.ModelDataUrl) } - - if container.ImageConfig != nil { - cfg["image_config"] = flattenImageConfig(container.ImageConfig) + if apiObject.ModelDataSource != nil { + tfMap["model_data_source"] = flattenModelDataSource(apiObject.ModelDataSource) } - - if container.InferenceSpecificationName != nil { - cfg["inference_specification_name"] = aws.ToString(container.InferenceSpecificationName) + if len(apiObject.AdditionalModelDataSources) > 0 { + tfMap["additional_model_data_source"] = flattenAdditionalModelDataSources(apiObject.AdditionalModelDataSources) } - - if container.MultiModelConfig != nil { - cfg["multi_model_config"] = flattenMultiModelConfig(container.MultiModelConfig) + if apiObject.ModelPackageName != nil { + tfMap["model_package_name"] = aws.ToString(apiObject.ModelPackageName) + } + if apiObject.Environment != nil { + tfMap[names.AttrEnvironment] = aws.StringMap(apiObject.Environment) + } + if apiObject.ImageConfig != nil { + tfMap["image_config"] = flattenImageConfig(apiObject.ImageConfig) + } + if apiObject.InferenceSpecificationName != nil { + tfMap["inference_specification_name"] = aws.ToString(apiObject.InferenceSpecificationName) + } + if apiObject.MultiModelConfig != nil { + tfMap["multi_model_config"] = flattenMultiModelConfig(apiObject.MultiModelConfig) } - return []any{cfg} + return []any{tfMap} } -func flattenModelDataSource(modelDataSource *awstypes.ModelDataSource) []any { - if modelDataSource == nil { +func flattenModelDataSource(apiObject *awstypes.ModelDataSource) []any { + if apiObject == nil { return []any{} } - cfg := make(map[string]any) - - if modelDataSource.S3DataSource != nil { - cfg["s3_data_source"] = flattenS3ModelDataSource(modelDataSource.S3DataSource) + tfMap := make(map[string]any) + if apiObject.S3DataSource != nil { + tfMap["s3_data_source"] = flattenS3ModelDataSource(apiObject.S3DataSource) } - return []any{cfg} + return []any{tfMap} } -func flattenS3ModelDataSource(s3ModelDataSource *awstypes.S3ModelDataSource) []any { - if s3ModelDataSource == nil { - return []any{} +func flattenAdditionalModelDataSources(apiObjects []awstypes.AdditionalModelDataSource) []any { + tfList := make([]any, 0, len(apiObjects)) + for _, obj := range apiObjects { + tfList = append(tfList, flattenAdditionalModelDataSource(obj)) } - cfg := make(map[string]any) + return tfList +} - if s3ModelDataSource.S3Uri != nil { - cfg["s3_uri"] = aws.ToString(s3ModelDataSource.S3Uri) +func flattenAdditionalModelDataSource(apiObject awstypes.AdditionalModelDataSource) map[string]any { + tfMap := make(map[string]any) + if apiObject.ChannelName != nil { + tfMap["channel_name"] = aws.ToString(apiObject.ChannelName) } + if apiObject.S3DataSource != nil { + tfMap["s3_data_source"] = flattenS3ModelDataSource(apiObject.S3DataSource) + } + + return tfMap +} - cfg["s3_data_type"] = s3ModelDataSource.S3DataType +func flattenS3ModelDataSource(apiObject *awstypes.S3ModelDataSource) []any { + if apiObject == nil { + return []any{} + } - cfg["compression_type"] = s3ModelDataSource.CompressionType + tfMap := map[string]any{ + "s3_data_type": apiObject.S3DataType, + "compression_type": apiObject.CompressionType, + } - if s3ModelDataSource.ModelAccessConfig != nil { - cfg["model_access_config"] = flattenModelAccessConfig(s3ModelDataSource.ModelAccessConfig) + if apiObject.ModelAccessConfig != nil { + tfMap["model_access_config"] = flattenModelAccessConfig(apiObject.ModelAccessConfig) + } + if apiObject.S3Uri != nil { + tfMap["s3_uri"] = aws.ToString(apiObject.S3Uri) } - return []any{cfg} + return []any{tfMap} } -func flattenImageConfig(imageConfig *awstypes.ImageConfig) []any { - if imageConfig == nil { +func flattenImageConfig(apiObject *awstypes.ImageConfig) []any { + if apiObject == nil { return []any{} } - cfg := make(map[string]any) - - cfg["repository_access_mode"] = imageConfig.RepositoryAccessMode - - if tfMap := flattenRepositoryAuthConfig(imageConfig.RepositoryAuthConfig); len(tfMap) > 0 { - cfg["repository_auth_config"] = []any{tfMap} + tfMap := map[string]any{ + "repository_access_mode": apiObject.RepositoryAccessMode, + } + if v := flattenRepositoryAuthConfig(apiObject.RepositoryAuthConfig); len(v) > 0 { + tfMap["repository_auth_config"] = []any{v} } - return []any{cfg} + return []any{tfMap} } func flattenRepositoryAuthConfig(apiObject *awstypes.RepositoryAuthConfig) map[string]any { @@ -849,7 +1011,6 @@ func flattenRepositoryAuthConfig(apiObject *awstypes.RepositoryAuthConfig) map[s } tfMap := make(map[string]any) - if v := apiObject.RepositoryCredentialsProviderArn; v != nil { tfMap["repository_credentials_provider_arn"] = aws.ToString(v) } @@ -857,62 +1018,47 @@ func flattenRepositoryAuthConfig(apiObject *awstypes.RepositoryAuthConfig) map[s return tfMap } -func flattenContainers(containers []awstypes.ContainerDefinition) []any { - fContainers := make([]any, 0, len(containers)) - for _, container := range containers { - fContainers = append(fContainers, flattenContainer(&container)[0].(map[string]any)) - } - return fContainers -} - -func flattenModelAccessConfig(config *awstypes.ModelAccessConfig) []any { - if config == nil { - return []any{} +func flattenContainers(apiObjects []awstypes.ContainerDefinition) []any { + tfList := make([]any, 0, len(apiObjects)) + for _, obj := range apiObjects { + tfList = append(tfList, flattenContainer(&obj)[0].(map[string]any)) } - - cfg := make(map[string]any) - - cfg["accept_eula"] = aws.ToBool(config.AcceptEula) - - return []any{cfg} + return tfList } -func flattenMultiModelConfig(config *awstypes.MultiModelConfig) []any { - if config == nil { +func flattenModelAccessConfig(apiObject *awstypes.ModelAccessConfig) []any { + if apiObject == nil { return []any{} } - cfg := make(map[string]any) - - if config.ModelCacheSetting != "" { - cfg["model_cache_setting"] = config.ModelCacheSetting + tfMap := map[string]any{ + "accept_eula": aws.ToBool(apiObject.AcceptEula), } - return []any{cfg} + return []any{tfMap} } -func expandModelInferenceExecutionConfig(l []any) *awstypes.InferenceExecutionConfig { - if len(l) == 0 { - return nil +func flattenMultiModelConfig(apiObject *awstypes.MultiModelConfig) []any { + if apiObject == nil { + return []any{} } - m := l[0].(map[string]any) - - config := &awstypes.InferenceExecutionConfig{ - Mode: awstypes.InferenceExecutionMode(m[names.AttrMode].(string)), + tfMap := make(map[string]any) + if apiObject.ModelCacheSetting != "" { + tfMap["model_cache_setting"] = apiObject.ModelCacheSetting } - return config + return []any{tfMap} } -func flattenModelInferenceExecutionConfig(config *awstypes.InferenceExecutionConfig) []any { - if config == nil { +func flattenModelInferenceExecutionConfig(apiObject *awstypes.InferenceExecutionConfig) []any { + if apiObject == nil { return []any{} } - cfg := make(map[string]any) - - cfg[names.AttrMode] = config.Mode + tfMap := map[string]any{ + names.AttrMode: apiObject.Mode, + } - return []any{cfg} + return []any{tfMap} } diff --git a/internal/service/sagemaker/model_test.go b/internal/service/sagemaker/model_test.go index 8d0830cf3ecc..2e1f8ea05691 100644 --- a/internal/service/sagemaker/model_test.go +++ b/internal/service/sagemaker/model_test.go @@ -582,6 +582,35 @@ func TestAccSageMakerModel_primaryContainerMultiModelConfigModelCacheSetting(t * }) } +func TestAccSageMakerModel_primaryContainerAdditionalModelDataSource(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sagemaker_model.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.SageMakerServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccModelConfig_primaryContainerAdditionalModelDataSource(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckModelExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "primary_container.0.additional_model_data_source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "primary_container.0.additional_model_data_source.0.channel_name", "test-channel"), + resource.TestCheckResourceAttr(resourceName, "primary_container.0.additional_model_data_source.0.s3_data_source.0.s3_data_type", "S3Prefix"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccSageMakerModel_containersMultiModelConfigModelCacheSetting(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -887,25 +916,8 @@ resource "aws_sagemaker_model" "test" { `, rName)) } -func testAccModelConfig_primaryContainerUncompressedModel(rName string) string { - return acctest.ConfigCompose(testAccModelConfig_base(rName), fmt.Sprintf(` -resource "aws_sagemaker_model" "test" { - name = %[1]q - execution_role_arn = aws_iam_role.test.arn - - primary_container { - image = data.aws_sagemaker_prebuilt_ecr_image.test.registry_path - model_data_source { - s3_data_source { - s3_data_type = "S3Prefix" - s3_uri = "s3://${aws_s3_object.test.bucket}/model/" - compression_type = "None" - } - } - } -} - - +func testAccModelConfig_s3DataSourceBase(rName string) string { + return fmt.Sprintf(` resource "aws_iam_policy" "test" { name = %[1]q description = "Allow SageMaker AI to create model" @@ -963,6 +975,55 @@ resource "aws_s3_object" "test" { key = "model/inference.py" content = "some-data" } +`, rName) +} + +func testAccModelConfig_primaryContainerAdditionalModelDataSource(rName string) string { + return acctest.ConfigCompose( + testAccModelConfig_base(rName), + testAccModelConfig_s3DataSourceBase(rName), + fmt.Sprintf(` +resource "aws_sagemaker_model" "test" { + name = %[1]q + execution_role_arn = aws_iam_role.test.arn + + primary_container { + image = data.aws_sagemaker_prebuilt_ecr_image.test.registry_path + model_data_url = "https://s3.amazonaws.com/${aws_s3_object.test.bucket}/${aws_s3_object.test.key}" + + additional_model_data_source { + channel_name = "test-channel" + s3_data_source { + s3_uri = "s3://${aws_s3_object.test.bucket}/model/" + s3_data_type = "S3Prefix" + compression_type = "None" + } + } + } +} +`, rName)) +} + +func testAccModelConfig_primaryContainerUncompressedModel(rName string) string { + return acctest.ConfigCompose( + testAccModelConfig_base(rName), + testAccModelConfig_s3DataSourceBase(rName), + fmt.Sprintf(` +resource "aws_sagemaker_model" "test" { + name = %[1]q + execution_role_arn = aws_iam_role.test.arn + + primary_container { + image = data.aws_sagemaker_prebuilt_ecr_image.test.registry_path + model_data_source { + s3_data_source { + s3_data_type = "S3Prefix" + s3_uri = "s3://${aws_s3_object.test.bucket}/model/" + compression_type = "None" + } + } + } +} `, rName)) } diff --git a/internal/service/sagemaker/notebook_instance_lifecycle_configuration_test.go b/internal/service/sagemaker/notebook_instance_lifecycle_configuration_test.go index d3667a480017..8e2402c07744 100644 --- a/internal/service/sagemaker/notebook_instance_lifecycle_configuration_test.go +++ b/internal/service/sagemaker/notebook_instance_lifecycle_configuration_test.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tfsagemaker "github.com/hashicorp/terraform-provider-aws/internal/service/sagemaker" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -78,8 +78,8 @@ func TestAccSageMakerNotebookInstanceLifecycleConfiguration_update(t *testing.T) Check: resource.ComposeTestCheckFunc( testAccCheckNotebookInstanceLifecycleConfigurationExists(ctx, resourceName, &lifecycleConfig), - resource.TestCheckResourceAttr(resourceName, "on_create", itypes.Base64EncodeOnce([]byte("echo bla"))), - resource.TestCheckResourceAttr(resourceName, "on_start", itypes.Base64EncodeOnce([]byte("echo blub"))), + resource.TestCheckResourceAttr(resourceName, "on_create", inttypes.Base64EncodeOnce([]byte("echo bla"))), + resource.TestCheckResourceAttr(resourceName, "on_start", inttypes.Base64EncodeOnce([]byte("echo blub"))), ), }, { diff --git a/internal/service/secretsmanager/secret_version_test.go b/internal/service/secretsmanager/secret_version_test.go index 3c01c5bd5db2..5e9728e2d407 100644 --- a/internal/service/secretsmanager/secret_version_test.go +++ b/internal/service/secretsmanager/secret_version_test.go @@ -19,7 +19,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tfsecretsmanager "github.com/hashicorp/terraform-provider-aws/internal/service/secretsmanager" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -74,7 +74,7 @@ func TestAccSecretsManagerSecretVersion_base64Binary(t *testing.T) { Config: testAccSecretVersionConfig_binary(rName), Check: resource.ComposeTestCheckFunc( testAccCheckSecretVersionExists(ctx, resourceName, &version), - resource.TestCheckResourceAttr(resourceName, "secret_binary", itypes.Base64EncodeOnce([]byte("test-binary"))), + resource.TestCheckResourceAttr(resourceName, "secret_binary", inttypes.Base64EncodeOnce([]byte("test-binary"))), resource.TestCheckResourceAttrSet(resourceName, "version_id"), resource.TestCheckResourceAttr(resourceName, "version_stages.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "version_stages.*", "AWSCURRENT"), diff --git a/internal/service/servicecatalog/portfolio_data_source_tags_gen_test.go b/internal/service/servicecatalog/portfolio_data_source_tags_gen_test.go index e353ec4611d0..1060470fc3c1 100644 --- a/internal/service/servicecatalog/portfolio_data_source_tags_gen_test.go +++ b/internal/service/servicecatalog/portfolio_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfservicecatalog "github.com/hashicorp/terraform-provider-aws/internal/service/servicecatalog" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccServiceCatalogPortfolioDataSource_tags_IgnoreTags_Overlap_ResourceTa } func expectFullPortfolioDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Portfolio", }), knownValue) diff --git a/internal/service/servicecatalog/portfolio_tags_gen_test.go b/internal/service/servicecatalog/portfolio_tags_gen_test.go index 4f6a2c98b53e..bbd0b1cdf218 100644 --- a/internal/service/servicecatalog/portfolio_tags_gen_test.go +++ b/internal/service/servicecatalog/portfolio_tags_gen_test.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfservicecatalog "github.com/hashicorp/terraform-provider-aws/internal/service/servicecatalog" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -2309,7 +2309,7 @@ func TestAccServiceCatalogPortfolio_tags_IgnoreTags_Overlap_ResourceTag(t *testi } func expectFullPortfolioResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullResourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullResourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Portfolio", }), knownValue) diff --git a/internal/service/servicecatalog/product_data_source_tags_gen_test.go b/internal/service/servicecatalog/product_data_source_tags_gen_test.go index 59558e44eee6..be3f915d7493 100644 --- a/internal/service/servicecatalog/product_data_source_tags_gen_test.go +++ b/internal/service/servicecatalog/product_data_source_tags_gen_test.go @@ -15,7 +15,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfservicecatalog "github.com/hashicorp/terraform-provider-aws/internal/service/servicecatalog" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -205,7 +205,7 @@ func TestAccServiceCatalogProductDataSource_tags_IgnoreTags_Overlap_ResourceTag( } func expectFullProductDataSourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullDataSourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Product", }), knownValue) diff --git a/internal/service/servicecatalog/product_tags_gen_test.go b/internal/service/servicecatalog/product_tags_gen_test.go index 96dc93e27bf2..760f4d57e4a9 100644 --- a/internal/service/servicecatalog/product_tags_gen_test.go +++ b/internal/service/servicecatalog/product_tags_gen_test.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfservicecatalog "github.com/hashicorp/terraform-provider-aws/internal/service/servicecatalog" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -2379,7 +2379,7 @@ func TestAccServiceCatalogProduct_tags_IgnoreTags_Overlap_ResourceTag(t *testing } func expectFullProductResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullResourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullResourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Product", }), knownValue) diff --git a/internal/service/servicecatalog/provisioned_product_tags_gen_test.go b/internal/service/servicecatalog/provisioned_product_tags_gen_test.go index 9b7fd5ad543a..c69e4b0934ed 100644 --- a/internal/service/servicecatalog/provisioned_product_tags_gen_test.go +++ b/internal/service/servicecatalog/provisioned_product_tags_gen_test.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfservicecatalog "github.com/hashicorp/terraform-provider-aws/internal/service/servicecatalog" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -2418,7 +2418,7 @@ func testAccServiceCatalogProvisionedProduct_removingTagNotSupported(t *testing. } func expectFullProvisionedProductResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullResourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullResourceTagsSpecTags(tfservicecatalog.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Provisioned Product", }), knownValue) diff --git a/internal/service/servicecatalog/tags.go b/internal/service/servicecatalog/tags.go index 34cbc583202c..f95f9540efd9 100644 --- a/internal/service/servicecatalog/tags.go +++ b/internal/service/servicecatalog/tags.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: MPL-2.0 //go:build !generate -// +build !generate package servicecatalog diff --git a/internal/service/sesv2/email_identity_test.go b/internal/service/sesv2/email_identity_test.go index 51f647b3655f..d8962888506e 100644 --- a/internal/service/sesv2/email_identity_test.go +++ b/internal/service/sesv2/email_identity_test.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tfsesv2 "github.com/hashicorp/terraform-provider-aws/internal/service/sesv2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -195,10 +195,10 @@ func TestAccSESV2EmailIdentity_domainSigning(t *testing.T) { rName := acctest.RandomDomainName() resourceName := "aws_sesv2_email_identity.test" - key1 := itypes.Base64EncodeOnce([]byte(acctest.TLSRSAPrivateKeyPEM(t, 2048))) + key1 := inttypes.Base64EncodeOnce([]byte(acctest.TLSRSAPrivateKeyPEM(t, 2048))) selector1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - key2 := itypes.Base64EncodeOnce([]byte(acctest.TLSRSAPrivateKeyPEM(t, 2048))) + key2 := inttypes.Base64EncodeOnce([]byte(acctest.TLSRSAPrivateKeyPEM(t, 2048))) selector2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ diff --git a/internal/service/sfn/state_machine.go b/internal/service/sfn/state_machine.go index 9b9e10739b05..a1511f005574 100644 --- a/internal/service/sfn/state_machine.go +++ b/internal/service/sfn/state_machine.go @@ -113,6 +113,10 @@ func resourceStateMachine() *schema.Resource { "log_destination": { Type: schema.TypeString, Optional: true, + ValidateFunc: validation.All( + verify.ValidARN, + validation.StringMatch(regexache.MustCompile(`:\*$`), "ARN must end with `:*`"), + ), }, }, }, diff --git a/internal/service/sns/topic.go b/internal/service/sns/topic.go index 2a1a1c1de2ab..649bcab76f04 100644 --- a/internal/service/sns/topic.go +++ b/internal/service/sns/topic.go @@ -20,7 +20,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/attrmap" "github.com/hashicorp/terraform-provider-aws/internal/conns" @@ -52,17 +51,7 @@ var ( Optional: true, ValidateFunc: validation.IntBetween(0, 100), }, - "archive_policy": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentJSONWithEmptyDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + "archive_policy": sdkv2.JSONDocumentWithEmptySchemaOptional(), names.AttrARN: { Type: schema.TypeString, Computed: true, @@ -76,17 +65,7 @@ var ( Optional: true, Default: false, }, - "delivery_policy": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentJSONDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + "delivery_policy": sdkv2.JSONDocumentSchemaOptional(), names.AttrDisplayName: { Type: schema.TypeString, Optional: true, @@ -170,18 +149,7 @@ var ( Type: schema.TypeString, Computed: true, }, - names.AttrPolicy: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + names.AttrPolicy: sdkv2.IAMPolicyDocumentSchemaOptionalComputed(), "signature_version": { Type: schema.TypeInt, Optional: true, @@ -306,12 +274,7 @@ func resourceTopicCreate(ctx context.Context, d *schema.ResourceData, meta any) d.SetId(aws.ToString(output.TopicArn)) - // Retry for eventual consistency; if ABAC is in use, this takes some time - // usually about 10s, presumably for tags really to be there, and we get a - // permissions error. - _, err = tfresource.RetryWhenIsAErrorMessageContains[any, *types.AuthorizationErrorException](ctx, propagationTimeout, func(ctx context.Context) (any, error) { - return nil, putTopicAttributes(ctx, conn, d.Id(), attributes) - }, "no identity-based policy allows") + err = putTopicAttributes(ctx, conn, d.Id(), attributes) if err != nil { return sdkdiag.AppendFromErr(diags, err) @@ -453,7 +416,25 @@ func putTopicAttributes(ctx context.Context, conn *sns.Client, arn string, attri continue } - err := putTopicAttribute(ctx, conn, arn, name, value) + _, err := tfresource.RetryWhen(ctx, propagationTimeout, + func(ctx context.Context) (any, error) { + return nil, putTopicAttribute(ctx, conn, arn, name, value) + }, + func(err error) (bool, error) { + // Retry for eventual consistency; if ABAC is in use, this takes some time + // usually about 10s, presumably for tags really to be there, and we get a + // permissions error. + if errs.IsAErrorMessageContains[*types.AuthorizationErrorException](err, "no identity-based policy allows") { + return true, err + } + + if errs.IsAErrorMessageContains[*types.AuthorizationErrorException](err, "is not authorized to perform") { + return true, err + } + + return false, err + }, + ) if err != nil { return err @@ -467,14 +448,14 @@ func putTopicAttribute(ctx context.Context, conn *sns.Client, arn string, name, const ( timeout = 2 * time.Minute ) - input := &sns.SetTopicAttributesInput{ + input := sns.SetTopicAttributesInput{ AttributeName: aws.String(name), AttributeValue: aws.String(value), TopicArn: aws.String(arn), } _, err := tfresource.RetryWhenIsA[any, *types.InvalidParameterException](ctx, timeout, func(ctx context.Context) (any, error) { - return conn.SetTopicAttributes(ctx, input) + return conn.SetTopicAttributes(ctx, &input) }) if err != nil { diff --git a/internal/service/sns/topic_data_protection_policy.go b/internal/service/sns/topic_data_protection_policy.go index 61c04f917a1e..bd4cce50f86e 100644 --- a/internal/service/sns/topic_data_protection_policy.go +++ b/internal/service/sns/topic_data_protection_policy.go @@ -14,10 +14,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" @@ -40,17 +40,7 @@ func resourceTopicDataProtectionPolicy() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidARN, }, - names.AttrPolicy: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + names.AttrPolicy: sdkv2.IAMPolicyDocumentSchemaRequired(), }, } } diff --git a/internal/service/sns/topic_subscription.go b/internal/service/sns/topic_subscription.go index 0414158410a6..b8a4780601e6 100644 --- a/internal/service/sns/topic_subscription.go +++ b/internal/service/sns/topic_subscription.go @@ -26,6 +26,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/sdkv2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" @@ -67,17 +68,7 @@ var ( Optional: true, Default: false, }, - "filter_policy": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentJSONDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + "filter_policy": sdkv2.JSONDocumentSchemaOptional(), "filter_policy_scope": { Type: schema.TypeString, Optional: true, @@ -103,28 +94,8 @@ var ( Optional: true, Default: false, }, - "redrive_policy": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentJSONDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, - "replay_policy": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringIsJSON, - DiffSuppressFunc: verify.SuppressEquivalentJSONDiffs, - DiffSuppressOnRefresh: true, - StateFunc: func(v any) string { - json, _ := structure.NormalizeJsonString(v) - return json - }, - }, + "redrive_policy": sdkv2.JSONDocumentSchemaOptional(), + "replay_policy": sdkv2.JSONDocumentSchemaOptional(), "subscription_role_arn": { Type: schema.TypeString, Optional: true, diff --git a/internal/service/sns/topic_test.go b/internal/service/sns/topic_test.go index 3855eb34d64f..c86ce0d4856d 100644 --- a/internal/service/sns/topic_test.go +++ b/internal/service/sns/topic_test.go @@ -6,6 +6,7 @@ package sns_test import ( "context" "fmt" + "os" "testing" "github.com/YakDriver/regexache" @@ -13,11 +14,13 @@ import ( sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/envvar" tfsns "github.com/hashicorp/terraform-provider-aws/internal/service/sns" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -620,6 +623,151 @@ func TestAccSNSTopic_encryption(t *testing.T) { }) } +/* +Create an IAM role to be assumed via: + +data "aws_caller_identity" "current" {} + + resource "aws_iam_role" "terraform_execution_role" { + name = "sns-topic-test-terraform-execution-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + AWS = [ + # Prefer the converted role ARN (works for callers using assumed-role sessions) + data.aws_caller_identity.current.arn, + # optionally keep account-root if you need cross-account/account-wide allow + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + ] + } + # Allow both AssumeRole and SetSourceIdentity so callers may pass SourceIdentity + Action = [ + "sts:AssumeRole", + "sts:SetSourceIdentity" + ] + } + ] + }) + + tags = { + Name = "sns-topic-test-terraform-execution-role" + Purpose = "Terraform execution role that supports SourceIdentity" + Environment = "demo" + } + } + +# Policy that allows many AWS operations but specifically excludes iam:PassRole + + resource "aws_iam_policy" "terraform_execution_policy" { + name = "sns-topic-test-terraform-execution-policy" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + + { + Sid = "AllowEC2Operations" + Effect = "Allow" + Action = [ + "ec2:*" + ] + Resource = "*" + }, + { + Sid = "AllowSNSOperations" + Effect = "Allow" + Action = [ + "sns:*" + ] + Resource = "*" + }, + { + Sid = "AllowS3Operations" + Effect = "Allow" + Action = [ + "s3:*" + ] + Resource = "*" + }, + { + Sid = "AllowIAMReadOperations" + Effect = "Allow" + Action = [ + "iam:GetRole", + "iam:GetRolePolicy", + "iam:ListRolePolicies", + "iam:CreatePolicy", + "iam:ListAttachedRolePolicies", + "iam:GetPolicy", + "iam:GetPolicyVersion", + "iam:ListPolicyVersions", + "iam:GetInstanceProfile", + "iam:ListInstanceProfiles", + "iam:CreateRole", + "iam:DeleteRole", + "iam:CreateInstanceProfile", + "iam:DeleteInstanceProfile", + "iam:AddRoleToInstanceProfile", + "iam:RemoveRoleFromInstanceProfile", + "iam:AttachRolePolicy", + "iam:ListInstanceProfilesForRole", + "iam:DetachRolePolicy", + "iam:PutRolePolicy", + "iam:DeleteRolePolicy", + "iam:TagRole", + "iam:UntagRole", + "iam:DeletePolicy" + ] + Resource = "*" + } + ] + }) + } + +# Attach the policy to the role + + resource "aws_iam_role_policy_attachment" "terraform_execution_policy_attachment" { + role = aws_iam_role.terraform_execution_role.name + policy_arn = aws_iam_policy.terraform_execution_policy.arn + } + + output "execution_role_arn" { + value = aws_iam_role.terraform_execution_role.arn + } + +Then run this test with TF_ACC_ASSUME_ROLE_ARN=. +*/ +func TestAccSNSTopic_iamEventualConsistency(t *testing.T) { + ctx := acctest.Context(t) + var attributes map[string]string + resourceName := "aws_sns_topic.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckAssumeRoleARN(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.SNSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckTopicDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccTopicConfig_iamEventualConsistency(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckTopicExists(ctx, resourceName, &attributes), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + func testAccCheckTopicHasPolicy(ctx context.Context, n string, expectedPolicyText string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -1066,3 +1214,89 @@ EOF } `, rName) } + +func testAccTopicConfig_iamEventualConsistency(rName string) string { + //lintignore:AT004 + return fmt.Sprintf(` +provider "aws" { + assume_role { + role_arn = %[1]q + session_name = "TerraformSNSTopicPassRoleTest" + } +} + +data "aws_partition" "current" {} + +resource "aws_iam_role" "sns_feedback_role" { + name = "%[2]s-sns-cloudwatch-logs-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "sns.${data.aws_partition.current.dns_suffix}" + } + Action = "sts:AssumeRole" + } + ] + }) +} + +# Policy for SNS to write to CloudWatch Logs. +resource "aws_iam_role_policy" "sns_feedback_policy" { + name = "%[2]s-sns-cloudwatch-logs-policy" + role = aws_iam_role.sns_feedback_role.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:PutMetricFilter", + "logs:PutRetentionPolicy" + ] + Resource = "*" + } + ] + }) +} + +resource "aws_sns_topic" "test" { + name = %[2]q + + lambda_failure_feedback_role_arn = aws_iam_role.sns_feedback_role.arn +} + +# Grant PassRole permission to the execution role. +resource "aws_iam_policy" "terraform_passrole_policy" { + name = "%[2]s-terraform_passrole_policy" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "ExplicitlyAllowPassRole" + Effect = "Allow" + Action = [ + "iam:PassRole" + ] + Resource = "*" + } + ] + }) +} + +# Attach the policy to the execution role. +resource "aws_iam_role_policy_attachment" "terraform_execution_policy_attachment" { + # Extract the role name from the ARN. + role = trimprefix(provider::aws::arn_parse(%[1]q).resource, "role/") + policy_arn = aws_iam_policy.terraform_passrole_policy.arn +} +`, os.Getenv(envvar.AccAssumeRoleARN), rName) +} diff --git a/internal/service/sqs/service_package_gen.go b/internal/service/sqs/service_package_gen.go index e7d230c3c5f8..e2d3d5061adb 100644 --- a/internal/service/sqs/service_package_gen.go +++ b/internal/service/sqs/service_package_gen.go @@ -55,9 +55,10 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa IdentifierAttribute: names.AttrID, }), Region: unique.Make(inttypes.ResourceRegionDefault()), - Identity: inttypes.VersionedIdentity(1, inttypes.RegionalCustomInherentRegionIdentity(names.AttrURL, parseQueueURL, + Identity: inttypes.RegionalCustomInherentRegionIdentity(names.AttrURL, parseQueueURL, inttypes.WithIdentityDuplicateAttrs(names.AttrID), - )), + inttypes.WithVersion(1), + ), Import: inttypes.SDKv2Import{ WrappedImport: true, }, @@ -67,9 +68,10 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa TypeName: "aws_sqs_queue_policy", Name: "Queue Policy", Region: unique.Make(inttypes.ResourceRegionDefault()), - Identity: inttypes.VersionedIdentity(1, inttypes.RegionalCustomInherentRegionIdentity("queue_url", parseQueueURL, + Identity: inttypes.RegionalCustomInherentRegionIdentity("queue_url", parseQueueURL, inttypes.WithIdentityDuplicateAttrs(names.AttrID), - )), + inttypes.WithVersion(1), + ), Import: inttypes.SDKv2Import{ WrappedImport: true, }, @@ -79,9 +81,10 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa TypeName: "aws_sqs_queue_redrive_allow_policy", Name: "Queue Redrive Allow Policy", Region: unique.Make(inttypes.ResourceRegionDefault()), - Identity: inttypes.VersionedIdentity(1, inttypes.RegionalCustomInherentRegionIdentity("queue_url", parseQueueURL, + Identity: inttypes.RegionalCustomInherentRegionIdentity("queue_url", parseQueueURL, inttypes.WithIdentityDuplicateAttrs(names.AttrID), - )), + inttypes.WithVersion(1), + ), Import: inttypes.SDKv2Import{ WrappedImport: true, }, @@ -91,9 +94,10 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*inttypes.ServicePa TypeName: "aws_sqs_queue_redrive_policy", Name: "Queue Redrive Policy", Region: unique.Make(inttypes.ResourceRegionDefault()), - Identity: inttypes.VersionedIdentity(1, inttypes.RegionalCustomInherentRegionIdentity("queue_url", parseQueueURL, + Identity: inttypes.RegionalCustomInherentRegionIdentity("queue_url", parseQueueURL, inttypes.WithIdentityDuplicateAttrs(names.AttrID), - )), + inttypes.WithVersion(1), + ), Import: inttypes.SDKv2Import{ WrappedImport: true, }, diff --git a/internal/service/ssm/activation_tags_gen_test.go b/internal/service/ssm/activation_tags_gen_test.go index aa1af128e957..2c32912f27a9 100644 --- a/internal/service/ssm/activation_tags_gen_test.go +++ b/internal/service/ssm/activation_tags_gen_test.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" tfssm "github.com/hashicorp/terraform-provider-aws/internal/service/ssm" - "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -2391,7 +2391,7 @@ func TestAccSSMActivation_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { } func expectFullActivationResourceTags(ctx context.Context, resourceAddress string, knownValue knownvalue.Check) statecheck.StateCheck { - return tfstatecheck.ExpectFullResourceTagsSpecTags(tfssm.ServicePackage(ctx), resourceAddress, unique.Make(types.ServicePackageResourceTags{ + return tfstatecheck.ExpectFullResourceTagsSpecTags(tfssm.ServicePackage(ctx), resourceAddress, unique.Make(inttypes.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, ResourceType: "Activation", }), knownValue) diff --git a/internal/service/ssm/document.go b/internal/service/ssm/document.go index 7b99acdfe439..9666c7ffc2d0 100644 --- a/internal/service/ssm/document.go +++ b/internal/service/ssm/document.go @@ -29,7 +29,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -394,7 +394,7 @@ func resourceDocumentUpdate(ctx context.Context, d *schema.ResourceData, meta an conn := meta.(*conns.AWSClient).SSMClient(ctx) if d.HasChange(names.AttrPermissions) { - var oldAccountIDs, newAccountIDs itypes.Set[string] + var oldAccountIDs, newAccountIDs inttypes.Set[string] o, n := d.GetChange(names.AttrPermissions) if v := o.(map[string]any); len(v) > 0 { diff --git a/internal/service/ssoadmin/account_assignment.go b/internal/service/ssoadmin/account_assignment.go index e5f73f267d72..040078e8a8b2 100644 --- a/internal/service/ssoadmin/account_assignment.go +++ b/internal/service/ssoadmin/account_assignment.go @@ -80,7 +80,7 @@ func resourceAccountAssignment() *schema.Resource { }, "target_type": { Type: schema.TypeString, - Optional: true, + Required: true, ForceNew: true, ValidateDiagFunc: enum.Validate[awstypes.TargetType](), }, diff --git a/internal/service/timestreaminfluxdb/db_cluster.go b/internal/service/timestreaminfluxdb/db_cluster.go index 578f941e03d9..d912899fe750 100644 --- a/internal/service/timestreaminfluxdb/db_cluster.go +++ b/internal/service/timestreaminfluxdb/db_cluster.go @@ -19,6 +19,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -26,7 +28,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -73,15 +74,16 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ names.AttrAllocatedStorage: schema.Int64Attribute{ - Required: true, + Optional: true, Validators: []validator.Int64{ int64validator.Between(20, 16384), }, - Description: `The amount of storage to allocate for your DB storage type in GiB (gibibytes).`, + Description: `The amount of storage to allocate for your DB storage type in GiB (gibibytes). + This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group).`, }, names.AttrARN: framework.ARNAttributeComputedOnly(), names.AttrBucket: schema.StringAttribute{ - Required: true, + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -92,9 +94,12 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque "", ), }, - Description: `The name of the initial InfluxDB bucket. All InfluxDB data is stored in a bucket. - A bucket combines the concept of a database and a retention period (the duration of time - that each data point persists). A bucket belongs to an organization.`, + Description: `Name of the initial InfluxDB bucket. All InfluxDB data is stored in a bucket. + A bucket combines the concept of a database and a retention period (the duration of time + that each data point persists). A bucket belongs to an organization. Along with organization, + username, and password, this argument will be stored in the secret referred to by the + influx_auth_parameters_secret_arn attribute. This field is forbidden for InfluxDB V3 clusters + (when using an InfluxDB V3 db parameter group).`, }, "db_instance_type": schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.DbInstanceType](), @@ -136,12 +141,19 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque CustomType: fwtypes.StringEnumType[awstypes.ClusterDeploymentType](), Optional: true, Computed: true, - Default: stringdefault.StaticString(string(awstypes.ClusterDeploymentTypeMultiNodeReadReplicas)), PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.RequiresReplaceIfConfigured(), stringplanmodifier.UseStateForUnknown(), }, - Description: `Specifies the type of cluster to create.`, + Description: `Specifies the type of cluster to create. This field is forbidden for InfluxDB V3 clusters + (when using an InfluxDB V3 db parameter group).`, + }, + "engine_type": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + Description: `The database engine type of the DB cluster.`, }, names.AttrEndpoint: schema.StringAttribute{ Computed: true, @@ -167,9 +179,9 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque stringplanmodifier.UseStateForUnknown(), }, Description: `The Amazon Resource Name (ARN) of the AWS Secrets Manager secret containing the - initial InfluxDB authorization parameters. The secret value is a JSON formatted - key-value pair holding InfluxDB authorization values: organization, bucket, - username, and password.`, + initial InfluxDB authorization parameters. For InfluxDB V2 clusters, the secret value is a JSON + formatted key-value pair holding InfluxDB authorization values: organization, bucket, + username, and password. For InfluxDB V3 clusters, the secret contains the InfluxDB admin token.`, }, names.AttrName: schema.StringAttribute{ Required: true, @@ -203,18 +215,21 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), "organization": schema.StringAttribute{ - Required: true, + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, Validators: []validator.String{ stringvalidator.LengthBetween(1, 64), }, - Description: `The name of the initial organization for the initial admin user in InfluxDB. An - InfluxDB organization is a workspace for a group of users.`, + Description: `Name of the initial organization for the initial admin user in InfluxDB. An + InfluxDB organization is a workspace for a group of users. Along with bucket, username, + and password, this argument will be stored in the secret referred to by the + influx_auth_parameters_secret_arn attribute. This field is forbidden for InfluxDB V3 clusters + (when using an InfluxDB V3 db parameter group).`, }, names.AttrPassword: schema.StringAttribute{ - Required: true, + Optional: true, Sensitive: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), @@ -223,10 +238,12 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque stringvalidator.LengthBetween(8, 64), stringvalidator.RegexMatches(regexache.MustCompile("^[a-zA-Z0-9]+$"), ""), }, - Description: `The password of the initial admin user created in InfluxDB. This password will - allow you to access the InfluxDB UI to perform various administrative tasks and - also use the InfluxDB CLI to create an operator token. These attributes will be - stored in a Secret created in AWS SecretManager in your account.`, + Description: `Password of the initial admin user created in InfluxDB. This password will + allow you to access the InfluxDB UI to perform various administrative tasks and + also use the InfluxDB CLI to create an operator token. Along with bucket, username, + and organization, this argument will be stored in the secret referred to by the + influx_auth_parameters_secret_arn attribute. This field is forbidden for InfluxDB V3 clusters + (when using an InfluxDB V3 db parameter group) as the AWS API rejects it.`, }, names.AttrPort: schema.Int32Attribute{ Optional: true, @@ -258,7 +275,7 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque read-only operations.`, }, names.AttrUsername: schema.StringAttribute{ - Required: true, + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -269,13 +286,12 @@ func (r *dbClusterResource) Schema(ctx context.Context, req resource.SchemaReque consecutive hyphens`, ), }, - Description: `The username of the initial admin user created in InfluxDB. - Must start with a letter and can't end with a hyphen or contain two - consecutive hyphens. For example, my-user1. This username will allow - you to access the InfluxDB UI to perform various administrative tasks - and also use the InfluxDB CLI to create an operator token. These - attributes will be stored in a Secret created in Amazon Secrets - Manager in your account.`, + Description: `Username of the initial admin user created in InfluxDB. Must start with a letter + and can't end with a hyphen or contain two consecutive hyphens. This username will allow + you to access the InfluxDB UI to perform various administrative tasks and also use the + InfluxDB CLI to create an operator token. Along with bucket, organization, and password, + this argument will be stored in the secret referred to by the influx_auth_parameters_secret_arn + attribute. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group).`, }, names.AttrVPCSecurityGroupIDs: schema.SetAttribute{ CustomType: fwtypes.SetOfStringType, @@ -555,31 +571,154 @@ func (r *dbClusterResource) Delete(ctx context.Context, req resource.DeleteReque } } +func isParameterGroupV3(ctx context.Context, conn *timestreaminfluxdb.Client, parameterGroupID string) (bool, diag.Diagnostics) { + var diags diag.Diagnostics + + out, err := findDBParameterGroupByID(ctx, conn, parameterGroupID) + + if tfresource.NotFound(err) { + return false, diags + } + + if err != nil { + diags.AddWarning( + "Unable to query parameter group", + "Could not determine parameter group type. Validation will be skipped.", + ) + return false, diags + } + + switch out.Parameters.(type) { + case *awstypes.ParametersMemberInfluxDBv3Core: + return true, diags + case *awstypes.ParametersMemberInfluxDBv3Enterprise: + return true, diags + default: + return false, diags + } +} + func (r *dbClusterResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { - var allocatedStorage types.Int64 - resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root(names.AttrAllocatedStorage), &allocatedStorage)...) + var data dbClusterResourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { return } - if allocatedStorage.IsNull() || allocatedStorage.IsUnknown() { - return + isNullOrUnknown := func(val attr.Value) bool { + return val.IsNull() || val.IsUnknown() } - if allocatedStorage.ValueInt64() > math.MaxInt32 { - resp.Diagnostics.AddError( - "Invalid value for allocated_storage", - "allocated_storage was greater than the maximum allowed value for int32", - ) - return + if !isNullOrUnknown(data.AllocatedStorage) { + switch v := data.AllocatedStorage.ValueInt64(); { + case v > math.MaxInt32: + resp.Diagnostics.AddError( + "Invalid value for allocated_storage", + "allocated_storage was greater than the maximum allowed value for int32", + ) + return + case v < math.MinInt32: + resp.Diagnostics.AddError( + "Invalid value for allocated_storage", + "allocated_storage was less than the minimum allowed value for int32", + ) + return + } } - if allocatedStorage.ValueInt64() < math.MinInt32 { - resp.Diagnostics.AddError( - "Invalid value for allocated_storage", - "allocated_storage was less than the minimum allowed value for int32", - ) - return + hasV2Fields := !isNullOrUnknown(data.AllocatedStorage) || + !isNullOrUnknown(data.Bucket) || + !isNullOrUnknown(data.DeploymentType) || + !isNullOrUnknown(data.Organization) || + !isNullOrUnknown(data.Password) || + !isNullOrUnknown(data.Username) + + var isV3Cluster bool + if !isNullOrUnknown(data.DBParameterGroupIdentifier) { + meta := r.Meta() + if meta == nil { + return + } + paramGroupID := data.DBParameterGroupIdentifier.ValueString() + isV3, diags := isParameterGroupV3(ctx, meta.TimestreamInfluxDBClient(ctx), paramGroupID) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + isV3Cluster = isV3 + + if !hasV2Fields && !isV3Cluster { + resp.Diagnostics.AddAttributeError( + path.Root("db_parameter_group_identifier"), + "Invalid Parameter Group Type", + "An InfluxDB V2 parameter group requires InfluxDB V2 fields (allocated_storage, bucket, deployment_type, organization, password, username). Use an InfluxDB V3 parameter group or provide the V2 fields.", + ) + } + } + + if isV3Cluster { + for _, v := range []struct { + val attr.Value + path string + }{ + {data.AllocatedStorage, names.AttrAllocatedStorage}, + {data.Bucket, names.AttrBucket}, + {data.DeploymentType, "deployment_type"}, + {data.Organization, "organization"}, + {data.Password, names.AttrPassword}, + {data.Username, names.AttrUsername}, + } { + if !isNullOrUnknown(v.val) { + resp.Diagnostics.AddAttributeError( + path.Root(v.path), + "Invalid Configuration for InfluxDB V3", + v.path+" must not be set when using an InfluxDB V3 db parameter group", + ) + } + } + } else { + for _, v := range []struct { + val attr.Value + path string + }{ + {data.AllocatedStorage, names.AttrAllocatedStorage}, + {data.Bucket, names.AttrBucket}, + {data.Organization, "organization"}, + {data.Password, names.AttrPassword}, + {data.Username, names.AttrUsername}, + } { + if isNullOrUnknown(v.val) { + resp.Diagnostics.AddAttributeError( + path.Root(v.path), + "Missing Required Configuration for InfluxDB V2", + v.path+" is required for InfluxDB V2 clusters", + ) + } + } + } +} + +func (r *dbClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { + if !req.Plan.Raw.IsNull() { + var data dbClusterResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + var isV3Cluster bool + if !data.DBParameterGroupIdentifier.IsNull() { + isV3, diags := isParameterGroupV3(ctx, r.Meta().TimestreamInfluxDBClient(ctx), data.DBParameterGroupIdentifier.ValueString()) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + isV3Cluster = isV3 + } + + if !isV3Cluster && data.DeploymentType.IsUnknown() { + resp.Plan.SetAttribute(ctx, path.Root("deployment_type"), fwtypes.StringEnumValue(awstypes.ClusterDeploymentTypeMultiNodeReadReplicas)) + } } } @@ -589,7 +728,6 @@ func waitDBClusterCreated(ctx context.Context, conn *timestreaminfluxdb.Client, Target: enum.Slice(awstypes.ClusterStatusAvailable), Refresh: statusDBCluster(conn, id), Timeout: timeout, - NotFoundChecks: 20, ContinuousTargetOccurence: 2, } @@ -607,7 +745,6 @@ func waitDBClusterUpdated(ctx context.Context, conn *timestreaminfluxdb.Client, Target: enum.Slice(awstypes.ClusterStatusAvailable), Refresh: statusDBCluster(conn, id), Timeout: timeout, - NotFoundChecks: 20, ContinuousTargetOccurence: 2, } @@ -651,10 +788,14 @@ func statusDBCluster(conn *timestreaminfluxdb.Client, id string) retry.StateRefr } func findDBClusterByID(ctx context.Context, conn *timestreaminfluxdb.Client, id string) (*timestreaminfluxdb.GetDbClusterOutput, error) { - in := ×treaminfluxdb.GetDbClusterInput{ + in := timestreaminfluxdb.GetDbClusterInput{ DbClusterId: aws.String(id), } + return findDBCluster(ctx, conn, &in) +} + +func findDBCluster(ctx context.Context, conn *timestreaminfluxdb.Client, in *timestreaminfluxdb.GetDbClusterInput) (*timestreaminfluxdb.GetDbClusterOutput, error) { out, err := conn.GetDbCluster(ctx, in) if errs.IsA[*awstypes.ResourceNotFoundException](err) { @@ -674,6 +815,34 @@ func findDBClusterByID(ctx context.Context, conn *timestreaminfluxdb.Client, id return out, nil } +func findDBParameterGroupByID(ctx context.Context, conn *timestreaminfluxdb.Client, id string) (*timestreaminfluxdb.GetDbParameterGroupOutput, error) { + in := timestreaminfluxdb.GetDbParameterGroupInput{ + Identifier: aws.String(id), + } + + return findDBParameterGroup(ctx, conn, &in) +} + +func findDBParameterGroup(ctx context.Context, conn *timestreaminfluxdb.Client, in *timestreaminfluxdb.GetDbParameterGroupInput) (*timestreaminfluxdb.GetDbParameterGroupOutput, error) { + out, err := conn.GetDbParameterGroup(ctx, in) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + } + } + + if err != nil { + return nil, err + } + + if out == nil || out.Id == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out, nil +} + type dbClusterResourceModel struct { framework.WithRegionModel AllocatedStorage types.Int64 `tfsdk:"allocated_storage"` @@ -683,6 +852,7 @@ type dbClusterResourceModel struct { DBParameterGroupIdentifier types.String `tfsdk:"db_parameter_group_identifier"` DBStorageType fwtypes.StringEnum[awstypes.DbStorageType] `tfsdk:"db_storage_type"` DeploymentType fwtypes.StringEnum[awstypes.ClusterDeploymentType] `tfsdk:"deployment_type"` + EngineType types.String `tfsdk:"engine_type"` Endpoint types.String `tfsdk:"endpoint"` FailoverMode fwtypes.StringEnum[awstypes.FailoverMode] `tfsdk:"failover_mode"` ID types.String `tfsdk:"id"` diff --git a/internal/service/timestreaminfluxdb/db_cluster_test.go b/internal/service/timestreaminfluxdb/db_cluster_test.go index 4c93ba9a1b80..51b352f4a929 100644 --- a/internal/service/timestreaminfluxdb/db_cluster_test.go +++ b/internal/service/timestreaminfluxdb/db_cluster_test.go @@ -13,9 +13,13 @@ import ( "github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb" awstypes "github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb/types" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/retry" tftimestreaminfluxdb "github.com/hashicorp/terraform-provider-aws/internal/service/timestreaminfluxdb" @@ -45,16 +49,24 @@ func TestAccTimestreamInfluxDBDBCluster_basic(t *testing.T) { Config: testAccDBClusterConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckDBClusterExists(ctx, t, resourceName, &dbCluster), - acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "timestream-influxdb", regexache.MustCompile(`db-cluster/.+$`)), - resource.TestCheckResourceAttr(resourceName, "db_storage_type", string(awstypes.DbStorageTypeInfluxIoIncludedT1)), - resource.TestCheckResourceAttr(resourceName, "deployment_type", string(awstypes.ClusterDeploymentTypeMultiNodeReadReplicas)), - resource.TestCheckResourceAttr(resourceName, "failover_mode", string(awstypes.FailoverModeAutomatic)), - resource.TestCheckResourceAttrSet(resourceName, "influx_auth_parameters_secret_arn"), - resource.TestCheckResourceAttr(resourceName, "network_type", string(awstypes.NetworkTypeIpv4)), - resource.TestCheckResourceAttr(resourceName, names.AttrPort, "8086"), - resource.TestCheckResourceAttr(resourceName, names.AttrPubliclyAccessible, acctest.CtFalse), - resource.TestCheckResourceAttrSet(resourceName, "reader_endpoint"), ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), tfknownvalue.RegionalARNRegexp("timestream-influxdb", regexache.MustCompile(`db-cluster/.+`))), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("db_storage_type"), tfknownvalue.StringExact(awstypes.DbStorageTypeInfluxIoIncludedT1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("deployment_type"), tfknownvalue.StringExact(awstypes.ClusterDeploymentTypeMultiNodeReadReplicas)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("engine_type"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("failover_mode"), tfknownvalue.StringExact(awstypes.FailoverModeAutomatic)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("influx_auth_parameters_secret_arn"), knownvalue.NotNull()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("network_type"), tfknownvalue.StringExact(awstypes.NetworkTypeIpv4)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrPort), knownvalue.Int32Exact(8086)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrPubliclyAccessible), knownvalue.Bool(false)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("reader_endpoint"), knownvalue.NotNull()), + }, }, { ResourceName: resourceName, @@ -507,6 +519,116 @@ func TestAccTimestreamInfluxDBDBCluster_failoverMode(t *testing.T) { }) } +func TestAccTimestreamInfluxDBDBCluster_dbParameterGroupV3(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var dbCluster timestreaminfluxdb.GetDbClusterOutput + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + resourceName := "aws_timestreaminfluxdb_db_cluster.test" + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheckDBClusters(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.TimestreamInfluxDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDBClusterDestroy(ctx, t), + Steps: []resource.TestStep{ + { + Config: testAccDBClusterConfig_dbParameterGroupV3(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDBClusterExists(ctx, t, resourceName, &dbCluster), + acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "timestream-influxdb", regexache.MustCompile(`db-cluster/.+$`)), + resource.TestCheckResourceAttr(resourceName, "db_parameter_group_identifier", "InfluxDBV3Core"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEndpoint), + resource.TestCheckResourceAttr(resourceName, names.AttrPort, "8181"), + resource.TestCheckResourceAttrSet(resourceName, "engine_type"), + resource.TestCheckResourceAttrSet(resourceName, "influx_auth_parameters_secret_arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{names.AttrBucket, names.AttrUsername, names.AttrPassword, "organization", names.AttrAllocatedStorage}, + }, + }, + }) +} + +func TestAccTimestreamInfluxDBDBCluster_validateConfig(t *testing.T) { + ctx := acctest.Context(t) + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheckDBClusters(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.TimestreamInfluxDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDBClusterDestroy(ctx, t), + Steps: []resource.TestStep{ + { + Config: testAccDBClusterConfig_v2MissingAllocatedStorage(rName), + ExpectError: regexache.MustCompile("allocated_storage is required for InfluxDB V2 clusters"), + }, + { + Config: testAccDBClusterConfig_v2MissingBucket(rName), + ExpectError: regexache.MustCompile("bucket is required for InfluxDB V2 clusters"), + }, + { + Config: testAccDBClusterConfig_v2MissingOrganization(rName), + ExpectError: regexache.MustCompile("organization is required for InfluxDB V2 clusters"), + }, + { + Config: testAccDBClusterConfig_v2MissingPassword(rName), + ExpectError: regexache.MustCompile("password is required for InfluxDB V2 clusters"), + }, + { + Config: testAccDBClusterConfig_v2MissingUsername(rName), + ExpectError: regexache.MustCompile("username is required for InfluxDB V2 clusters"), + }, + { + Config: testAccDBClusterConfig_v3WithV2Fields(rName), + ExpectError: regexache.MustCompile(`(?s)allocated_storage must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v2WithV3ParameterGroup(rName), + ExpectError: regexache.MustCompile(`(?s)allocated_storage must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v3WithAllocatedStorage(rName), + ExpectError: regexache.MustCompile(`(?s)allocated_storage must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v3WithBucket(rName), + ExpectError: regexache.MustCompile(`(?s)bucket must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v3WithDeploymentType(rName), + ExpectError: regexache.MustCompile(`(?s)deployment_type must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v3WithOrganization(rName), + ExpectError: regexache.MustCompile(`(?s)organization must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v3WithPassword(rName), + ExpectError: regexache.MustCompile(`(?s)password must not be set when using an InfluxDB V3 db parameter.*group`), + }, + { + Config: testAccDBClusterConfig_v3WithUsername(rName), + ExpectError: regexache.MustCompile(`(?s)username must not be set when using an InfluxDB V3 db parameter.*group`), + }, + }, + }) +} + func testAccCheckDBClusterDestroy(ctx context.Context, t *testing.T) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.ProviderMeta(ctx, t).TimestreamInfluxDBClient(ctx) @@ -572,27 +694,75 @@ func testAccPreCheckDBClusters(ctx context.Context, t *testing.T) { } func testAccDBClusterConfig_base(rName string, subnetCount int) string { - return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, subnetCount), ` + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, subnetCount), fmt.Sprintf(` resource "aws_security_group" "test" { vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } } -`) +`, rName)) +} + +func testAccDBClusterConfig_v3Base(rName string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} + +resource "aws_route_table" "test" { + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_route_table_association" "test" { + count = 2 + + subnet_id = aws_subnet.test[count.index].id + route_table_id = aws_route_table.test.id +} + +resource "aws_vpc_endpoint" "s3" { + vpc_id = aws_vpc.test.id + service_name = "com.amazonaws.${data.aws_region.current.region}.s3" + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_endpoint_route_table_association" "test" { + route_table_id = aws_route_table.test.id + vpc_endpoint_id = aws_vpc_endpoint.s3.id +} + +resource "aws_security_group_rule" "test" { + type = "egress" + protocol = "-1" + from_port = 0 + to_port = 0 + prefix_list_ids = [aws_vpc_endpoint.s3.prefix_list_id] + security_group_id = aws_security_group.test.id +} +`, rName) } // Minimal configuration. func testAccDBClusterConfig_basic(rName string) string { return acctest.ConfigCompose(testAccDBClusterConfig_base(rName, 2), fmt.Sprintf(` +# InfluxDB V2. resource "aws_timestreaminfluxdb_db_cluster" "test" { - name = %[1]q allocated_storage = 20 + bucket = "initial" + db_instance_type = "db.influx.medium" + name = %[1]q + organization = "organization" username = "admin" password = "testpassword" vpc_subnet_ids = aws_subnet.test[*].id vpc_security_group_ids = [aws_security_group.test.id] - db_instance_type = "db.influx.medium" - port = 8086 - bucket = "initial" - organization = "organization" } `, rName)) } @@ -811,3 +981,281 @@ resource "aws_timestreaminfluxdb_db_cluster" "test" { } `, rName, failoverMode)) } + +func testAccDBClusterConfig_dbParameterGroupV3(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v2MissingAllocatedStorage(rName string) string { + return acctest.ConfigCompose(testAccDBClusterConfig_base(rName, 2), fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + username = "admin" + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + bucket = "initial" + organization = "organization" + deployment_type = "MULTI_NODE_READ_REPLICAS" +} +`, rName)) +} + +func testAccDBClusterConfig_v2MissingBucket(rName string) string { + return acctest.ConfigCompose(testAccDBClusterConfig_base(rName, 2), fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + username = "admin" + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + organization = "organization" + deployment_type = "MULTI_NODE_READ_REPLICAS" +} +`, rName)) +} + +func testAccDBClusterConfig_v2MissingOrganization(rName string) string { + return acctest.ConfigCompose(testAccDBClusterConfig_base(rName, 2), fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + username = "admin" + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + bucket = "initial" + deployment_type = "MULTI_NODE_READ_REPLICAS" +} +`, rName)) +} + +func testAccDBClusterConfig_v2MissingPassword(rName string) string { + return acctest.ConfigCompose(testAccDBClusterConfig_base(rName, 2), fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + username = "admin" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + bucket = "initial" + organization = "organization" + deployment_type = "MULTI_NODE_READ_REPLICAS" +} +`, rName)) +} + +func testAccDBClusterConfig_v2MissingUsername(rName string) string { + return acctest.ConfigCompose(testAccDBClusterConfig_base(rName, 2), fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + bucket = "initial" + organization = "organization" + deployment_type = "MULTI_NODE_READ_REPLICAS" +} +`, rName)) +} + +func testAccDBClusterConfig_v2WithV3ParameterGroup(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + username = "admin" + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + bucket = "initial" + organization = "organization" + deployment_type = "MULTI_NODE_READ_REPLICAS" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithV2Fields(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + username = "admin" + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + bucket = "initial" + organization = "organization" + deployment_type = "MULTI_NODE_READ_REPLICAS" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithAllocatedStorage(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + allocated_storage = 20 + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithBucket(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + bucket = "initial" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithDeploymentType(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + deployment_type = "MULTI_NODE_READ_REPLICAS" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithOrganization(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + organization = "organization" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithPassword(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + password = "testpassword" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} + +func testAccDBClusterConfig_v3WithUsername(rName string) string { + return acctest.ConfigCompose( + testAccDBClusterConfig_base(rName, 2), + testAccDBClusterConfig_v3Base(rName), + fmt.Sprintf(` +resource "aws_timestreaminfluxdb_db_cluster" "test" { + name = %[1]q + username = "admin" + vpc_subnet_ids = aws_subnet.test[*].id + vpc_security_group_ids = [aws_security_group.test.id] + db_instance_type = "db.influx.medium" + db_parameter_group_identifier = "InfluxDBV3Core" + + depends_on = [ + aws_vpc_endpoint_route_table_association.test, + aws_security_group_rule.test, + ] +} +`, rName)) +} diff --git a/internal/service/transfer/web_app_customization_test.go b/internal/service/transfer/web_app_customization_test.go index 2a8a97cdadea..772c072c7fc2 100644 --- a/internal/service/transfer/web_app_customization_test.go +++ b/internal/service/transfer/web_app_customization_test.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" tftransfer "github.com/hashicorp/terraform-provider-aws/internal/service/transfer" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -212,8 +212,8 @@ func TestAccTransferWebAppCustomization_files(t *testing.T) { resourceName := "aws_transfer_web_app_customization.test" darkBytes, _ := os.ReadFile("test-fixtures/Terraform-LogoMark_onDark.png") lightBytes, _ := os.ReadFile("test-fixtures/Terraform-LogoMark_onLight.png") - darkFileBase64Encoded := itypes.Base64Encode(darkBytes) - lightFileBase64Encoded := itypes.Base64Encode(lightBytes) + darkFileBase64Encoded := inttypes.Base64Encode(darkBytes) + lightFileBase64Encoded := inttypes.Base64Encode(lightBytes) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { diff --git a/internal/service/vpclattice/domain_verification.go b/internal/service/vpclattice/domain_verification.go new file mode 100644 index 000000000000..536939018429 --- /dev/null +++ b/internal/service/vpclattice/domain_verification.go @@ -0,0 +1,237 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package vpclattice + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/vpclattice" + awstypes "github.com/aws/aws-sdk-go-v2/service/vpclattice/types" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + sdkid "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_vpclattice_domain_verification", name="Domain Verification") +// @Tags(identifierAttribute="arn") +// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/vpclattice;vpclattice.GetDomainVerificationOutput") +func newDomainVerificationResource(context.Context) (resource.ResourceWithConfigure, error) { + return &domainVerificationResource{}, nil +} + +type domainVerificationResource struct { + framework.ResourceWithModel[domainVerificationResourceModel] + framework.WithImportByID +} + +func (r *domainVerificationResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrARN: framework.ARNAttributeComputedOnly(), + names.AttrCreatedAt: schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrDomainName: schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrID: framework.IDAttribute(), + "last_verified_time": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrStatus: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.VerificationStatus](), + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + "txt_record_name": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "txt_record_value": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + } +} + +func (r *domainVerificationResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data domainVerificationResourceModel + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().VPCLatticeClient(ctx) + + input := vpclattice.StartDomainVerificationInput{ + ClientToken: aws.String(sdkid.UniqueId()), + DomainName: fwflex.StringFromFramework(ctx, data.DomainName), + Tags: getTagsIn(ctx), + } + + output, err := conn.StartDomainVerification(ctx, &input) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("creating VPCLattice Domain Verification (%s)", data.DomainName.ValueString()), err.Error()) + return + } + + data.ID = fwflex.StringToFramework(ctx, output.Id) + + outputGet, err := findDomainVerificationByID(ctx, conn, data.ID.ValueString()) + + if err != nil { + response.State.SetAttribute(ctx, path.Root(names.AttrID), data.ID) + response.Diagnostics.AddError(fmt.Sprintf("reading VPCLattice Domain Verification (%s)", data.ID.ValueString()), err.Error()) + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGet, &data)...) + if response.Diagnostics.HasError() { + return + } + + // Manually set TXT record fields from TxtMethodConfig + if outputGet.TxtMethodConfig != nil { + data.TxtRecordName = fwflex.StringToFramework(ctx, outputGet.TxtMethodConfig.Name) + data.TxtRecordValue = fwflex.StringToFramework(ctx, outputGet.TxtMethodConfig.Value) + } + + response.Diagnostics.Append(response.State.Set(ctx, data)...) +} + +func (r *domainVerificationResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data domainVerificationResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().VPCLatticeClient(ctx) + + output, err := findDomainVerificationByID(ctx, conn, data.ID.ValueString()) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading VPCLattice Domain Verification (%s)", data.ID.ValueString()), err.Error()) + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + // Manually set TXT record fields from TxtMethodConfig + if output.TxtMethodConfig != nil { + data.TxtRecordName = fwflex.StringToFramework(ctx, output.TxtMethodConfig.Name) + data.TxtRecordValue = fwflex.StringToFramework(ctx, output.TxtMethodConfig.Value) + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *domainVerificationResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data domainVerificationResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().VPCLatticeClient(ctx) + + input := vpclattice.DeleteDomainVerificationInput{ + DomainVerificationIdentifier: fwflex.StringFromFramework(ctx, data.ID), + } + _, err := conn.DeleteDomainVerification(ctx, &input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting VPCLattice Domain Verification (%s)", data.ID.ValueString()), err.Error()) + return + } +} + +func findDomainVerificationByID(ctx context.Context, conn *vpclattice.Client, id string) (*vpclattice.GetDomainVerificationOutput, error) { + input := vpclattice.GetDomainVerificationInput{ + DomainVerificationIdentifier: aws.String(id), + } + + output, err := conn.GetDomainVerification(ctx, &input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +type domainVerificationResourceModel struct { + framework.WithRegionModel + ARN types.String `tfsdk:"arn"` + CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` + DomainName types.String `tfsdk:"domain_name"` + ID types.String `tfsdk:"id"` + LastVerifiedTime timetypes.RFC3339 `tfsdk:"last_verified_time"` + Status fwtypes.StringEnum[awstypes.VerificationStatus] `tfsdk:"status"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` + TxtRecordName types.String `tfsdk:"txt_record_name"` + TxtRecordValue types.String `tfsdk:"txt_record_value"` +} diff --git a/internal/service/vpclattice/domain_verification_tags_gen_test.go b/internal/service/vpclattice/domain_verification_tags_gen_test.go new file mode 100644 index 000000000000..1eeee3c81e5c --- /dev/null +++ b/internal/service/vpclattice/domain_verification_tags_gen_test.go @@ -0,0 +1,2279 @@ +// Code generated by internal/generate/tagstests/main.go; DO NOT EDIT. + +package vpclattice_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go-v2/service/vpclattice" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccVPCLatticeDomainVerification_tags(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_null(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_EmptyMap(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{})), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{}), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_AddOnUpdate(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_EmptyTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_EmptyTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + acctest.CtKey2: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + acctest.CtKey2: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_EmptyTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_providerOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1Updated), + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey2: config.StringVariable(acctest.CtValue2), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_nonOverlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1Updated), + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{})), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_overlapping(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtOverlapKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + acctest.CtOverlapKey2: config.StringVariable("providervalue2"), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtOverlapKey2: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtOverlapKey1: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtOverlapKey1: config.StringVariable(acctest.CtResourceValue2), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_updateToProviderOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_updateToResourceOnly(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_emptyResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_emptyProviderOnlyTag(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(""), + }), + acctest.CtResourceTags: nil, + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_nullOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(""), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + acctest.CtTagsKey1, // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_DefaultTags_nullNonOverlappingResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.Null(), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(""), + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_defaults/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: nil, + }), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "tags.resourcekey1", // The canonical value returned by the AWS API is "" + }, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_ComputedTag_OnCreate(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_ComputedTag_OnUpdate_Add(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, "tags.computedkey1", "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(2)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapPartial(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey("computedkey1")), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tagsComputed2/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable("computedkey1"), + "knownTagKey": config.StringVariable(acctest.CtKey1), + "knownTagValue": config.StringVariable(acctest.CtValue1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_ComputedTag_OnUpdate_Replace(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrPair(resourceName, acctest.CtTagsKey1, "null_resource.test", names.AttrID), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapSizeExact(1)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapSizeExact(1)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTags).AtMapKey(acctest.CtKey1)), + plancheck.ExpectUnknownValue(resourceName, tfjsonpath.New(names.AttrTagsAll)), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + }, + }, + }, + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tagsComputed1/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + "unknownTagKey": config.StringVariable(acctest.CtKey1), + }, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_IgnoreTags_Overlap_DefaultTag(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 2: Update ignored tag only + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Updated), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionNoop), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtProviderTags: config.MapVariable(map[string]config.Variable{ + acctest.CtProviderKey1: config.StringVariable(acctest.CtProviderValue1Again), + }), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtProviderKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtProviderKey1: knownvalue.StringExact(acctest.CtProviderValue1), // TODO: Should not be set + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_tags_IgnoreTags_Overlap_ResourceTag(t *testing.T) { + ctx := acctest.Context(t) + + var v vpclattice.GetDomainVerificationOutput + resourceName := "aws_vpclattice_domain_verification.test" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + acctest.ParallelTest(ctx, t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + // 1: Create + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 2: Update ignored tag + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Updated), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + // 3: Update both tags + { + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ConfigDirectory: config.StaticDirectory("testdata/DomainVerification/tags_ignore/"), + ConfigVariables: config.Variables{ + acctest.CtRName: config.StringVariable(rName), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + acctest.CtResourceKey1: config.StringVariable(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: config.StringVariable(acctest.CtResourceValue2Updated), + }), + "ignore_tag_keys": config.SetVariable( + config.StringVariable(acctest.CtResourceKey1), + ), + }, + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &v), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + expectFullResourceTags(ctx, resourceName, knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1), // TODO: Should not be set + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + PostApplyPreRefresh: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), // TODO: Should be NoOp + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey1: knownvalue.StringExact(acctest.CtResourceValue1Again), + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtResourceKey2: knownvalue.StringExact(acctest.CtResourceValue2Updated), + })), + }, + }, + ExpectNonEmptyPlan: true, + }, + }, + }) +} diff --git a/internal/service/vpclattice/domain_verification_test.go b/internal/service/vpclattice/domain_verification_test.go new file mode 100644 index 000000000000..f38208d14c6e --- /dev/null +++ b/internal/service/vpclattice/domain_verification_test.go @@ -0,0 +1,136 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package vpclattice_test + +import ( + "context" + "fmt" + "testing" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/service/vpclattice" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfvpclattice "github.com/hashicorp/terraform-provider-aws/internal/service/vpclattice" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccVPCLatticeDomainVerification_basic(t *testing.T) { + ctx := acctest.Context(t) + var domainVerification vpclattice.GetDomainVerificationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + domainName := fmt.Sprintf("%s.example.com", rName) + resourceName := "aws_vpclattice_domain_verification.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDomainVerificationConfig_basic(domainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &domainVerification), + acctest.MatchResourceAttrRegionalARN(ctx, resourceName, names.AttrARN, "vpc-lattice", regexache.MustCompile(`domainverification/dv-.+`)), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreatedAt), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, domainName), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), + resource.TestCheckResourceAttrSet(resourceName, "txt_record_name"), + resource.TestCheckResourceAttrSet(resourceName, "txt_record_value"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccVPCLatticeDomainVerification_disappears(t *testing.T) { + ctx := acctest.Context(t) + var domainVerification vpclattice.GetDomainVerificationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + domainName := fmt.Sprintf("%s.example.com", rName) + resourceName := "aws_vpclattice_domain_verification.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainVerificationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccDomainVerificationConfig_basic(domainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainVerificationExists(ctx, resourceName, &domainVerification), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfvpclattice.ResourceDomainVerification, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckDomainVerificationDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_vpclattice_domain_verification" { + continue + } + + _, err := tfvpclattice.FindDomainVerificationByID(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("VPCLattice Domain Verification %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccCheckDomainVerificationExists(ctx context.Context, n string, v *vpclattice.GetDomainVerificationOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).VPCLatticeClient(ctx) + + output, err := tfvpclattice.FindDomainVerificationByID(ctx, conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccDomainVerificationConfig_basic(domainName string) string { + return fmt.Sprintf(` +resource "aws_vpclattice_domain_verification" "test" { + domain_name = %[1]q +} +`, domainName) +} diff --git a/internal/service/vpclattice/exports_test.go b/internal/service/vpclattice/exports_test.go index 5906effe9d06..cd71be02d122 100644 --- a/internal/service/vpclattice/exports_test.go +++ b/internal/service/vpclattice/exports_test.go @@ -7,6 +7,7 @@ package vpclattice var ( ResourceAccessLogSubscription = resourceAccessLogSubscription ResourceAuthPolicy = resourceAuthPolicy + ResourceDomainVerification = newDomainVerificationResource ResourceListener = resourceListener ResourceListenerRule = resourceListenerRule ResourceResourceConfiguration = newResourceConfigurationResource @@ -22,6 +23,7 @@ var ( FindAccessLogSubscriptionByID = findAccessLogSubscriptionByID FindAuthPolicyByID = findAuthPolicyByID + FindDomainVerificationByID = findDomainVerificationByID FindListenerByTwoPartKey = findListenerByTwoPartKey FindListenerRuleByThreePartKey = findListenerRuleByThreePartKey FindResourceConfigurationByID = findResourceConfigurationByID diff --git a/internal/service/vpclattice/resource_configuration.go b/internal/service/vpclattice/resource_configuration.go index 105894f747d5..fcc262c962a1 100644 --- a/internal/service/vpclattice/resource_configuration.go +++ b/internal/service/vpclattice/resource_configuration.go @@ -73,7 +73,35 @@ func (r *resourceConfigurationResource) Schema(ctx context.Context, request reso }, }, names.AttrARN: framework.ARNAttributeComputedOnly(), - names.AttrID: framework.IDAttribute(), + "custom_domain_name": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "domain_verification_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain_verification_id": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplaceIfConfigured(), + stringplanmodifier.UseStateForUnknown(), + }, + }, + "domain_verification_status": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.VerificationStatus](), + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrID: framework.IDAttribute(), names.AttrName: schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ @@ -238,6 +266,7 @@ func (r *resourceConfigurationResource) Create(ctx context.Context, request reso // Additional fields. input.ClientToken = aws.String(sdkid.UniqueId()) + input.DomainVerificationIdentifier = fwflex.StringFromFramework(ctx, data.DomainVerificationID) input.ResourceConfigurationGroupIdentifier = fwflex.StringFromFramework(ctx, data.ResourceConfigurationGroupID) input.ResourceGatewayIdentifier = fwflex.StringFromFramework(ctx, data.ResourceGatewayID) input.Tags = getTagsIn(ctx) @@ -495,6 +524,10 @@ type resourceConfigurationResourceModel struct { framework.WithRegionModel AllowAssociationToShareableServiceNetwork types.Bool `tfsdk:"allow_association_to_shareable_service_network"` ARN types.String `tfsdk:"arn"` + CustomDomainName types.String `tfsdk:"custom_domain_name"` + DomainVerificationARN fwtypes.ARN `tfsdk:"domain_verification_arn"` + DomainVerificationID types.String `tfsdk:"domain_verification_id"` + DomainVerificationStatus fwtypes.StringEnum[awstypes.VerificationStatus] `tfsdk:"domain_verification_status"` ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` PortRanges fwtypes.SetOfString `tfsdk:"port_ranges"` diff --git a/internal/service/vpclattice/resource_configuration_test.go b/internal/service/vpclattice/resource_configuration_test.go index 252db6909ba5..51a151f1cbc0 100644 --- a/internal/service/vpclattice/resource_configuration_test.go +++ b/internal/service/vpclattice/resource_configuration_test.go @@ -286,6 +286,46 @@ func TestAccVPCLatticeResourceConfiguration_arnResource(t *testing.T) { }) } +func TestAccVPCLatticeResourceConfiguration_domainVerification(t *testing.T) { + ctx := acctest.Context(t) + var resourceconfiguration vpclattice.GetResourceConfigurationOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + domainName := fmt.Sprintf("%s.example.com", rName) + customDomainName := fmt.Sprintf("test.%s.example.com", rName) + resourceName := "aws_vpclattice_resource_configuration.test" + domainVerificationResourceName := "aws_vpclattice_domain_verification.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.VPCLatticeEndpointID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.VPCLatticeServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResourceConfigurationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResourceConfigurationConfig_domainVerification(rName, domainName, customDomainName), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceConfigurationExists(ctx, resourceName, &resourceconfiguration), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "custom_domain_name", customDomainName), + resource.TestCheckResourceAttrPair(resourceName, "domain_verification_id", domainVerificationResourceName, names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "domain_verification_arn", domainVerificationResourceName, names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "domain_verification_status", string(types.VerificationStatusPending)), + resource.TestCheckResourceAttr(resourceName, "resource_configuration_definition.0.dns_resource.0.domain_name", customDomainName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccVPCLatticeResourceConfiguration_disappears(t *testing.T) { ctx := acctest.Context(t) var resourceconfiguration vpclattice.GetResourceConfigurationOutput @@ -476,18 +516,22 @@ resource "aws_vpclattice_resource_configuration" "test" { } } +data "aws_rds_orderable_db_instance" "test" { + engine = "aurora-postgresql" + engine_latest_version = true + preferred_instance_classes = ["db.serverless"] +} + resource "aws_rds_cluster" "test" { - cluster_identifier = %[1]q - engine = "aurora-postgresql" - engine_mode = "provisioned" - engine_version = "15.4" - database_name = "test" - master_username = "test" - manage_master_user_password = true - enable_http_endpoint = true - vpc_security_group_ids = [aws_security_group.test.id] - skip_final_snapshot = true - db_subnet_group_name = aws_db_subnet_group.test.name + cluster_identifier = %[1]q + master_password = "avoid-plaintext-passwords" + master_username = "tfacctest" + skip_final_snapshot = true + engine = data.aws_rds_orderable_db_instance.test.engine + engine_version = data.aws_rds_orderable_db_instance.test.engine_version + enable_http_endpoint = true + vpc_security_group_ids = [aws_security_group.test.id] + db_subnet_group_name = aws_db_subnet_group.test.name serverlessv2_scaling_configuration { max_capacity = 1.0 @@ -509,3 +553,30 @@ resource "aws_db_subnet_group" "test" { } `, rName)) } + +func testAccResourceConfigurationConfig_domainVerification(rName, domainName, customDomainName string) string { + return acctest.ConfigCompose(testAccResourceGatewayConfig_basic(rName), + fmt.Sprintf(` +resource "aws_vpclattice_domain_verification" "test" { + domain_name = %[2]q +} + +resource "aws_vpclattice_resource_configuration" "test" { + name = %[1]q + + resource_gateway_identifier = aws_vpclattice_resource_gateway.test.id + custom_domain_name = %[3]q + domain_verification_id = aws_vpclattice_domain_verification.test.id + + port_ranges = ["443"] + protocol = "TCP" + + resource_configuration_definition { + dns_resource { + domain_name = %[3]q + ip_address_type = "IPV4" + } + } +} +`, rName, domainName, customDomainName)) +} diff --git a/internal/service/vpclattice/service_package_gen.go b/internal/service/vpclattice/service_package_gen.go index 57313208f26d..45a663caba9b 100644 --- a/internal/service/vpclattice/service_package_gen.go +++ b/internal/service/vpclattice/service_package_gen.go @@ -23,6 +23,15 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*inttypes.S func (p *servicePackage) FrameworkResources(ctx context.Context) []*inttypes.ServicePackageFrameworkResource { return []*inttypes.ServicePackageFrameworkResource{ + { + Factory: newDomainVerificationResource, + TypeName: "aws_vpclattice_domain_verification", + Name: "Domain Verification", + Tags: unique.Make(inttypes.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }), + Region: unique.Make(inttypes.ResourceRegionDefault()), + }, { Factory: newResourceConfigurationResource, TypeName: "aws_vpclattice_resource_configuration", diff --git a/internal/service/vpclattice/testdata/DomainVerification/tags/main_gen.tf b/internal/service/vpclattice/testdata/DomainVerification/tags/main_gen.tf new file mode 100644 index 000000000000..2f7db9167485 --- /dev/null +++ b/internal/service/vpclattice/testdata/DomainVerification/tags/main_gen.tf @@ -0,0 +1,21 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_vpclattice_domain_verification" "test" { + domain_name = "${var.rName}.example.com" + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} diff --git a/internal/service/vpclattice/testdata/DomainVerification/tagsComputed1/main_gen.tf b/internal/service/vpclattice/testdata/DomainVerification/tagsComputed1/main_gen.tf new file mode 100644 index 000000000000..c2aa768f0c4e --- /dev/null +++ b/internal/service/vpclattice/testdata/DomainVerification/tagsComputed1/main_gen.tf @@ -0,0 +1,25 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_vpclattice_domain_verification" "test" { + domain_name = "${var.rName}.example.com" + + tags = { + (var.unknownTagKey) = null_resource.test.id + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} diff --git a/internal/service/vpclattice/testdata/DomainVerification/tagsComputed2/main_gen.tf b/internal/service/vpclattice/testdata/DomainVerification/tagsComputed2/main_gen.tf new file mode 100644 index 000000000000..f893b72bd515 --- /dev/null +++ b/internal/service/vpclattice/testdata/DomainVerification/tagsComputed2/main_gen.tf @@ -0,0 +1,36 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "null" {} + +resource "aws_vpclattice_domain_verification" "test" { + domain_name = "${var.rName}.example.com" + + tags = { + (var.unknownTagKey) = null_resource.test.id + (var.knownTagKey) = var.knownTagValue + } +} + +resource "null_resource" "test" {} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "unknownTagKey" { + type = string + nullable = false +} + +variable "knownTagKey" { + type = string + nullable = false +} + +variable "knownTagValue" { + type = string + nullable = false +} diff --git a/internal/service/vpclattice/testdata/DomainVerification/tags_defaults/main_gen.tf b/internal/service/vpclattice/testdata/DomainVerification/tags_defaults/main_gen.tf new file mode 100644 index 000000000000..3786c0d7a89e --- /dev/null +++ b/internal/service/vpclattice/testdata/DomainVerification/tags_defaults/main_gen.tf @@ -0,0 +1,32 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } +} + +resource "aws_vpclattice_domain_verification" "test" { + domain_name = "${var.rName}.example.com" + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = false +} diff --git a/internal/service/vpclattice/testdata/DomainVerification/tags_ignore/main_gen.tf b/internal/service/vpclattice/testdata/DomainVerification/tags_ignore/main_gen.tf new file mode 100644 index 000000000000..6d4b31e9e07a --- /dev/null +++ b/internal/service/vpclattice/testdata/DomainVerification/tags_ignore/main_gen.tf @@ -0,0 +1,41 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +provider "aws" { + default_tags { + tags = var.provider_tags + } + ignore_tags { + keys = var.ignore_tag_keys + } +} + +resource "aws_vpclattice_domain_verification" "test" { + domain_name = "${var.rName}.example.com" + + tags = var.resource_tags +} + +variable "rName" { + description = "Name for resource" + type = string + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource. To specify no tags, set to `null`" + # Not setting a default, so that this must explicitly be set to `null` to specify no tags + type = map(string) + nullable = true +} + +variable "provider_tags" { + type = map(string) + nullable = true + default = null +} + +variable "ignore_tag_keys" { + type = set(string) + nullable = false +} diff --git a/internal/service/vpclattice/testdata/tmpl/domain_verification_tags.gtpl b/internal/service/vpclattice/testdata/tmpl/domain_verification_tags.gtpl new file mode 100644 index 000000000000..cf2abab5884f --- /dev/null +++ b/internal/service/vpclattice/testdata/tmpl/domain_verification_tags.gtpl @@ -0,0 +1,5 @@ +resource "aws_vpclattice_domain_verification" "test" { + domain_name = "${var.rName}.example.com" + + {{- template "tags" . }} +} diff --git a/internal/service/wafv2/flex.go b/internal/service/wafv2/flex.go index c0809dbf0af3..bf0d59964082 100644 --- a/internal/service/wafv2/flex.go +++ b/internal/service/wafv2/flex.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/flex" tfjson "github.com/hashicorp/terraform-provider-aws/internal/json" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -1141,7 +1141,7 @@ func walkWebACLJSON(v reflect.Value) { case reflect.Slice, reflect.Array: switch reflect.ValueOf(va.outputType).Type().Elem().Kind() { case reflect.Uint8: - base64String := itypes.Base64Encode([]byte(str.(string))) + base64String := inttypes.Base64Encode([]byte(str.(string))) st[va.key] = base64String default: } @@ -1188,7 +1188,7 @@ func walkRulesGroupJSON(v reflect.Value) { case reflect.Slice, reflect.Array: switch reflect.ValueOf(va.outputType).Type().Elem().Kind() { case reflect.Uint8: - base64String := itypes.Base64Encode([]byte(str.(string))) + base64String := inttypes.Base64Encode([]byte(str.(string))) st[va.key] = base64String default: } diff --git a/internal/service/wafv2/ip_set.go b/internal/service/wafv2/ip_set.go index 3e01e46c9191..c2d364f1262b 100644 --- a/internal/service/wafv2/ip_set.go +++ b/internal/service/wafv2/ip_set.go @@ -27,7 +27,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -72,7 +72,7 @@ func resourceIPSet() *schema.Resource { for _, ov := range oldAddresses { hasAddress := false for _, nv := range newAddresses { - if itypes.CIDRBlocksEqual(ov.(string), nv.(string)) { + if inttypes.CIDRBlocksEqual(ov.(string), nv.(string)) { hasAddress = true break } diff --git a/internal/service/wafv2/web_acl_logging_configuration.go b/internal/service/wafv2/web_acl_logging_configuration.go index d97dfceb02e1..a60a35f66d7d 100644 --- a/internal/service/wafv2/web_acl_logging_configuration.go +++ b/internal/service/wafv2/web_acl_logging_configuration.go @@ -148,10 +148,10 @@ func resourceWebACLLoggingConfiguration() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.All( - validation.StringLenBetween(1, 40), + validation.StringLenBetween(1, 64), // The value is returned in lower case by the API. // Trying to solve it with StateFunc and/or DiffSuppressFunc resulted in hash problem of the rule field or didn't work. - validation.StringMatch(regexache.MustCompile(`^[0-9a-z_-]+$`), "must contain only lowercase alphanumeric characters, underscores, and hyphens"), + validation.StringMatch(regexache.MustCompile(`^.*\S.*$`), "Must be any string that contains at least one non-whitespace character"), ), }, }, diff --git a/internal/service/wafv2/web_acl_logging_configuration_test.go b/internal/service/wafv2/web_acl_logging_configuration_test.go index de9bc51f9582..e104bce2f7d0 100644 --- a/internal/service/wafv2/web_acl_logging_configuration_test.go +++ b/internal/service/wafv2/web_acl_logging_configuration_test.go @@ -81,7 +81,7 @@ func TestAccWAFV2WebACLLoggingConfiguration_updateSingleHeaderRedactedField(t *t resource.TestCheckResourceAttr(resourceName, "log_destination_configs.#", "1"), resource.TestCheckResourceAttr(resourceName, "redacted_fields.#", "2"), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "redacted_fields.*", map[string]string{ - "single_header.0.name": "referer", + "single_header.0.name": "sso.csrf", }), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "redacted_fields.*", map[string]string{ "single_header.0.name": "user-agent", @@ -801,7 +801,7 @@ resource "aws_wafv2_web_acl_logging_configuration" "test" { redacted_fields { single_header { - name = "referer" + name = "sso.csrf" } } diff --git a/internal/service/workspaces/directory.go b/internal/service/workspaces/directory.go index 7e481847bea2..5ddd1bd6ecd0 100644 --- a/internal/service/workspaces/directory.go +++ b/internal/service/workspaces/directory.go @@ -23,7 +23,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -706,7 +706,7 @@ func findDirectoryByID(ctx context.Context, conn *workspaces.Client, id string) return nil, err } - if itypes.IsZero(output) { + if inttypes.IsZero(output) { return nil, tfresource.NewEmptyResultError(input) } diff --git a/internal/service/workspaces/workspace.go b/internal/service/workspaces/workspace.go index 22f7dcb2b624..88e8a550a466 100644 --- a/internal/service/workspaces/workspace.go +++ b/internal/service/workspaces/workspace.go @@ -22,7 +22,7 @@ import ( tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" - itypes "github.com/hashicorp/terraform-provider-aws/internal/types" + inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -351,7 +351,7 @@ func findWorkspaceByID(ctx context.Context, conn *workspaces.Client, id string) return nil, err } - if itypes.IsZero(output) { + if inttypes.IsZero(output) { return nil, tfresource.NewEmptyResultError(input) } diff --git a/internal/sweep/register_gen_test.go b/internal/sweep/register_gen_test.go index 9d948704d3b5..3ea4eda45708 100644 --- a/internal/sweep/register_gen_test.go +++ b/internal/sweep/register_gen_test.go @@ -119,6 +119,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/service/neptune" "github.com/hashicorp/terraform-provider-aws/internal/service/neptunegraph" "github.com/hashicorp/terraform-provider-aws/internal/service/networkfirewall" + "github.com/hashicorp/terraform-provider-aws/internal/service/networkflowmonitor" "github.com/hashicorp/terraform-provider-aws/internal/service/networkmanager" "github.com/hashicorp/terraform-provider-aws/internal/service/notifications" "github.com/hashicorp/terraform-provider-aws/internal/service/notificationscontacts" @@ -300,6 +301,7 @@ func registerSweepers() { neptune.RegisterSweepers() neptunegraph.RegisterSweepers() networkfirewall.RegisterSweepers() + networkflowmonitor.RegisterSweepers() networkmanager.RegisterSweepers() notifications.RegisterSweepers() notificationscontacts.RegisterSweepers() diff --git a/internal/tfresource/wait.go b/internal/tfresource/wait.go index 355efc751e9e..ff8b1bd51d4b 100644 --- a/internal/tfresource/wait.go +++ b/internal/tfresource/wait.go @@ -26,6 +26,11 @@ const ( targetStateTrue targetState = "TRUE" ) +const ( + // Required so that we're not returning a zero-value from the `refresh` function + dummy string = "x" +) + // WaitUntil waits for the function `f` to return `true`. // If `f` returns an error, return immediately with that error. // If `timeout` is exceeded before `f` returns `true`, return an error. @@ -39,10 +44,10 @@ func WaitUntil(ctx context.Context, timeout time.Duration, f func(context.Contex } if done { - return "", targetStateTrue, nil + return dummy, targetStateTrue, nil } - return "", targetStateFalse, nil + return dummy, targetStateFalse, nil } stateConf := &retry.StateChangeConfOf[any, targetState]{ diff --git a/internal/types/service_package.go b/internal/types/service_package.go index 95db2ba0065f..3ebd090137a3 100644 --- a/internal/types/service_package.go +++ b/internal/types/service_package.go @@ -144,6 +144,7 @@ type Identity struct { IsCustomInherentRegion bool customInherentRegionParser RegionalCustomInherentRegionIdentityFunc version int64 + sdkv2IdentityUpgraders []schema.IdentityUpgrader } func (i Identity) HasInherentRegion() bool { @@ -166,6 +167,10 @@ func (i Identity) Version() int64 { return i.version } +func (i Identity) SDKv2IdentityUpgraders() []schema.IdentityUpgrader { + return i.sdkv2IdentityUpgraders +} + func (i Identity) CustomInherentRegionParser() RegionalCustomInherentRegionIdentityFunc { return i.customInherentRegionParser } @@ -421,11 +426,6 @@ func RegionalSingletonIdentity(opts ...IdentityOptsFunc) Identity { return identity } -func VersionedIdentity(version int64, base Identity) Identity { - base.version = version - return base -} - type IdentityOptsFunc func(opts *Identity) func WithIdentityDuplicateAttrs(attrs ...string) IdentityOptsFunc { @@ -457,6 +457,18 @@ func WithV6_0SDKv2Fix() IdentityOptsFunc { } } +func WithVersion(version int64) IdentityOptsFunc { + return func(opts *Identity) { + opts.version = version + } +} + +func WithSDKv2IdentityUpgraders(identityUpgraders ...schema.IdentityUpgrader) IdentityOptsFunc { + return func(opts *Identity) { + opts.sdkv2IdentityUpgraders = identityUpgraders + } +} + type ImportIDParser interface { Parse(id string) (string, map[string]string, error) } diff --git a/internal/types/zero.go b/internal/types/zero.go index 979f9c194f52..598319f25767 100644 --- a/internal/types/zero.go +++ b/internal/types/zero.go @@ -7,13 +7,16 @@ import ( "reflect" ) -// IsZero returns true if `v` is `nil`, is a pointer to `nil`, or points to the zero value of `T`. -func IsZero[T any](v *T) bool { - if v == nil { - return true +// IsZero returns true if `v` is the zero value of `T`, `nil`, is a pointer to `nil`, or points to the zero value of `T`. +func IsZero[T any](v T) bool { + val := reflect.ValueOf(v) + val = reflect.Indirect(val) + + if val.Kind() == reflect.Interface { + val = val.Elem() } - if val := reflect.ValueOf(*v); !val.IsValid() || val.IsZero() { + if !val.IsValid() || val.IsZero() { return true } diff --git a/internal/types/zero_test.go b/internal/types/zero_test.go index 09f8061fd877..2ae9bb3b160f 100644 --- a/internal/types/zero_test.go +++ b/internal/types/zero_test.go @@ -12,7 +12,7 @@ type AIsZero struct { Value int } -func TestIsZero(t *testing.T) { +func TestIsZeroPtr(t *testing.T) { t.Parallel() zero := Zero[AIsZero]() @@ -53,6 +53,36 @@ func TestIsZero(t *testing.T) { } } +func TestIsZeroStructValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + Value AIsZero + Expected bool + }{ + "zero value struct": { + Value: AIsZero{}, + Expected: true, + }, + "non-zero value struct": { + Value: AIsZero{Value: 42}, + Expected: false, + }, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := IsZero(testCase.Value) + + if got != testCase.Expected { + t.Errorf("got %t, expected %t", got, testCase.Expected) + } + }) + } +} + func TestIsZeroPointerToAny(t *testing.T) { t.Parallel() @@ -98,3 +128,44 @@ func TestIsZeroPointerToAny(t *testing.T) { }) } } + +func TestIsZeroAnyValue(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + Value any + Expected bool + }{ + "nil value": { + Expected: true, + }, + "zero int value": { + Value: 0, + Expected: true, + }, + "zero string value": { + Value: "", + Expected: true, + }, + "non-zero int value": { + Value: 1, + Expected: false, + }, + "non-zero string value": { + Value: "string", + Expected: false, + }, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := IsZero(testCase.Value) + + if got != testCase.Expected { + t.Errorf("got %t, expected %t", got, testCase.Expected) + } + }) + } +} diff --git a/names/data/names_data.hcl b/names/data/names_data.hcl index 6c0d21b910e6..289f9c46a8fd 100644 --- a/names/data/names_data.hcl +++ b/names/data/names_data.hcl @@ -9276,7 +9276,7 @@ service "ec2" { } resource_prefix { - actual = "aws_(ami|availability_zone|ec2_(availability|capacity|default_credit_specification|fleet|host|instance|public_ipv4_pool|serial|spot|tag)|eip|instance|key_pair|launch_template|placement_group|spot)" + actual = "aws_(ami|availability_zone|ec2_(allowed_images_settings|availability|capacity|default_credit_specification|fleet|host|instance|public_ipv4_pool|serial|spot|tag)|eip|instance|key_pair|launch_template|placement_group|spot)" correct = "aws_ec2_" } @@ -9586,7 +9586,7 @@ service "ec2" { provider_package_correct = "ec2" split_package = "ec2" file_prefix = "ec2_" - doc_prefix = ["ami", "availability_zone", "ec2_availability_", "ec2_capacity_", "ec2_default_credit_specification", "ec2_fleet", "ec2_host", "ec2_image_", "ec2_instance_", "ec2_public_ipv4_pool", "ec2_serial_", "ec2_spot_", "ec2_tag", "eip", "instance", "key_pair", "launch_template", "placement_group", "spot_"] + doc_prefix = ["ami", "availability_zone", "ec2_allowed_images_settings", "ec2_availability_", "ec2_capacity_", "ec2_default_credit_specification", "ec2_fleet", "ec2_host", "ec2_image_", "ec2_instance_", "ec2_public_ipv4_pool", "ec2_serial_", "ec2_spot_", "ec2_tag", "eip", "instance", "key_pair", "launch_template", "placement_group", "spot_"] brand = "Amazon" } diff --git a/skaff/go.mod b/skaff/go.mod index ef80ce60fd61..c0f536e4c554 100644 --- a/skaff/go.mod +++ b/skaff/go.mod @@ -1,9 +1,9 @@ module github.com/hashicorp/terraform-provider-aws/skaff -go 1.24.8 +go 1.24.10 require ( - github.com/YakDriver/regexache v0.24.0 + github.com/YakDriver/regexache v0.25.0 github.com/hashicorp/terraform-provider-aws v1.60.1-0.20220322001452-8f7a597d0c24 github.com/spf13/cobra v1.10.1 ) @@ -19,10 +19,10 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/zclconf/go-cty v1.17.0 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/text v0.30.0 // indirect - golang.org/x/tools v0.38.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/tools v0.39.0 // indirect ) replace github.com/hashicorp/terraform-provider-aws => ../ diff --git a/skaff/go.sum b/skaff/go.sum index 53874600d53d..f754669f011a 100644 --- a/skaff/go.sum +++ b/skaff/go.sum @@ -1,5 +1,5 @@ -github.com/YakDriver/regexache v0.24.0 h1:zUKaixelkswzdqsqPc2sveiV//Mi/msJn0teG8zBDiA= -github.com/YakDriver/regexache v0.24.0/go.mod h1:awcd8uBj614F3ScW06JqlfSGqq2/7vdJHy+RiKzVC+g= +github.com/YakDriver/regexache v0.25.0 h1:uggvmj09EhXQgaXYmdGsKuDARbmdOIqICiO+PIwhlTA= +github.com/YakDriver/regexache v0.25.0/go.mod h1:4xOFrfggN3UAGlhcvNpM/kuedpJL+48DrUs0CcCxPv8= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= @@ -30,13 +30,13 @@ github.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0 github.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/literally/go.mod b/tools/literally/go.mod index e6bccd071b06..560c2f349879 100644 --- a/tools/literally/go.mod +++ b/tools/literally/go.mod @@ -1,3 +1,3 @@ module github.com/hashicorp/terraform-provider-aws/tools/literally -go 1.24.8 +go 1.24.10 diff --git a/tools/tfsdk2fw/go.mod b/tools/tfsdk2fw/go.mod index 09462f0bc4ea..9fefbfb2259d 100644 --- a/tools/tfsdk2fw/go.mod +++ b/tools/tfsdk2fw/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/terraform-provider-aws/tools/tfsdk2fw -go 1.24.8 +go 1.24.10 require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 @@ -13,288 +13,288 @@ require ( github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/YakDriver/go-version v0.1.0 // indirect - github.com/YakDriver/regexache v0.24.0 // indirect - github.com/YakDriver/smarterr v0.7.0 // indirect + github.com/YakDriver/regexache v0.25.0 // indirect + github.com/YakDriver/smarterr v0.8.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go-v2 v1.39.6 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.31.17 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/config v1.31.21 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.25 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.8 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 // indirect - github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.44.10 // indirect - github.com/aws/aws-sdk-go-v2/service/account v1.29.2 // indirect - github.com/aws/aws-sdk-go-v2/service/acm v1.37.11 // indirect - github.com/aws/aws-sdk-go-v2/service/acmpca v1.45.3 // indirect - github.com/aws/aws-sdk-go-v2/service/amp v1.41.1 // indirect - github.com/aws/aws-sdk-go-v2/service/amplify v1.38.3 // indirect - github.com/aws/aws-sdk-go-v2/service/apigateway v1.36.1 // indirect - github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.32.11 // indirect - github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.1 // indirect - github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.10 // indirect - github.com/aws/aws-sdk-go-v2/service/appflow v1.51.1 // indirect - github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.10 // indirect - github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.2 // indirect - github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.9 // indirect - github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.2 // indirect - github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.1 // indirect - github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.3 // indirect - github.com/aws/aws-sdk-go-v2/service/appstream v1.50.4 // indirect - github.com/aws/aws-sdk-go-v2/service/appsync v1.52.1 // indirect - github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.12 // indirect - github.com/aws/aws-sdk-go-v2/service/athena v1.55.10 // indirect - github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.1 // indirect - github.com/aws/aws-sdk-go-v2/service/autoscaling v1.60.3 // indirect - github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/backup v1.49.4 // indirect - github.com/aws/aws-sdk-go-v2/service/batch v1.58.4 // indirect - github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/bedrock v1.48.4 // indirect - github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.1 // indirect - github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.1 // indirect - github.com/aws/aws-sdk-go-v2/service/billing v1.8.4 // indirect - github.com/aws/aws-sdk-go-v2/service/budgets v1.41.1 // indirect - github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.10 // indirect - github.com/aws/aws-sdk-go-v2/service/chime v1.41.1 // indirect - github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.10 // indirect - github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.2 // indirect - github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.1 // indirect - github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.9 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.1 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudformation v1.68.3 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.4 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.12 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.9 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.1 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.53.11 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.1 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.7 // indirect - github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.10 // indirect - github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.2 // indirect - github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.1 // indirect - github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.1 // indirect - github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.9 // indirect - github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.1 // indirect - github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.9 // indirect - github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.9 // indirect - github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.10 // indirect - github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.2 // indirect - github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.10 // indirect - github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.10 // indirect - github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.11 // indirect - github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.10 // indirect - github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.1 // indirect - github.com/aws/aws-sdk-go-v2/service/configservice v1.59.2 // indirect - github.com/aws/aws-sdk-go-v2/service/connect v1.143.3 // indirect - github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.1 // indirect - github.com/aws/aws-sdk-go-v2/service/controltower v1.26.10 // indirect - github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.2 // indirect - github.com/aws/aws-sdk-go-v2/service/costexplorer v1.59.2 // indirect - github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.20.10 // indirect - github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.3 // indirect - github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.58.2 // indirect - github.com/aws/aws-sdk-go-v2/service/databrew v1.39.3 // indirect - github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.3 // indirect - github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.9 // indirect - github.com/aws/aws-sdk-go-v2/service/datasync v1.55.4 // indirect - github.com/aws/aws-sdk-go-v2/service/datazone v1.44.2 // indirect - github.com/aws/aws-sdk-go-v2/service/dax v1.29.5 // indirect - github.com/aws/aws-sdk-go-v2/service/detective v1.38.2 // indirect - github.com/aws/aws-sdk-go-v2/service/devicefarm v1.36.3 // indirect - github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.1 // indirect - github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.3 // indirect - github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.4 // indirect - github.com/aws/aws-sdk-go-v2/service/dlm v1.35.4 // indirect - github.com/aws/aws-sdk-go-v2/service/docdb v1.48.1 // indirect - github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.2 // indirect - github.com/aws/aws-sdk-go-v2/service/drs v1.36.2 // indirect - github.com/aws/aws-sdk-go-v2/service/dsql v1.10.2 // indirect - github.com/aws/aws-sdk-go-v2/service/dynamodb v1.52.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.261.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ecs v1.67.2 // indirect - github.com/aws/aws-sdk-go-v2/service/efs v1.41.2 // indirect - github.com/aws/aws-sdk-go-v2/service/eks v1.74.7 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.1 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.11 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.11 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.51.5 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.11 // indirect - github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.10 // indirect - github.com/aws/aws-sdk-go-v2/service/emr v1.55.4 // indirect - github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.6 // indirect - github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.1 // indirect - github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.10 // indirect - github.com/aws/aws-sdk-go-v2/service/evidently v1.28.9 // indirect - github.com/aws/aws-sdk-go-v2/service/evs v1.5.6 // indirect - github.com/aws/aws-sdk-go-v2/service/finspace v1.33.10 // indirect - github.com/aws/aws-sdk-go-v2/service/firehose v1.42.1 // indirect - github.com/aws/aws-sdk-go-v2/service/fis v1.37.9 // indirect - github.com/aws/aws-sdk-go-v2/service/fms v1.44.10 // indirect - github.com/aws/aws-sdk-go-v2/service/fsx v1.62.4 // indirect - github.com/aws/aws-sdk-go-v2/service/gamelift v1.47.3 // indirect - github.com/aws/aws-sdk-go-v2/service/glacier v1.31.10 // indirect - github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.3 // indirect - github.com/aws/aws-sdk-go-v2/service/glue v1.132.1 // indirect - github.com/aws/aws-sdk-go-v2/service/grafana v1.32.3 // indirect - github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.10 // indirect - github.com/aws/aws-sdk-go-v2/service/groundstation v1.38.2 // indirect - github.com/aws/aws-sdk-go-v2/service/guardduty v1.65.4 // indirect - github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.2 // indirect - github.com/aws/aws-sdk-go-v2/service/iam v1.49.2 // indirect - github.com/aws/aws-sdk-go-v2/service/identitystore v1.33.3 // indirect - github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.48.4 // indirect - github.com/aws/aws-sdk-go-v2/service/inspector v1.30.9 // indirect - github.com/aws/aws-sdk-go-v2/service/inspector2 v1.44.10 // indirect + github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.45.2 // indirect + github.com/aws/aws-sdk-go-v2/service/account v1.29.4 // indirect + github.com/aws/aws-sdk-go-v2/service/acm v1.37.13 // indirect + github.com/aws/aws-sdk-go-v2/service/acmpca v1.46.2 // indirect + github.com/aws/aws-sdk-go-v2/service/amp v1.42.0 // indirect + github.com/aws/aws-sdk-go-v2/service/amplify v1.38.5 // indirect + github.com/aws/aws-sdk-go-v2/service/apigateway v1.37.0 // indirect + github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.0 // indirect + github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.3 // indirect + github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/service/appflow v1.51.3 // indirect + github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.12 // indirect + github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.4 // indirect + github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.11 // indirect + github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.4 // indirect + github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.3 // indirect + github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.5 // indirect + github.com/aws/aws-sdk-go-v2/service/appstream v1.52.1 // indirect + github.com/aws/aws-sdk-go-v2/service/appsync v1.52.3 // indirect + github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.14 // indirect + github.com/aws/aws-sdk-go-v2/service/athena v1.55.12 // indirect + github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.3 // indirect + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.61.0 // indirect + github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.5 // indirect + github.com/aws/aws-sdk-go-v2/service/backup v1.54.0 // indirect + github.com/aws/aws-sdk-go-v2/service/batch v1.58.6 // indirect + github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/service/bedrock v1.49.1 // indirect + github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.3 // indirect + github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.3 // indirect + github.com/aws/aws-sdk-go-v2/service/billing v1.9.0 // indirect + github.com/aws/aws-sdk-go-v2/service/budgets v1.41.3 // indirect + github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.12 // indirect + github.com/aws/aws-sdk-go-v2/service/chime v1.41.3 // indirect + github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.12 // indirect + github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.4 // indirect + github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.3 // indirect + github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.11 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.3 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.70.0 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudfront v1.56.2 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.14 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.11 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.3 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.54.0 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.3 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.60.0 // indirect + github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.12 // indirect + github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.4 // indirect + github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.3 // indirect + github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.3 // indirect + github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.11 // indirect + github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.3 // indirect + github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.11 // indirect + github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.11 // indirect + github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.12 // indirect + github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.4 // indirect + github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.12 // indirect + github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.12 // indirect + github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.13 // indirect + github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.12 // indirect + github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.3 // indirect + github.com/aws/aws-sdk-go-v2/service/configservice v1.59.4 // indirect + github.com/aws/aws-sdk-go-v2/service/connect v1.146.0 // indirect + github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.3 // indirect + github.com/aws/aws-sdk-go-v2/service/controltower v1.27.2 // indirect + github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.4 // indirect + github.com/aws/aws-sdk-go-v2/service/costexplorer v1.60.0 // indirect + github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.21.0 // indirect + github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.5 // indirect + github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.60.0 // indirect + github.com/aws/aws-sdk-go-v2/service/databrew v1.39.5 // indirect + github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.5 // indirect + github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.11 // indirect + github.com/aws/aws-sdk-go-v2/service/datasync v1.55.6 // indirect + github.com/aws/aws-sdk-go-v2/service/datazone v1.48.0 // indirect + github.com/aws/aws-sdk-go-v2/service/dax v1.29.7 // indirect + github.com/aws/aws-sdk-go-v2/service/detective v1.38.4 // indirect + github.com/aws/aws-sdk-go-v2/service/devicefarm v1.37.0 // indirect + github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.3 // indirect + github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.5 // indirect + github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.6 // indirect + github.com/aws/aws-sdk-go-v2/service/dlm v1.35.6 // indirect + github.com/aws/aws-sdk-go-v2/service/docdb v1.48.3 // indirect + github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.4 // indirect + github.com/aws/aws-sdk-go-v2/service/drs v1.36.4 // indirect + github.com/aws/aws-sdk-go-v2/service/dsql v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.272.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.53.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ecs v1.68.0 // indirect + github.com/aws/aws-sdk-go-v2/service/efs v1.41.4 // indirect + github.com/aws/aws-sdk-go-v2/service/eks v1.74.9 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.3 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.13 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.13 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.53.0 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.13 // indirect + github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.12 // indirect + github.com/aws/aws-sdk-go-v2/service/emr v1.56.0 // indirect + github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.8 // indirect + github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.3 // indirect + github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.12 // indirect + github.com/aws/aws-sdk-go-v2/service/evidently v1.28.11 // indirect + github.com/aws/aws-sdk-go-v2/service/evs v1.5.8 // indirect + github.com/aws/aws-sdk-go-v2/service/finspace v1.33.12 // indirect + github.com/aws/aws-sdk-go-v2/service/firehose v1.42.3 // indirect + github.com/aws/aws-sdk-go-v2/service/fis v1.37.11 // indirect + github.com/aws/aws-sdk-go-v2/service/fms v1.44.12 // indirect + github.com/aws/aws-sdk-go-v2/service/fsx v1.64.0 // indirect + github.com/aws/aws-sdk-go-v2/service/gamelift v1.48.2 // indirect + github.com/aws/aws-sdk-go-v2/service/glacier v1.31.12 // indirect + github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.5 // indirect + github.com/aws/aws-sdk-go-v2/service/glue v1.133.0 // indirect + github.com/aws/aws-sdk-go-v2/service/grafana v1.32.5 // indirect + github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.12 // indirect + github.com/aws/aws-sdk-go-v2/service/groundstation v1.39.2 // indirect + github.com/aws/aws-sdk-go-v2/service/guardduty v1.68.0 // indirect + github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.4 // indirect + github.com/aws/aws-sdk-go-v2/service/iam v1.52.0 // indirect + github.com/aws/aws-sdk-go-v2/service/identitystore v1.34.2 // indirect + github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.49.0 // indirect + github.com/aws/aws-sdk-go-v2/service/inspector v1.30.11 // indirect + github.com/aws/aws-sdk-go-v2/service/inspector2 v1.45.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.11.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 // indirect - github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.2 // indirect - github.com/aws/aws-sdk-go-v2/service/invoicing v1.6.12 // indirect - github.com/aws/aws-sdk-go-v2/service/iot v1.69.9 // indirect - github.com/aws/aws-sdk-go-v2/service/ivs v1.48.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.9 // indirect - github.com/aws/aws-sdk-go-v2/service/kafka v1.44.3 // indirect - github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.10 // indirect - github.com/aws/aws-sdk-go-v2/service/kendra v1.60.10 // indirect - github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.3 // indirect - github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.1 // indirect - github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.10 // indirect - github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.11 // indirect - github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.9 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.47.1 // indirect - github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.9 // indirect - github.com/aws/aws-sdk-go-v2/service/lambda v1.81.1 // indirect - github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.10 // indirect - github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.3 // indirect - github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.56.10 // indirect - github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.10 // indirect - github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.4 // indirect - github.com/aws/aws-sdk-go-v2/service/location v1.50.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.4 // indirect + github.com/aws/aws-sdk-go-v2/service/invoicing v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/iot v1.69.11 // indirect + github.com/aws/aws-sdk-go-v2/service/ivs v1.48.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.11 // indirect + github.com/aws/aws-sdk-go-v2/service/kafka v1.46.0 // indirect + github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.12 // indirect + github.com/aws/aws-sdk-go-v2/service/kendra v1.60.12 // indirect + github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.3 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.12 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.13 // indirect + github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.11 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.48.2 // indirect + github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.11 // indirect + github.com/aws/aws-sdk-go-v2/service/lambda v1.82.0 // indirect + github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.12 // indirect + github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.5 // indirect + github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.57.0 // indirect + github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.12 // indirect + github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.6 // indirect + github.com/aws/aws-sdk-go-v2/service/location v1.50.4 // indirect github.com/aws/aws-sdk-go-v2/service/lookoutmetrics v1.37.2 // indirect - github.com/aws/aws-sdk-go-v2/service/m2 v1.26.3 // indirect - github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.2 // indirect - github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.45.4 // indirect - github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.84.1 // indirect - github.com/aws/aws-sdk-go-v2/service/medialive v1.85.3 // indirect - github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.10 // indirect - github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.32.3 // indirect - github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.10 // indirect - github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.10 // indirect - github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.3 // indirect - github.com/aws/aws-sdk-go-v2/service/mgn v1.38.2 // indirect - github.com/aws/aws-sdk-go-v2/service/mq v1.34.8 // indirect - github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.10 // indirect - github.com/aws/aws-sdk-go-v2/service/neptune v1.43.1 // indirect - github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.9 // indirect - github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.57.5 // indirect - github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.10.3 // indirect - github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.3 // indirect - github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.2 // indirect - github.com/aws/aws-sdk-go-v2/service/notifications v1.7.8 // indirect - github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.12 // indirect - github.com/aws/aws-sdk-go-v2/service/oam v1.23.3 // indirect - github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.4 // indirect - github.com/aws/aws-sdk-go-v2/service/odb v1.5.4 // indirect - github.com/aws/aws-sdk-go-v2/service/opensearch v1.52.10 // indirect - github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.2 // indirect - github.com/aws/aws-sdk-go-v2/service/organizations v1.46.2 // indirect - github.com/aws/aws-sdk-go-v2/service/osis v1.21.3 // indirect - github.com/aws/aws-sdk-go-v2/service/outposts v1.57.4 // indirect - github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.1 // indirect - github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.10 // indirect - github.com/aws/aws-sdk-go-v2/service/pcs v1.14.4 // indirect - github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.10 // indirect - github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.0 // indirect - github.com/aws/aws-sdk-go-v2/service/pipes v1.23.9 // indirect - github.com/aws/aws-sdk-go-v2/service/polly v1.54.3 // indirect - github.com/aws/aws-sdk-go-v2/service/pricing v1.40.3 // indirect - github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.10 // indirect + github.com/aws/aws-sdk-go-v2/service/m2 v1.26.5 // indirect + github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.4 // indirect + github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.46.0 // indirect + github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.85.0 // indirect + github.com/aws/aws-sdk-go-v2/service/medialive v1.87.0 // indirect + github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.12 // indirect + github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.33.0 // indirect + github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.12 // indirect + github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.12 // indirect + github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.5 // indirect + github.com/aws/aws-sdk-go-v2/service/mgn v1.38.4 // indirect + github.com/aws/aws-sdk-go-v2/service/mq v1.34.10 // indirect + github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.12 // indirect + github.com/aws/aws-sdk-go-v2/service/neptune v1.43.3 // indirect + github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.11 // indirect + github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.58.0 // indirect + github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.11.0 // indirect + github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.5 // indirect + github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/notifications v1.7.10 // indirect + github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.14 // indirect + github.com/aws/aws-sdk-go-v2/service/oam v1.23.5 // indirect + github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.6 // indirect + github.com/aws/aws-sdk-go-v2/service/odb v1.5.6 // indirect + github.com/aws/aws-sdk-go-v2/service/opensearch v1.54.0 // indirect + github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.4 // indirect + github.com/aws/aws-sdk-go-v2/service/organizations v1.46.4 // indirect + github.com/aws/aws-sdk-go-v2/service/osis v1.21.5 // indirect + github.com/aws/aws-sdk-go-v2/service/outposts v1.57.6 // indirect + github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.3 // indirect + github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.12 // indirect + github.com/aws/aws-sdk-go-v2/service/pcs v1.15.0 // indirect + github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.12 // indirect + github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.2 // indirect + github.com/aws/aws-sdk-go-v2/service/pipes v1.23.11 // indirect + github.com/aws/aws-sdk-go-v2/service/polly v1.54.5 // indirect + github.com/aws/aws-sdk-go-v2/service/pricing v1.40.5 // indirect + github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.12 // indirect github.com/aws/aws-sdk-go-v2/service/qldb v1.32.2 // indirect - github.com/aws/aws-sdk-go-v2/service/quicksight v1.95.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ram v1.34.11 // indirect - github.com/aws/aws-sdk-go-v2/service/rbin v1.26.11 // indirect - github.com/aws/aws-sdk-go-v2/service/rds v1.108.7 // indirect - github.com/aws/aws-sdk-go-v2/service/redshift v1.59.5 // indirect - github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.10 // indirect - github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.13 // indirect - github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.9 // indirect - github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.2 // indirect - github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.4 // indirect - github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.12 // indirect - github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.30.11 // indirect - github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.10 // indirect - github.com/aws/aws-sdk-go-v2/service/route53 v1.59.3 // indirect - github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.8 // indirect - github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.10 // indirect - github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.3 // indirect - github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.10 // indirect - github.com/aws/aws-sdk-go-v2/service/route53resolver v1.40.10 // indirect - github.com/aws/aws-sdk-go-v2/service/rum v1.29.2 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2 // indirect - github.com/aws/aws-sdk-go-v2/service/s3control v1.66.7 // indirect - github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3tables v1.10.9 // indirect - github.com/aws/aws-sdk-go-v2/service/s3vectors v1.4.12 // indirect - github.com/aws/aws-sdk-go-v2/service/sagemaker v1.219.1 // indirect - github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.9 // indirect - github.com/aws/aws-sdk-go-v2/service/schemas v1.34.1 // indirect - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.11 // indirect - github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.2 // indirect - github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.2 // indirect - github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.1 // indirect - github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.1 // indirect - github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.10 // indirect - github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.14 // indirect - github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ses v1.34.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sfn v1.39.11 // indirect - github.com/aws/aws-sdk-go-v2/service/shield v1.34.10 // indirect - github.com/aws/aws-sdk-go-v2/service/signer v1.31.10 // indirect - github.com/aws/aws-sdk-go-v2/service/sns v1.39.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sqs v1.42.13 // indirect - github.com/aws/aws-sdk-go-v2/service/ssm v1.66.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.9 // indirect - github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.10 // indirect - github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect - github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect - github.com/aws/aws-sdk-go-v2/service/swf v1.33.4 // indirect - github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.2 // indirect - github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.10 // indirect - github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.4 // indirect - github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.3 // indirect - github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.9 // indirect - github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.4 // indirect - github.com/aws/aws-sdk-go-v2/service/transfer v1.67.4 // indirect - github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.29.9 // indirect - github.com/aws/aws-sdk-go-v2/service/vpclattice v1.19.4 // indirect - github.com/aws/aws-sdk-go-v2/service/waf v1.30.9 // indirect - github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.10 // indirect - github.com/aws/aws-sdk-go-v2/service/wafv2 v1.68.4 // indirect - github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.10 // indirect - github.com/aws/aws-sdk-go-v2/service/workmail v1.36.8 // indirect - github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.2 // indirect - github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.33.3 // indirect - github.com/aws/aws-sdk-go-v2/service/xray v1.36.9 // indirect + github.com/aws/aws-sdk-go-v2/service/quicksight v1.96.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ram v1.34.13 // indirect + github.com/aws/aws-sdk-go-v2/service/rbin v1.26.13 // indirect + github.com/aws/aws-sdk-go-v2/service/rds v1.109.0 // indirect + github.com/aws/aws-sdk-go-v2/service/redshift v1.60.0 // indirect + github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.12 // indirect + github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.15 // indirect + github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.11 // indirect + github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.4 // indirect + github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.6 // indirect + github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.14 // indirect + github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.0 // indirect + github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.12 // indirect + github.com/aws/aws-sdk-go-v2/service/route53 v1.60.0 // indirect + github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.10 // indirect + github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.12 // indirect + github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.5 // indirect + github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.12 // indirect + github.com/aws/aws-sdk-go-v2/service/route53resolver v1.41.0 // indirect + github.com/aws/aws-sdk-go-v2/service/rum v1.30.0 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.91.0 // indirect + github.com/aws/aws-sdk-go-v2/service/s3control v1.66.9 // indirect + github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.3 // indirect + github.com/aws/aws-sdk-go-v2/service/s3tables v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/s3vectors v1.5.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sagemaker v1.224.0 // indirect + github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.12 // indirect + github.com/aws/aws-sdk-go-v2/service/schemas v1.34.3 // indirect + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.0 // indirect + github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.4 // indirect + github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.4 // indirect + github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.3 // indirect + github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.12 // indirect + github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.16 // indirect + github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ses v1.34.11 // indirect + github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sfn v1.40.0 // indirect + github.com/aws/aws-sdk-go-v2/service/shield v1.34.12 // indirect + github.com/aws/aws-sdk-go-v2/service/signer v1.31.12 // indirect + github.com/aws/aws-sdk-go-v2/service/sns v1.39.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sqs v1.42.15 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.67.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.11 // indirect + github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.12 // indirect + github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.11 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.8 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 // indirect + github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.0 // indirect + github.com/aws/aws-sdk-go-v2/service/swf v1.33.6 // indirect + github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.4 // indirect + github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.6 // indirect + github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.5 // indirect + github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.11 // indirect + github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.6 // indirect + github.com/aws/aws-sdk-go-v2/service/transfer v1.67.6 // indirect + github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.30.2 // indirect + github.com/aws/aws-sdk-go-v2/service/vpclattice v1.20.2 // indirect + github.com/aws/aws-sdk-go-v2/service/waf v1.30.11 // indirect + github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.12 // indirect + github.com/aws/aws-sdk-go-v2/service/wafv2 v1.70.0 // indirect + github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.12 // indirect + github.com/aws/aws-sdk-go-v2/service/workmail v1.36.10 // indirect + github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.4 // indirect + github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.34.0 // indirect + github.com/aws/aws-sdk-go-v2/service/xray v1.36.11 // indirect github.com/aws/smithy-go v1.23.2 // indirect github.com/beevik/etree v1.6.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/cedar-policy/cedar-go v1.2.9 // indirect + github.com/cedar-policy/cedar-go v1.3.0 // indirect github.com/cloudflare/circl v1.6.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fatih/color v1.18.0 // indirect @@ -317,6 +317,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-set/v3 v3.0.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hc-install v0.9.2 // indirect @@ -364,14 +365,14 @@ require ( go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect - golang.org/x/crypto v0.43.0 // indirect + golang.org/x/crypto v0.44.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/mod v0.29.0 // indirect - golang.org/x/net v0.46.0 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.37.0 // indirect - golang.org/x/text v0.30.0 // indirect - golang.org/x/tools v0.38.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/tools v0.39.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/grpc v1.75.1 // indirect diff --git a/tools/tfsdk2fw/go.sum b/tools/tfsdk2fw/go.sum index 52c69fe9a0df..22d7ca64ff76 100644 --- a/tools/tfsdk2fw/go.sum +++ b/tools/tfsdk2fw/go.sum @@ -12,10 +12,10 @@ github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBi github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/YakDriver/go-version v0.1.0 h1:/x+Xg2+l89Mjtxl0VRf2+ue8cnHkw6jfYv49j6f7gZw= github.com/YakDriver/go-version v0.1.0/go.mod h1:LXwFAp1E3KBhS7FHO/FE8r3XCmvKizs/VXXXFWfoSYY= -github.com/YakDriver/regexache v0.24.0 h1:zUKaixelkswzdqsqPc2sveiV//Mi/msJn0teG8zBDiA= -github.com/YakDriver/regexache v0.24.0/go.mod h1:awcd8uBj614F3ScW06JqlfSGqq2/7vdJHy+RiKzVC+g= -github.com/YakDriver/smarterr v0.7.0 h1:LHL/ke6J4NdjsiHASLzn3V1Bt4Ra+t8t+c22WBiOiQo= -github.com/YakDriver/smarterr v0.7.0/go.mod h1:tF8iZvoX2SHQIEk5Ttj+jnLe3jb2JGQ4ag8JkuYZE7Y= +github.com/YakDriver/regexache v0.25.0 h1:uggvmj09EhXQgaXYmdGsKuDARbmdOIqICiO+PIwhlTA= +github.com/YakDriver/regexache v0.25.0/go.mod h1:4xOFrfggN3UAGlhcvNpM/kuedpJL+48DrUs0CcCxPv8= +github.com/YakDriver/smarterr v0.8.0 h1:U4GZytxw/js/2hzoyg94S341sC8PuD0CV5dEBRurZPs= +github.com/YakDriver/smarterr v0.8.0/go.mod h1:tF8iZvoX2SHQIEk5Ttj+jnLe3jb2JGQ4ag8JkuYZE7Y= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= @@ -27,14 +27,14 @@ github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+X github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3 h1:DHctwEM8P8iTXFxC/QK0MRjwEpWQeM9yzidCRjldUz0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.3/go.mod h1:xdCzcZEtnSTKVDOmUZs4l/j3pSV6rpo1WXl5ugNsL8Y= -github.com/aws/aws-sdk-go-v2/config v1.31.17 h1:QFl8lL6RgakNK86vusim14P2k8BFSxjvUkcWLDjgz9Y= -github.com/aws/aws-sdk-go-v2/config v1.31.17/go.mod h1:V8P7ILjp/Uef/aX8TjGk6OHZN6IKPM5YW6S78QnRD5c= -github.com/aws/aws-sdk-go-v2/credentials v1.18.21 h1:56HGpsgnmD+2/KpG0ikvvR8+3v3COCwaF4r+oWwOeNA= -github.com/aws/aws-sdk-go-v2/credentials v1.18.21/go.mod h1:3YELwedmQbw7cXNaII2Wywd+YY58AmLPwX4LzARgmmA= +github.com/aws/aws-sdk-go-v2/config v1.31.21 h1:gH/y+NphLGIVuNHXNkTQir3PmL44Efe8OpPAsbDms0o= +github.com/aws/aws-sdk-go-v2/config v1.31.21/go.mod h1:P6I8guuLej6F2++fKUlo9OIhI59LuEsyEZZMMmgqh/4= +github.com/aws/aws-sdk-go-v2/credentials v1.18.25 h1:MvtSN3ECsQbgEHcux1pZQhuMjZnShlsqcS0Pqlan4Vw= +github.com/aws/aws-sdk-go-v2/credentials v1.18.25/go.mod h1:YATyDPzlHucr1cxEE9rsZl7ZG3gQsxpjD6o5of/8qXE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3 h1:4GNV1lhyELGjMz5ILMRxDvxvOaeo3Ux9Z69S1EgVMMQ= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.3/go.mod h1:br7KA6edAAqDGUYJ+zVVPAyMrPhnN+zdt17yTUT6FPw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.8 h1:R1Ws+p6Gyk0mdVvMI8zruUFnqaFouKKKDOdadtKbHbI= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.8/go.mod h1:VPrEBa+zT9J2x+HHdeq5SwTMd7tbhcBQH3sYPiKORfY= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY= @@ -43,256 +43,256 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEG github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13 h1:eg/WYAa12vqTphzIdWMzqYRVKKnCboVPRlvaybNCqPA= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.13/go.mod h1:/FDdxWhz1486obGrKKC1HONd7krpk38LBt+dutLcN9k= -github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.44.10 h1:e9IzNA2eWkeSsVWP+PqSPIit+YUyd7dE0FNmWcbDWSg= -github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.44.10/go.mod h1:iATSoxt/SEINLDvYHe5N9/UDnc45vngRxRJYr2MqGO0= -github.com/aws/aws-sdk-go-v2/service/account v1.29.2 h1:u+Sq9gnWQmTug7OOnr/kGR4g0V7RAIn/YAX66vYPjp0= -github.com/aws/aws-sdk-go-v2/service/account v1.29.2/go.mod h1:3LbGl+sLnaiyCVp2LJXj0gEoeV2Uw0QOsDpP1gDMBVA= -github.com/aws/aws-sdk-go-v2/service/acm v1.37.11 h1:oQgvxk0+83+EVZYsea3QysBDcrXffPG4UcnBfI2XD7M= -github.com/aws/aws-sdk-go-v2/service/acm v1.37.11/go.mod h1:v8E4cAu0qIxpS7IokQilQb60A8IODPxo82VxVtJ+Dgo= -github.com/aws/aws-sdk-go-v2/service/acmpca v1.45.3 h1:+9/8gDU+vK4MDNYL4bDYEkqdoKqAthD7GifEroL2GtU= -github.com/aws/aws-sdk-go-v2/service/acmpca v1.45.3/go.mod h1:rpBWGq3UUlrgtAwNMy+I9ZoGgbiCoy30QetJZtI6+1A= -github.com/aws/aws-sdk-go-v2/service/amp v1.41.1 h1:Mkao9rWXSWKXnPswpRQrOQl9LlW+zLQcelJkSMPv0jI= -github.com/aws/aws-sdk-go-v2/service/amp v1.41.1/go.mod h1:uwNPmGivmh+4kJecS8OuYtMQTeZCGoBxdLLAGv+13r0= -github.com/aws/aws-sdk-go-v2/service/amplify v1.38.3 h1:gzDbuRQ+3TgZDtqU6YkdumaGIco5X/v0SEST4FNe2hU= -github.com/aws/aws-sdk-go-v2/service/amplify v1.38.3/go.mod h1:ieZIB8x+q5G3azy9SUtyGzGxXGHCVsTK4YvnADiCBZQ= -github.com/aws/aws-sdk-go-v2/service/apigateway v1.36.1 h1:IdikGPwXSRpybGY5QFf3VBJe7qjojVGwEhs6T1U7YCI= -github.com/aws/aws-sdk-go-v2/service/apigateway v1.36.1/go.mod h1:9tT261wkl3uME2BWp/a3nzGNe9BM7jLWZdrXW1eX3BA= -github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.32.11 h1:FGTcpVtiTMti0vWIptgncvP4gCDKfj7MIfdlbq0UCxQ= -github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.32.11/go.mod h1:vr6hE/YGoQQa8PPwsB1uKt9wHjNZZcbXN+ww6lBXVhY= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.1 h1:gSrJ9yZe7oRHSGWKn+68//iQ1DS/RhNVqGcAVhC6VH8= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.1/go.mod h1:rvGHrN6a1lCypZrV0gDsJNPP5w51XIzr6manLptGnZg= -github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.10 h1:8BzTiju+0ULXjDwnLgC+aVG1ka7s7vyvnZLFjoSQ0FM= -github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.10/go.mod h1:EFrW9OOrllIDc/Rg/aUpaWnK81C2VVxhtFt9XUmM4kQ= -github.com/aws/aws-sdk-go-v2/service/appflow v1.51.1 h1:xsMtmgeovHNBxoIsPy9FHWNbYz+6OitWpn/iocBu5gc= -github.com/aws/aws-sdk-go-v2/service/appflow v1.51.1/go.mod h1:bjux2H0bZSqK50RnMXHMr1eBi6Uw6gJmTeDOvFk7w14= -github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.10 h1:kI2+k9m0GMNAjKLpmnvyEDjglzVFayw/cJOEBA1ptKc= -github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.10/go.mod h1:FrNhRSko1IPmuXPB8ldLs3nRkjjONG3E7ZE5nnV0snE= -github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.2 h1:zZ6TJ93crR09QVPxqoFJnlioltKejaPLxY1dCcBjU20= -github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.2/go.mod h1:BDzrZs53Hsb5MyAICN2dmtFWaeLONzMaseXyF9Bagt0= -github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.9 h1:siRXiihD1QrredolQOogo3LIUT2IxG7VGaf96MS1XjQ= -github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.9/go.mod h1:2Sln2mubGkQTNc86N2eobz6KhGrHatsr4lVoIkUwrhQ= -github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.2 h1:YYAuZMyQyL7AgqqIltetNMMFrk3eITn9tk7wOzopPYI= -github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.2/go.mod h1:5Il7eB5oblkNf9V8ugOpPwA6ZARgTzld7otDTumO2w4= -github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.1 h1:jh5RzCpaQUpcUkxM+SYgacL+idKvMXYQTHmcQDYwZGg= -github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.1/go.mod h1:xcEbbUjLqajeslIydrSJhESXNlGMtfXmu7MLY6ONlzY= -github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.3 h1:MY0ipQXQ3c++MZtnY7pF1uHu2vByFEoCUun/5zIjPmk= -github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.3/go.mod h1:rI1byQGgb9tUXBvo3uLFrRXRzaCJayw+CiqAnDgYSKw= -github.com/aws/aws-sdk-go-v2/service/appstream v1.50.4 h1:cq3Q4bOTAgzMjfj8iWP0A4/abnykkXbuK0yk8US254I= -github.com/aws/aws-sdk-go-v2/service/appstream v1.50.4/go.mod h1:flCm0TnAjuMbHs8YaGjVjQjUUsa5EP5O6nC4Zpt080E= -github.com/aws/aws-sdk-go-v2/service/appsync v1.52.1 h1:Vj314J7fmfo5XY1dI19d/4qo4r8cpyf565b7hFLYUBU= -github.com/aws/aws-sdk-go-v2/service/appsync v1.52.1/go.mod h1:uCcHMGXa27Gp8b/hlAI0JbqmXeZp16E2FDWNz5nX0cQ= -github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.12 h1:dVoHETeQsZucFnY+jaTctpzLZsLc9wHolJNCEQRCaJw= -github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.12/go.mod h1:PyPhpvZGkGYZTeuYRlPwZTgBx93EUYtHdpPbiIlY7Q8= -github.com/aws/aws-sdk-go-v2/service/athena v1.55.10 h1:lhHg2H2XeRix8Zk2UKxsJXKk93066CAZCw0x5pMRvDw= -github.com/aws/aws-sdk-go-v2/service/athena v1.55.10/go.mod h1:1bY3ff3w7nTDnyGgOAOEZpO7e7bUiG2iDM2tXbCzxjg= -github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.1 h1:wF8gPnNk6r2PHV7lX/Bc0PLksQ7ehy8xnECyBhxsoBo= -github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.1/go.mod h1:6U6XFWocDXxVtEZsjDajhNtAxNJzZRs9k7CJHuTMJCY= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.60.3 h1:63i7taIpNPPncOc1tXoArX6KkFFXiHNZugaPuFPrbMw= -github.com/aws/aws-sdk-go-v2/service/autoscaling v1.60.3/go.mod h1:6E1AiecbY52kVBl8lKkdaO759rbGK3TBBBNnfxJezTM= -github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.3 h1:Pubm5Z15HT7TxjIlCe0Wi1yez4GC2TVD8IkfHHdoA0M= -github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.3/go.mod h1:NkStIqURmzgUVyoB3YkmU1HUtIPECrExIastd5QbXIk= -github.com/aws/aws-sdk-go-v2/service/backup v1.49.4 h1:v30l5443w7l8CGmKNeoeIZE1dBvO5psDUuoC6RqGElM= -github.com/aws/aws-sdk-go-v2/service/backup v1.49.4/go.mod h1:Sqiqu5Ws64P9IYY+0mQ4OafDKK1LK6sRWQqw89dZZYA= -github.com/aws/aws-sdk-go-v2/service/batch v1.58.4 h1:teElXpUfGCUfrGmHzA+BDmfq/bjD2c1MDG/Uq4P0dEQ= -github.com/aws/aws-sdk-go-v2/service/batch v1.58.4/go.mod h1:zaUBHLEVy5UjLlFt996XZMXLza3teA7f0IhAoV7+3mg= -github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.3 h1:7GGp+4HcHUEhJMc+Io7vUEQFIKvuYwcH0Y2nk3YQN/w= -github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.3/go.mod h1:PJ5iWye10CA9cYAeVL4RUSkZvAwVK/WrOnTSHLztNAI= -github.com/aws/aws-sdk-go-v2/service/bedrock v1.48.4 h1:ZxjMilNfgm+do1eXsU13DE34OIS/IRFudJrZBkKzNdo= -github.com/aws/aws-sdk-go-v2/service/bedrock v1.48.4/go.mod h1:xJ84P+JCcEkzkMjqBKmImWl/zlwEwBmbjc9QR+tcACQ= -github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.1 h1:qgWo/BbdHN80+PUEWxv3D+ppvEfkx5gqSiKKnGriodM= -github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.1/go.mod h1:R5jkUdemrZt6+90gq4JFyxHKldEMH88F6wdxquDLa4Q= -github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.1 h1:g/lzCCkLOkmcJLsAC/a6jvQ+26rKB5e5nj/TGJRbHag= -github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.1/go.mod h1:MvhjtEWL5RO1w6AMrt4d9k//kZxZUsLrTSipRM9Q0/8= -github.com/aws/aws-sdk-go-v2/service/billing v1.8.4 h1:Y/f33Wdef0k3l+tTrKigBAGSGS8w7U10MQHxTQ6d7jM= -github.com/aws/aws-sdk-go-v2/service/billing v1.8.4/go.mod h1:7WI9oHeKA76HgGtTaUeKToGO/rRH9/fx7WLCw1QLJt4= -github.com/aws/aws-sdk-go-v2/service/budgets v1.41.1 h1:Xvc3wK1+jcLmXWLeKbluJJvtQA/Ql8Bt5VzdjcEVAM0= -github.com/aws/aws-sdk-go-v2/service/budgets v1.41.1/go.mod h1:wjQL1whunmAT3ZhqQGZq0lPGNmU27Uu8RjGmT12wLNg= -github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.10 h1:M1TeQUGe3K6yRVrWjbzQWtPZzL0YCjXE67ZuXHq9As0= -github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.10/go.mod h1:H9eUeKMZNHJnd/zKD3Ga0xyk6da+LDSFMZfOw2Wz45E= -github.com/aws/aws-sdk-go-v2/service/chime v1.41.1 h1:44oVq8c++c/LV12VId21rnnp8VOsYeUHIDzcFbAJqiU= -github.com/aws/aws-sdk-go-v2/service/chime v1.41.1/go.mod h1:NL5o86salGH/wxYiFkrzG6K8/GGPGdUNYXS00LCoNr4= -github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.10 h1:hsizZupHqOY/a4kXJqo/kgkjPwHxptt4ethWPxIVk58= -github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.10/go.mod h1:ykYGKe/rWysRsTmMJcq5VvqFzViL4XqsHke2UMh4ok0= -github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.2 h1:duYgiNtiFVrcq1TAo4LhaMeALa1+7uy7rqCgm94nS7w= -github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.2/go.mod h1:xjd2Oeftl4VNXrNTaEBSpwu4cKUDo82FQL9eHunFDqU= -github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.1 h1:9Up9lk52f4JwQTTneROfVm9cm4T4ZMiI4P6l9Racla4= -github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.1/go.mod h1:q9yJkMo4u5vpFAExN0Vtw+ChYDwq0hsSrD9DDE5Sd8w= -github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.9 h1:m5cYYOu2qNdLlejq9xAzJYnqEiUdCt34AXUl0C9Lt30= -github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.9/go.mod h1:kyuiuFhvDWwqLGNWmwbIr/amPIFQWrA7KkbxRQvP0JU= -github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.1 h1:JdROcIIy8NsG5yoAZgr8zya8khelwZEkiQhC+2qwnLM= -github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.1/go.mod h1:6kx+wmHMUP1fQBUpXN2N9xRt2sQUlloxwyF5cMIvDOc= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.68.3 h1:H4jVDatTYCt6WSG7oC0dlZl8kfKHT2anADHQiQI1HVo= -github.com/aws/aws-sdk-go-v2/service/cloudformation v1.68.3/go.mod h1:llucikq1Q6I1Ps8rNV3St0bOY5RQMxYh1lpCaskyhPw= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.4 h1:jjgrc81F2h7KlpeN/g/B8QzQDIbaVIuh3u+Ibl/UZY8= -github.com/aws/aws-sdk-go-v2/service/cloudfront v1.55.4/go.mod h1:UtP1sSXq2FHHO7Lvn4mNplFS4x7oP4+uMIJIQ8+3JyY= -github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.12 h1:sL/TJmTThdewOJDczZuuosnifzbbzmgYeCWCrVXLI4Q= -github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.12/go.mod h1:yFxrWxlbxnTilFCsiViY+x3qnKqi1CGdSPfEWYnwh6Q= -github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.9 h1:iJ6l2NdE1LElrAgnGbmh1Uw9H/sh+s5b/IgP6Vg5080= -github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.9/go.mod h1:w13K+4E6mjE6m5w3tDBZCs+S0zUiAse7M3qZg5ugecw= -github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.1 h1:rREW79PiTjRnFfB+x6ReyYYfb2eplnYbuEQZDhgudS0= -github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.1/go.mod h1:6hxErkN8bbEtojNMVdGQPpL7j9+A/QKL+eDljfRIKMM= -github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.53.11 h1:GqRfk8acdUn5kBmq6RlN98PIUAhe1uiKVEFQ8Wqg+tg= -github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.53.11/go.mod h1:yPef5Em35Sb/89IIHAOarpsld8EuxyxuDVDlHj32LVA= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.1 h1:mgk+V5mDNGDTpawxzS0GyjTDbcmD2Db/IpIxVuIJaTM= -github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.1/go.mod h1:KSWhI1V5x80r8NUqs8QDkOazDolFqFUAjsyE5nYjKro= -github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.7 h1:Yj4NvoEEdSxA90x/uCBskzeF3OxZr72Yaf64n0fIVR4= -github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.58.7/go.mod h1:9/Q0/HtqBTLMksFse42wZjUq0jJrUuo4XlnXy/uSoeg= -github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.10 h1:iHbgvCKy+QOWwxoi27E0cvScKANkdJ4QVUvtPKPX9b8= -github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.10/go.mod h1:9R9pEHnoKOjLs5dDREGyV1Ui2kWZgPPKz0VZd3juZhY= -github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.2 h1:6YCT7dAWUWd9uNWnXatVCNDYMCKOilv//1ZbH42MtbE= -github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.2/go.mod h1:LAT1SFMRPN1z4wewG4PHazKs2xL+J59saaAJQfZj8rc= -github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.1 h1:Cx+3UeTRF9nUgqmK73ee+pfqC/xU62WlMEp4u9sKkoo= -github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.1/go.mod h1:160q+ylvlYKq6c8wufCHYeX4Qei0IC509n4hxlh8oVA= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.1 h1:HKp8jj94R8WmgseHjmKH8weZKHiI2pgfZ+7yh0z9BRs= -github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.1/go.mod h1:jZuIO2m8qmy6VFTQgB/8bTb72o+X4zLRfnu1PubtriM= -github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.9 h1:eDbt/ZpY/TD/SZwREHwIOUVCtxOIDtP0D9r+RiG6QDw= -github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.9/go.mod h1:MMDcKcUGX6vTU6iI4+JFF486CGygY/COEldYNSdQDFQ= -github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.1 h1:XXE1+yxobGTQ8u6kOfIzKkjlY9GKZO9ym/qB4HSwof8= -github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.1/go.mod h1:t9VTnwqOH9QaIWz+NXLMpV68Q983qdWH+ol+4pXATI8= -github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.9 h1:JurZxcGvXRgMUcXQX/64fQ6gbX4Fs5EuFtdKoxqZxtg= -github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.9/go.mod h1:TTz1x8GSLqG2xw5I6ZPs0nm9Ro8W/D44MyeffDYxXnE= -github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.9 h1:F57knV0os9MQqwt7AesU/SG9VDKcgKgTEfIz9S+Q7fI= -github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.9/go.mod h1:KysZ41BGS0TjTmMIu6v0jIOKSlmhACK+7NnZOytrqC4= -github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.10 h1:Bjyew34SxxjAQnijpd14fGGO+2KnILO/AQzVJblX4B4= -github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.10/go.mod h1:COTp2TtxyTD6Pm7H6mKieN+Q0TmccQhJnfxD6//JPtg= -github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.2 h1:dnPgXfBdVf0Mz/tqnmLTihGUbpttUnfcWDy074QiaOo= -github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.2/go.mod h1:QOzDyBkE0ODl/dOuwpcSdMDz/8mz2i+KbwE8hSTUxKo= -github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.10 h1:12f0ZP5XkV4O7RIYz/wpuhaxLP6s7+J75OpqB83eous= -github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.10/go.mod h1:9+D52LzbRUGdyzwB/AMLPi4ydjtSeFkCSloB6Tw7bq0= -github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.10 h1:Lx1tOt8Zo9onYJQ2vhwnXjgIESysOiJ65bx9PaYPCcc= -github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.10/go.mod h1:ahZYJFutez0db6zWQyLWNddBtDDGovvOShiUTnOYPPw= -github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.11 h1:zuNz0zPOh6yOwwuh7tO9dvfcy/fTVkvLL0S99c2XbYo= -github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.11/go.mod h1:NLRVISwN4NcFEWz8WN5kySbgN1g8hjYPR2cZD9Of3Rg= -github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.10 h1:Ky+u5qntJYl4vzaYAgut7Ww55fKUmO3hI1Bu7FUze7M= -github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.10/go.mod h1:QY56Tp8KUNsipLdUdWGTwNg76WXpos4Q4Bbw51i2KS0= -github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.1 h1:jwDn2p79HGHHZhn6PXU5Ur0zXTB2LTtH3EnmpujoTmU= -github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.1/go.mod h1:PzK50LObvBt9Mb2YxwsocMuck07wSMSR+eVU9CiV05M= -github.com/aws/aws-sdk-go-v2/service/configservice v1.59.2 h1:wLYrBB2bdNXCBHq2C4wSTUAOsbwpiOVYyK5gyPDwsbc= -github.com/aws/aws-sdk-go-v2/service/configservice v1.59.2/go.mod h1:8pBCQK4k6Qpff8QKM6gcCt2ZsluQFsNtNaa8ouEZLFc= -github.com/aws/aws-sdk-go-v2/service/connect v1.143.3 h1:lSoAUDJAEnZAJSlsB3htA89N04NKXp/aVzZjqHXbapg= -github.com/aws/aws-sdk-go-v2/service/connect v1.143.3/go.mod h1:4S/3f30iB9LArrLNHVRw/IWyGEGturV5Z5DF1rp3NsE= -github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.1 h1:QOS9GlCgEsug3XViTkdqJoP+aViiZO3jbqDogK9gYhs= -github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.1/go.mod h1:g0V7qnDiTliogqzfAiJrhrOAEKnY+XY3u7/FJ8sZEYU= -github.com/aws/aws-sdk-go-v2/service/controltower v1.26.10 h1:TIwjU2ujMh/xeGPhcdgkbSgD86rmX3/GOP99eNofkgU= -github.com/aws/aws-sdk-go-v2/service/controltower v1.26.10/go.mod h1:ZQuFo9/qnryEiHaDdXGo0pgsC+uHYHheHzGq+Vem8xM= -github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.2 h1:VivnMRlCTwLehgTM35HkCvDMtazOjR5qOBk5p2WIfA8= -github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.2/go.mod h1:z4Y8J/t7ktcqMxLtf4korP74Tg42Ov97FjuTDyFfJKw= -github.com/aws/aws-sdk-go-v2/service/costexplorer v1.59.2 h1:3gpBCMGemT7ICVav0yQfdPILVB5MDRL7D2C4XmD/QV0= -github.com/aws/aws-sdk-go-v2/service/costexplorer v1.59.2/go.mod h1:sP89eC3imDzTgMk/N+gDwDqjeQgLLEt0PuU5NMBHBCo= -github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.20.10 h1:pNn0agq67d7sF4zJ/bYHZkjK63W6UD4L85TCw55crxc= -github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.20.10/go.mod h1:Ouo0lXAlK9jTlJeMt6LTL+G6kKOfoK7xks0TT5AwdlQ= -github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.3 h1:eGd3TjGC98p5rxEVxmm9eKZyGX7o9xbGrMxUvwu7oEk= -github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.3/go.mod h1:86sgcd46latOOSvQKbctenNsiEHnow3vip0OnwSqC54= -github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.58.2 h1:bND6tXqyuCENQ4BgPnbZ/5uk52O8yVQ9VA5YiGpMUFM= -github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.58.2/go.mod h1:Sc22CT1GPF61n0yJdqquFNvqoyfnQCZ+WS7Uz8daW8c= -github.com/aws/aws-sdk-go-v2/service/databrew v1.39.3 h1:ysxZXq5UtMgacfeGErqwFZs4drcWfaRMfwTUi0TfaOk= -github.com/aws/aws-sdk-go-v2/service/databrew v1.39.3/go.mod h1:hu5s2BoJ9fqmyMoVVvYbAtTFOFg8lsr4TzgJnK58n2Q= -github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.3 h1:x3vzuW2JGtQWQocjYze9CScsxRQNs2eVlwhs4BDlYPQ= -github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.3/go.mod h1:rwA2QoV4mz3TSrr4QirNyAndfs3EmwbVrGx5nMtTdz0= -github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.9 h1:P3xC2HzI0AnETmQsyrWhgAVXKEHTRP9TwOz46/yOOl4= -github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.9/go.mod h1:WZjvFO/jWbSRaxdkTmbL5GZu1HmPV2+DrDFmUCH0BKk= -github.com/aws/aws-sdk-go-v2/service/datasync v1.55.4 h1:eV3CXCf6TDigPN8CpRt7p7i7h1EY4Er27yhN+vGvbvQ= -github.com/aws/aws-sdk-go-v2/service/datasync v1.55.4/go.mod h1:35IO7OkYfIGQJeJ8IOFN7dPrregYgMMxBlSGpR0dEj8= -github.com/aws/aws-sdk-go-v2/service/datazone v1.44.2 h1:GJKRpQurAmu+9R+j5WcuI4DAxLVkH4rFUQWLPUKrS2k= -github.com/aws/aws-sdk-go-v2/service/datazone v1.44.2/go.mod h1:ELpY+QIvAO5sH048NMmxDNMDuAKWbRmHCl0rrNR4V5s= -github.com/aws/aws-sdk-go-v2/service/dax v1.29.5 h1:UD59qdhdH1RTlRLID1KSJJGkP+X1Sji54rzP3k2A4EY= -github.com/aws/aws-sdk-go-v2/service/dax v1.29.5/go.mod h1:LqCHisA88LmdWAT7R/FsvLksZZs7ghdIUwZsZSu0xKs= -github.com/aws/aws-sdk-go-v2/service/detective v1.38.2 h1:artDNBhcGdZ0/GWj0EdpRKOXA3eKsHY9PqNmxwOd1Ts= -github.com/aws/aws-sdk-go-v2/service/detective v1.38.2/go.mod h1:cOhEIcmxoL4V4Uavp0LRUV30gYNTGiTd2G0/ECJlIls= -github.com/aws/aws-sdk-go-v2/service/devicefarm v1.36.3 h1:OOp6MY+hT8jc0vRKkK2xzI14dwoXenBPXYwy/nej+yI= -github.com/aws/aws-sdk-go-v2/service/devicefarm v1.36.3/go.mod h1:DOlSchQTITKhdLgShZBymT+x+kX6jSJx8ArGf2jvFVs= -github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.1 h1:mO8u1KoFx9MVe4Rp85NzUU6TZEAf4atrFrW86HOAjso= -github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.1/go.mod h1:pOx5GDFaf6hXYuvqq18r+Op5BCfuMuZKX2ZJgacqWNk= -github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.3 h1:884G69tdukkk8RYH73soxXPRzvjpSnzdoTPCVhYQ1v0= -github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.3/go.mod h1:ozhPmvMQlk6trPDKahoaHUUEzmgiRxuHjXMWqdBy/Is= -github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.4 h1:EgIG6rQdKZ3X/1c9H/1H1RKWVxFtY11b8C6MI72iVp4= -github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.4/go.mod h1:yv/LQu/I+t1HsDl5wBlBxhnFDmLe8sk+6EkFW1WTb10= -github.com/aws/aws-sdk-go-v2/service/dlm v1.35.4 h1:E6WM979VZjTY9Sxp24HXXKcPlulwXaBuWWoXrJN+6K0= -github.com/aws/aws-sdk-go-v2/service/dlm v1.35.4/go.mod h1:rP4rq5uek/rreEV2CzUzGPNcD36+ZLDeh9HzyxePFnE= -github.com/aws/aws-sdk-go-v2/service/docdb v1.48.1 h1:MBuwuulakbiHZ9SNHqdjfd95B3ie5yBVtPDLfQPajCo= -github.com/aws/aws-sdk-go-v2/service/docdb v1.48.1/go.mod h1:13D9OjKPmSXbWE+20zVYaesIuFSUtx1pEouI2hu8yp0= -github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.2 h1:S5Ym+nCmNuX+Mxlu1C57hpM2kRa/KMFhfJyI/ms+/fA= -github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.2/go.mod h1:GXVZTuVYCRQvfLiT+fKmnXLYap5xGTfz+UD47bxJEKE= -github.com/aws/aws-sdk-go-v2/service/drs v1.36.2 h1:HVo+k9ttPnGpjZS/4nGhifrltoGF8ytKBTUF+XPBt4M= -github.com/aws/aws-sdk-go-v2/service/drs v1.36.2/go.mod h1:qO9+wcb7meZj7R8VQd8QnHb+ZPRWdODsexKGr3ru7cA= -github.com/aws/aws-sdk-go-v2/service/dsql v1.10.2 h1:YhtJu0sZ3gFAix8M25aUS5tEVuoeN0Kp8qWQ0aURK0A= -github.com/aws/aws-sdk-go-v2/service/dsql v1.10.2/go.mod h1:qAIMlh9aATA3n6dbs3aHQD7MOCAN8km548KABpaxqUs= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.52.4 h1:5nhomXR6eve564BfKNb/2wvBJGicjXHOFW9++Y6jwRg= -github.com/aws/aws-sdk-go-v2/service/dynamodb v1.52.4/go.mod h1:6eUUnWOJ8sucL5Uk8rPkFo8FYioM0CTNGHga8hwzXVc= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.261.1 h1:1U9Is5mKIIgi8xlIZi5Apuq/SHnQrKUBmmRm4tmgLYM= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.261.1/go.mod h1:NDdDLLW5PtLLXN661gKcvJvqAH5OBXsfhMlmKVu1/pY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2 h1:aq2N/9UkbEyljIQ7OFcudEgUsJzO8MYucmfsM/k/dmc= -github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2/go.mod h1:1NVD1KuMjH2GqnPwMotPndQaT/MreKkWpjkF12d6oKU= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2 h1:9fe6w8bydUwNAhFVmjo+SRqAJjbBMOyILL/6hTTVkyA= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2/go.mod h1:x7gU4CAyAz4BsM9hlRkhHiYw2GIr1QCmN45uwQw9l/E= -github.com/aws/aws-sdk-go-v2/service/ecs v1.67.2 h1:oeICOX/+D0XXV1aMYJPXVe3CO37zYr7fB6HFgxchleU= -github.com/aws/aws-sdk-go-v2/service/ecs v1.67.2/go.mod h1:rrhqfkXfa2DSNq0RyFhnnFEAyI+yJB4+2QlZKeJvMjs= -github.com/aws/aws-sdk-go-v2/service/efs v1.41.2 h1:WlttNCWA42RoH3U2QASpq+5JkVZTnjAHt8Hpu4I/kQs= -github.com/aws/aws-sdk-go-v2/service/efs v1.41.2/go.mod h1:ddWcpZJhvKugMHfwzBsq3dtaBLH7PsTgtAyiL3BEdxo= -github.com/aws/aws-sdk-go-v2/service/eks v1.74.7 h1:dqNrMBr+8NrKNXUN3h88HLwJWDGSV3h7HgCFqItJ+MM= -github.com/aws/aws-sdk-go-v2/service/eks v1.74.7/go.mod h1:xHVz3A2oEVl3UzjCOSEz/fBeBoFrS6FJ3cc/jo0WLyM= -github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.1 h1:qlldII+DFEDZKZtFj9laRO4YBkgiTaSuOmccIoExeD8= -github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.1/go.mod h1:m21nBoJHIHVbICAgJgvaZuO2AEfamKO53hl05xQ1ZUQ= -github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.11 h1:cGWsx/MXgjg84MJnyNQ7Ety6KpLkGe200DvhXyUtm5Q= -github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.11/go.mod h1:V3Yl2vXro/+nzAmexAXOc1GdkTmEE+UHp0YMuTn5G5k= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.11 h1:99Ju2tMSx8pkNvGVSXLyL6yy7juXfCxcl8vL5gAtvZQ= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.11/go.mod h1:ImGbJ8W4fb8KZekLSWCnuuabYN5WusCD7cnW4Nz7i14= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.51.5 h1:g8zncADOBZ34APoawN/iZcYAZ0/mVtGGeaDPz5URqDU= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.51.5/go.mod h1:Uyo8wjqYyZaHVqoe+APHe4+THRGv4pctJzItYYnRe5Q= -github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.11 h1:i+GKaGY+1ci+/bm9jptCBtg27JUbHlPMbf/xaku5Cs0= -github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.11/go.mod h1:GXyWYhCWYQQhGzxzNDU6CRL++zIsBgguWJFTa/iTOqI= -github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.10 h1:4SaTltdS17HyE0Q48Dcki6iHc30hgDuC5qdMPbeXlrw= -github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.10/go.mod h1:hV8KFAz+flqQ0eHBEJYGU4NWzTqQBtrRyqVwfm3Gi2Q= -github.com/aws/aws-sdk-go-v2/service/emr v1.55.4 h1:D5+t3h3vXOnX2FAJUe1p1L0fu300ITpME6u0rvmJF7k= -github.com/aws/aws-sdk-go-v2/service/emr v1.55.4/go.mod h1:NZatCe1XK65DogTuEG2emmEN3NIZtwLsXtJzWpkqSx0= -github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.6 h1:RAXe6pdT2rI1CWsgMCt2gYmioPL+slLtk81hQXkRwuk= -github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.6/go.mod h1:ncWhqV69Tim5BrNp98qdJfLvlD/WwCs5X3lBPgV62rs= -github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.1 h1:KgTxH206wAPdbi7IhYWKI1KEeUehUHqXtM1FfBxi7nI= -github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.1/go.mod h1:osVEDevOxiptmGI1/Q3CCm0FFIRf0MhwnWoL8Br0Pso= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.10 h1:BI56PI2i1CE0czMJZ6OFk8jde6nPmFWktkDDna5yXvE= -github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.10/go.mod h1:WVMQLFJTxCpu7h7eKnItFtVWitmVRJLsHTbZFYOmkTs= -github.com/aws/aws-sdk-go-v2/service/evidently v1.28.9 h1:sHHMo7xRH9RC95aKrZyT//yV074EdDN2LVMQx2grt88= -github.com/aws/aws-sdk-go-v2/service/evidently v1.28.9/go.mod h1:3Dt+ChkPyMq1eJTpXmBu4AUtsXN0oqfYph09KNICC6Q= -github.com/aws/aws-sdk-go-v2/service/evs v1.5.6 h1:02QX83EWnWb+Zeil0XFWMXQQTsjHOjEPBReHSpnkhlw= -github.com/aws/aws-sdk-go-v2/service/evs v1.5.6/go.mod h1:/IUqdRVJhNRM7OjN7cdlxnM2j+nuf8b1C6j20YzKTeg= -github.com/aws/aws-sdk-go-v2/service/finspace v1.33.10 h1:d/06SukYzwzgYuN077Qc10hD9MpY89yjSB4WotY2wmo= -github.com/aws/aws-sdk-go-v2/service/finspace v1.33.10/go.mod h1:L9hrtvHZKfvGwvP3rZcNgaZhhH0QWarqvcuw66JUqR8= -github.com/aws/aws-sdk-go-v2/service/firehose v1.42.1 h1:SxuqmmRvQ0+vB5MjEB73Jo5PvRFMoHU3Zfv+80IhOkI= -github.com/aws/aws-sdk-go-v2/service/firehose v1.42.1/go.mod h1:tHbE62j5gxIYxqmus+zqDQEZama0aWmglUnAk5+lAUs= -github.com/aws/aws-sdk-go-v2/service/fis v1.37.9 h1:CKtEPx1xCQrRUHDLpkaX43ga3PhYNYNHmCPPph4IRt0= -github.com/aws/aws-sdk-go-v2/service/fis v1.37.9/go.mod h1:Ja2eowkEbK8dfjWqxg96k4lkVjnf7YTUpEtQKHflynQ= -github.com/aws/aws-sdk-go-v2/service/fms v1.44.10 h1:XiI/s24q/w2CI+NP9LtGKv5vmdAII8N9O8GhJaLOa/4= -github.com/aws/aws-sdk-go-v2/service/fms v1.44.10/go.mod h1:qKGD0P+Hxcbq4w6Q6PUrDDLd0C2PcgwLtIS2BT6+2yo= -github.com/aws/aws-sdk-go-v2/service/fsx v1.62.4 h1:urTv0bEKWU6bDfz9jF/yTq7CaCyBox6Xjmz/F20itbk= -github.com/aws/aws-sdk-go-v2/service/fsx v1.62.4/go.mod h1:MCyHv+eBeciHOldY/pOKwp7j02Jo2HS1cpvThq2hSqs= -github.com/aws/aws-sdk-go-v2/service/gamelift v1.47.3 h1:AFP5CCk1aJNd463CIx25u4NsBxScLlS3vUkG28ptDWQ= -github.com/aws/aws-sdk-go-v2/service/gamelift v1.47.3/go.mod h1:dcVPaAeS/WE1PQeOldz0EuPud1gttdoQXajAKhNf0rE= -github.com/aws/aws-sdk-go-v2/service/glacier v1.31.10 h1:x7Qw8EiMW/0TSujhbsy4txAu3GbuiAJvq50cuog2FGI= -github.com/aws/aws-sdk-go-v2/service/glacier v1.31.10/go.mod h1:qkG1pn5qsa79Ovau5ZJ3DpYa9Ar534RyQU8PjjMalCM= -github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.3 h1:JjzgrGBK+CXE2zQVlyjld1h3qc5VXlLxQmDTHfHGu4I= -github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.3/go.mod h1:La9wJnRUasTkBLOLqH2JVrApk1WG0vui4MVyr+rGS8Y= -github.com/aws/aws-sdk-go-v2/service/glue v1.132.1 h1:GgPCZotTW5wWrro7+hotCARLuI9UP1Gyjcf2s9W3evM= -github.com/aws/aws-sdk-go-v2/service/glue v1.132.1/go.mod h1:KBo/tKQu4KUTMQ88jWZR79PNgEeDCD8QrO8oMmAq8ng= -github.com/aws/aws-sdk-go-v2/service/grafana v1.32.3 h1:Wn3sl9tIorquSK0fPeMFXnNCJ1pB4zwuxpKzMTlNA9c= -github.com/aws/aws-sdk-go-v2/service/grafana v1.32.3/go.mod h1:6tjVI48fzvjSAKY486cvKQPNeuIcV5YULNlFyAPZ+UU= -github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.10 h1:gLoXDwLQNoj9h71oUE0SYrXWqfpyznjD3fqD6OYSsqA= -github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.10/go.mod h1:wXnnE8KHU07d8VHPGTibk+Kx2TXFaCsL92wJoPPvCvM= -github.com/aws/aws-sdk-go-v2/service/groundstation v1.38.2 h1:NATc0n6+15TgtrhO/xopKCELOiukzX5dRbJV809b6BI= -github.com/aws/aws-sdk-go-v2/service/groundstation v1.38.2/go.mod h1:mg5Mut9Q671xNH+VvfaPBVvS4U9vLw1R5wz4bJvPjd4= -github.com/aws/aws-sdk-go-v2/service/guardduty v1.65.4 h1:a8ni6rPoSFzTITPXH3Uy1HAEKd78QHMNSjkp+P+5pXQ= -github.com/aws/aws-sdk-go-v2/service/guardduty v1.65.4/go.mod h1:U8kxZNr/dDtSqvr9L8e+fyqVmU/BNyI9fKWAatpu1CE= -github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.2 h1:4rQFhJ0j1ifbwFQKY/QDR4eNcQk3T1tDoN7M/mBApT0= -github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.2/go.mod h1:1GUJHZK3s9RIYhn/cLwh5/08/EfcnpCllSHWeJ23nVg= -github.com/aws/aws-sdk-go-v2/service/iam v1.49.2 h1:XeF6yEMX4/FxoSHCE1VNMOZ0t+mGnf/onqVe9dDVAlQ= -github.com/aws/aws-sdk-go-v2/service/iam v1.49.2/go.mod h1:cuEMbL1mNtO1sUyT+DYDNIA8Y7aJG1oIdgHqUk29Uzk= -github.com/aws/aws-sdk-go-v2/service/identitystore v1.33.3 h1:LeDRkqRXONJ1bxBAGuB0kRp1v2PrEIRYiXMqCKVmF5A= -github.com/aws/aws-sdk-go-v2/service/identitystore v1.33.3/go.mod h1:uuQmaV23i5w+5Jy2XFnquY0Z41iR6oDDdu+Sqz6bsNg= -github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.48.4 h1:J30DLdOosZDh9zwmWrFQffBVaHenpPy2oa/AqH5UmXE= -github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.48.4/go.mod h1:VD7bLCk88KQgyRB+yIQH9BNmtmSpwgRQ0Q7Wp1bsCuk= -github.com/aws/aws-sdk-go-v2/service/inspector v1.30.9 h1:e1WIoRDAyFSsxs4qGlDexK5MiPAWaBgn+7cobyLfnYk= -github.com/aws/aws-sdk-go-v2/service/inspector v1.30.9/go.mod h1:Ce8Iac726mzXgIOgFkMllAZsgb5XTOjzC5og1vPkHu0= -github.com/aws/aws-sdk-go-v2/service/inspector2 v1.44.10 h1:Ljs2y3qmx4eimm97ZtmJEBr4qDCbG7vhIcaCTdV7qZ8= -github.com/aws/aws-sdk-go-v2/service/inspector2 v1.44.10/go.mod h1:btzexzBLvYxamIptsxWMmHhXXx/FFmdKGgH96IM6HE8= +github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.45.2 h1:Ako32TEdYnL79+slzTDOFxdSKhltoWcjkNxPWz9X/M4= +github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.45.2/go.mod h1:iATSoxt/SEINLDvYHe5N9/UDnc45vngRxRJYr2MqGO0= +github.com/aws/aws-sdk-go-v2/service/account v1.29.4 h1:qrptW0Zqnc3O0fjjfmBDtJPRaNH+qY47txKwRhXQ67A= +github.com/aws/aws-sdk-go-v2/service/account v1.29.4/go.mod h1:3LbGl+sLnaiyCVp2LJXj0gEoeV2Uw0QOsDpP1gDMBVA= +github.com/aws/aws-sdk-go-v2/service/acm v1.37.13 h1:5AUX6KOEBF20wiIaiI4fKHvVkELEptyLtRTbWGpNQNY= +github.com/aws/aws-sdk-go-v2/service/acm v1.37.13/go.mod h1:v8E4cAu0qIxpS7IokQilQb60A8IODPxo82VxVtJ+Dgo= +github.com/aws/aws-sdk-go-v2/service/acmpca v1.46.2 h1:mBl0TQb13preknTDjHWbanhl1BveYfF1QES/YverKlQ= +github.com/aws/aws-sdk-go-v2/service/acmpca v1.46.2/go.mod h1:rpBWGq3UUlrgtAwNMy+I9ZoGgbiCoy30QetJZtI6+1A= +github.com/aws/aws-sdk-go-v2/service/amp v1.42.0 h1:eBxruXVqrfytiVJIqxGVW4kGlbxlsCasNa5GZgcTgZ4= +github.com/aws/aws-sdk-go-v2/service/amp v1.42.0/go.mod h1:uwNPmGivmh+4kJecS8OuYtMQTeZCGoBxdLLAGv+13r0= +github.com/aws/aws-sdk-go-v2/service/amplify v1.38.5 h1:uqG80MBs+aYwh6V2bpD3p4EAN3+23H9zDF+kyQNmbgo= +github.com/aws/aws-sdk-go-v2/service/amplify v1.38.5/go.mod h1:ieZIB8x+q5G3azy9SUtyGzGxXGHCVsTK4YvnADiCBZQ= +github.com/aws/aws-sdk-go-v2/service/apigateway v1.37.0 h1:yGW8ujCEpbex84kfx9KL6HkzfSC3pTiUOwNgrCB/Tek= +github.com/aws/aws-sdk-go-v2/service/apigateway v1.37.0/go.mod h1:9tT261wkl3uME2BWp/a3nzGNe9BM7jLWZdrXW1eX3BA= +github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.0 h1:jFWRglDVLlQcANMwsdFp/lJ6RAsc/mFLopFlTw9IeXs= +github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.33.0/go.mod h1:vr6hE/YGoQQa8PPwsB1uKt9wHjNZZcbXN+ww6lBXVhY= +github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.3 h1:CiSitRcp8P68+JoA9cNuBL6H2cdDtNr1w1pkHyRXFKE= +github.com/aws/aws-sdk-go-v2/service/appconfig v1.43.3/go.mod h1:rvGHrN6a1lCypZrV0gDsJNPP5w51XIzr6manLptGnZg= +github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.12 h1:CKuViUgkrDY63niR+Jg2UBylJOSOrMx83NbOFKT0I7o= +github.com/aws/aws-sdk-go-v2/service/appfabric v1.16.12/go.mod h1:EFrW9OOrllIDc/Rg/aUpaWnK81C2VVxhtFt9XUmM4kQ= +github.com/aws/aws-sdk-go-v2/service/appflow v1.51.3 h1:lmeUBk1pCMxqGNhlp1bpAMLzelZsqVh6YEQw5kJffMU= +github.com/aws/aws-sdk-go-v2/service/appflow v1.51.3/go.mod h1:bjux2H0bZSqK50RnMXHMr1eBi6Uw6gJmTeDOvFk7w14= +github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.12 h1:Mpl2kD1mBc6fegNiwcRzp8FjgDZ97fbaEafbDXF9xqk= +github.com/aws/aws-sdk-go-v2/service/appintegrations v1.36.12/go.mod h1:FrNhRSko1IPmuXPB8ldLs3nRkjjONG3E7ZE5nnV0snE= +github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.4 h1:YjpBB2PGZSl6WRhmgzLMMdvY5FIpWPQ/oVThQd6uX3M= +github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.41.4/go.mod h1:BDzrZs53Hsb5MyAICN2dmtFWaeLONzMaseXyF9Bagt0= +github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.11 h1:EcnZjQKet6JnsXwj2tw1gfvesNmnfGfvwuzWMZIxTfM= +github.com/aws/aws-sdk-go-v2/service/applicationinsights v1.34.11/go.mod h1:2Sln2mubGkQTNc86N2eobz6KhGrHatsr4lVoIkUwrhQ= +github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.4 h1:t4DkpLlx64Dyv5ttJNfjuQCtXA4jwygnPic3u6SHeqg= +github.com/aws/aws-sdk-go-v2/service/applicationsignals v1.17.4/go.mod h1:5Il7eB5oblkNf9V8ugOpPwA6ZARgTzld7otDTumO2w4= +github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.3 h1:IsdFy0YkFhSo1nPjw9WcPpm3joGCEH1pLnXuLkAV2X0= +github.com/aws/aws-sdk-go-v2/service/appmesh v1.35.3/go.mod h1:xcEbbUjLqajeslIydrSJhESXNlGMtfXmu7MLY6ONlzY= +github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.5 h1:+fyOW8hT7uLzKQgkmKeqyq6Z8Y4+qiGsAOvbXYXmpdQ= +github.com/aws/aws-sdk-go-v2/service/apprunner v1.39.5/go.mod h1:rI1byQGgb9tUXBvo3uLFrRXRzaCJayw+CiqAnDgYSKw= +github.com/aws/aws-sdk-go-v2/service/appstream v1.52.1 h1:wP/OGyNS8YMeNf1nqNMl3zPkyl3Vp2UJ171ykt2Vkvc= +github.com/aws/aws-sdk-go-v2/service/appstream v1.52.1/go.mod h1:flCm0TnAjuMbHs8YaGjVjQjUUsa5EP5O6nC4Zpt080E= +github.com/aws/aws-sdk-go-v2/service/appsync v1.52.3 h1:ANP9cl/DMLE1BewJU7eg25Ipq2gdrBtzd3k7nIcfq3A= +github.com/aws/aws-sdk-go-v2/service/appsync v1.52.3/go.mod h1:uCcHMGXa27Gp8b/hlAI0JbqmXeZp16E2FDWNz5nX0cQ= +github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.14 h1:wRm3ZJkjRHNiTRFGPLR9xTzXpAG8l1h5ywGY9b5tN5I= +github.com/aws/aws-sdk-go-v2/service/arcregionswitch v1.2.14/go.mod h1:PyPhpvZGkGYZTeuYRlPwZTgBx93EUYtHdpPbiIlY7Q8= +github.com/aws/aws-sdk-go-v2/service/athena v1.55.12 h1:upjiOGrCbvVk/kgSvE8oRE5SwzuaayRsBoMs2dnVlvY= +github.com/aws/aws-sdk-go-v2/service/athena v1.55.12/go.mod h1:1bY3ff3w7nTDnyGgOAOEZpO7e7bUiG2iDM2tXbCzxjg= +github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.3 h1:gus+gJbIngKvaL6Q3PH7e2tjO1Isx+kp+ldWIvysiY0= +github.com/aws/aws-sdk-go-v2/service/auditmanager v1.46.3/go.mod h1:6U6XFWocDXxVtEZsjDajhNtAxNJzZRs9k7CJHuTMJCY= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.61.0 h1:L4+Ts9JbR5Bb92eyQunFFAB6TfTobcfFne8+fNPGFX0= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.61.0/go.mod h1:6E1AiecbY52kVBl8lKkdaO759rbGK3TBBBNnfxJezTM= +github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.5 h1:/Gf9lbM1ce3h5SswLp0dCzWz3Lb8wHdlQvD9okQFnKs= +github.com/aws/aws-sdk-go-v2/service/autoscalingplans v1.30.5/go.mod h1:NkStIqURmzgUVyoB3YkmU1HUtIPECrExIastd5QbXIk= +github.com/aws/aws-sdk-go-v2/service/backup v1.54.0 h1:irUsF+2pK8u1YfiH1SC265XCRR81txSLGOca1s8Dh88= +github.com/aws/aws-sdk-go-v2/service/backup v1.54.0/go.mod h1:Sqiqu5Ws64P9IYY+0mQ4OafDKK1LK6sRWQqw89dZZYA= +github.com/aws/aws-sdk-go-v2/service/batch v1.58.6 h1:/SWr0iPuPFm90sbJwTowOCD63ZtbdFYmp67XlXygwxo= +github.com/aws/aws-sdk-go-v2/service/batch v1.58.6/go.mod h1:zaUBHLEVy5UjLlFt996XZMXLza3teA7f0IhAoV7+3mg= +github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.5 h1:otJvRakif5zPNVJ2sRcayQFqYh8QMj3ukVNred28uTw= +github.com/aws/aws-sdk-go-v2/service/bcmdataexports v1.12.5/go.mod h1:PJ5iWye10CA9cYAeVL4RUSkZvAwVK/WrOnTSHLztNAI= +github.com/aws/aws-sdk-go-v2/service/bedrock v1.49.1 h1:Da6sk9ZLlC2PXBWRPENz9msEkn5fYE6MOSWKPTjoMRg= +github.com/aws/aws-sdk-go-v2/service/bedrock v1.49.1/go.mod h1:xJ84P+JCcEkzkMjqBKmImWl/zlwEwBmbjc9QR+tcACQ= +github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.3 h1:UArcFWYHtdk5QWOTteqRZwF/tAoaYx+ArreUakHx8K0= +github.com/aws/aws-sdk-go-v2/service/bedrockagent v1.51.3/go.mod h1:R5jkUdemrZt6+90gq4JFyxHKldEMH88F6wdxquDLa4Q= +github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.3 h1:lskoaAo1V+KpDYgS6lWMGvnxGhA0eX/bUQ6Xm7TEJM8= +github.com/aws/aws-sdk-go-v2/service/bedrockagentcorecontrol v1.13.3/go.mod h1:MvhjtEWL5RO1w6AMrt4d9k//kZxZUsLrTSipRM9Q0/8= +github.com/aws/aws-sdk-go-v2/service/billing v1.9.0 h1:xbdlsW9TVa7AVpqB8CzaX6cM4qQQ/9RLrx6GGuBoSHE= +github.com/aws/aws-sdk-go-v2/service/billing v1.9.0/go.mod h1:7WI9oHeKA76HgGtTaUeKToGO/rRH9/fx7WLCw1QLJt4= +github.com/aws/aws-sdk-go-v2/service/budgets v1.41.3 h1:9cQXqYwHzp4fcKCHOAlHeMm/m/K+dcZS2D5SB+4ZA9s= +github.com/aws/aws-sdk-go-v2/service/budgets v1.41.3/go.mod h1:wjQL1whunmAT3ZhqQGZq0lPGNmU27Uu8RjGmT12wLNg= +github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.12 h1:WAVCaNagdhnjzFUUsrYADbR6NF1RVG9LAZj2+oY8gAg= +github.com/aws/aws-sdk-go-v2/service/chatbot v1.14.12/go.mod h1:H9eUeKMZNHJnd/zKD3Ga0xyk6da+LDSFMZfOw2Wz45E= +github.com/aws/aws-sdk-go-v2/service/chime v1.41.3 h1:8Dt3NnfOF1ErL1xUxi6+fu5p/3Ezee6RZaCxH8YzL8g= +github.com/aws/aws-sdk-go-v2/service/chime v1.41.3/go.mod h1:NL5o86salGH/wxYiFkrzG6K8/GGPGdUNYXS00LCoNr4= +github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.12 h1:f6OT810gyz9/vYCGh99l8e2bSIqGO2B8HeSEsFwKy7w= +github.com/aws/aws-sdk-go-v2/service/chimesdkmediapipelines v1.26.12/go.mod h1:ykYGKe/rWysRsTmMJcq5VvqFzViL4XqsHke2UMh4ok0= +github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.4 h1:0W88faK7py65Xgpi/SPpK4HxF4nrHi0SG20ZTDdGQ1A= +github.com/aws/aws-sdk-go-v2/service/chimesdkvoice v1.28.4/go.mod h1:xjd2Oeftl4VNXrNTaEBSpwu4cKUDo82FQL9eHunFDqU= +github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.3 h1:158UOfGTmbAijrcMpR72d7UWaA8VtpyRDSQtiGB2Gd8= +github.com/aws/aws-sdk-go-v2/service/cleanrooms v1.37.3/go.mod h1:q9yJkMo4u5vpFAExN0Vtw+ChYDwq0hsSrD9DDE5Sd8w= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.11 h1:iR8n4gvDdN2hrUjXgETp76p/ILPbLFPuNbOi68B4CfE= +github.com/aws/aws-sdk-go-v2/service/cloud9 v1.33.11/go.mod h1:kyuiuFhvDWwqLGNWmwbIr/amPIFQWrA7KkbxRQvP0JU= +github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.3 h1:6ZTiyJCqVLE5CjuCZ6h9kKEbWOTbFxlBFXZ0fvTZK+s= +github.com/aws/aws-sdk-go-v2/service/cloudcontrol v1.29.3/go.mod h1:6kx+wmHMUP1fQBUpXN2N9xRt2sQUlloxwyF5cMIvDOc= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.70.0 h1:w9Yx0QWNhU2615kugQRIYSSR27GpZHkyRVdEHGi5PIY= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.70.0/go.mod h1:llucikq1Q6I1Ps8rNV3St0bOY5RQMxYh1lpCaskyhPw= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.56.2 h1:1Ipv5nooFuWg3iPGQPeh1WkUSJ96QFTqZQKMHPw9WHc= +github.com/aws/aws-sdk-go-v2/service/cloudfront v1.56.2/go.mod h1:UtP1sSXq2FHHO7Lvn4mNplFS4x7oP4+uMIJIQ8+3JyY= +github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.14 h1:AfC0uaSoMsz32lAOMkTjyfSX1PZRYniqzyt6pJmf+00= +github.com/aws/aws-sdk-go-v2/service/cloudfrontkeyvaluestore v1.12.14/go.mod h1:yFxrWxlbxnTilFCsiViY+x3qnKqi1CGdSPfEWYnwh6Q= +github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.11 h1:w+afQ/tvYUVdTiX1LhIm/vSNvaNiOyy3QoYGz3GfhuI= +github.com/aws/aws-sdk-go-v2/service/cloudhsmv2 v1.34.11/go.mod h1:w13K+4E6mjE6m5w3tDBZCs+S0zUiAse7M3qZg5ugecw= +github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.3 h1:AUYRw6eRXp6MjvKpTGRbNBmlfVRY7kEuClnMGv/zQQI= +github.com/aws/aws-sdk-go-v2/service/cloudsearch v1.32.3/go.mod h1:6hxErkN8bbEtojNMVdGQPpL7j9+A/QKL+eDljfRIKMM= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.54.0 h1:dbSrsAKSNOOwNd1rtaZwiRSzjc6U9yIRMfymrEeCM9g= +github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.54.0/go.mod h1:yPef5Em35Sb/89IIHAOarpsld8EuxyxuDVDlHj32LVA= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.3 h1:fD9/X9n4O6fauKLp9BE848I3JcXVEliwlgliernxUhs= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.52.3/go.mod h1:KSWhI1V5x80r8NUqs8QDkOazDolFqFUAjsyE5nYjKro= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.60.0 h1:jqF36cdImXcEo63d52Wpdi2qTXOLTZSJF/71h9MP5jo= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.60.0/go.mod h1:9/Q0/HtqBTLMksFse42wZjUq0jJrUuo4XlnXy/uSoeg= +github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.12 h1:j75xPdSialz4ipsvOpCtKl2VFb/ugc2PMgOfVvWjt6o= +github.com/aws/aws-sdk-go-v2/service/codeartifact v1.38.12/go.mod h1:9R9pEHnoKOjLs5dDREGyV1Ui2kWZgPPKz0VZd3juZhY= +github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.4 h1:rp7p7dTLS1qix2pVRT168GfZevumq0HoiytyrRG5e9o= +github.com/aws/aws-sdk-go-v2/service/codebuild v1.68.4/go.mod h1:LAT1SFMRPN1z4wewG4PHazKs2xL+J59saaAJQfZj8rc= +github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.3 h1:jusavOo6R3Cx7dF90etnt4fSU1KWM1NSwENFsdPPqVQ= +github.com/aws/aws-sdk-go-v2/service/codecatalyst v1.21.3/go.mod h1:160q+ylvlYKq6c8wufCHYeX4Qei0IC509n4hxlh8oVA= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.3 h1:D0CCIRXUefKZX30AyyG7QZby5+tVzP3Z+M66HoZVI4g= +github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.3/go.mod h1:jZuIO2m8qmy6VFTQgB/8bTb72o+X4zLRfnu1PubtriM= +github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.11 h1:UjRTTd2hwOv/bzqqaDlemhOqBK+J/tjTdv6PRJSvCxg= +github.com/aws/aws-sdk-go-v2/service/codeconnections v1.10.11/go.mod h1:MMDcKcUGX6vTU6iI4+JFF486CGygY/COEldYNSdQDFQ= +github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.3 h1:K6u1VZc2SmFqWaBELcIfowpH4livshEk3Iwg/Kuvd9g= +github.com/aws/aws-sdk-go-v2/service/codedeploy v1.35.3/go.mod h1:t9VTnwqOH9QaIWz+NXLMpV68Q983qdWH+ol+4pXATI8= +github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.11 h1:2+4r5Z7FE6bFMOfMt9b26xVwNwOn9DSS/gDTQSZVcuU= +github.com/aws/aws-sdk-go-v2/service/codeguruprofiler v1.29.11/go.mod h1:TTz1x8GSLqG2xw5I6ZPs0nm9Ro8W/D44MyeffDYxXnE= +github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.11 h1:SEaA8Sl/YGV7nrjySKWTncQo4Zj0Xcbjr2+jb8LFrtU= +github.com/aws/aws-sdk-go-v2/service/codegurureviewer v1.34.11/go.mod h1:KysZ41BGS0TjTmMIu6v0jIOKSlmhACK+7NnZOytrqC4= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.12 h1:OhbU8xlrNQt2qNHX8kKB8/WaONKPadiaSRXpyPYkCFY= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.46.12/go.mod h1:COTp2TtxyTD6Pm7H6mKieN+Q0TmccQhJnfxD6//JPtg= +github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.4 h1:we8Y0b2KcnY65saLrF9YXtFfK9BrpMY/qlx7QysALqI= +github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.35.4/go.mod h1:QOzDyBkE0ODl/dOuwpcSdMDz/8mz2i+KbwE8hSTUxKo= +github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.12 h1:6YR4J0bwBwLRwZ7OFm8gpA8BBVoTsbjfMBWNOuRkOBE= +github.com/aws/aws-sdk-go-v2/service/codestarnotifications v1.31.12/go.mod h1:9+D52LzbRUGdyzwB/AMLPi4ydjtSeFkCSloB6Tw7bq0= +github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.12 h1:lS0WkuQQ13PmBN5Aab3GajJA15BeTGOeFCYQlAmROfw= +github.com/aws/aws-sdk-go-v2/service/cognitoidentity v1.33.12/go.mod h1:ahZYJFutez0db6zWQyLWNddBtDDGovvOShiUTnOYPPw= +github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.13 h1:gUchSsfXNg3xDlGKTCOx/ZvFk/CbsiQ6pHgSzAAvNUo= +github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider v1.57.13/go.mod h1:NLRVISwN4NcFEWz8WN5kySbgN1g8hjYPR2cZD9Of3Rg= +github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.12 h1:OUq9z5ZMhZn87/QKG9xxWeyEmf8HKC4aiNnpLy36lc8= +github.com/aws/aws-sdk-go-v2/service/comprehend v1.40.12/go.mod h1:QY56Tp8KUNsipLdUdWGTwNg76WXpos4Q4Bbw51i2KS0= +github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.3 h1:0oum8CeAFRcovMsI+a8R3op5Z1ngJVLgi9ffWYt3xkQ= +github.com/aws/aws-sdk-go-v2/service/computeoptimizer v1.48.3/go.mod h1:PzK50LObvBt9Mb2YxwsocMuck07wSMSR+eVU9CiV05M= +github.com/aws/aws-sdk-go-v2/service/configservice v1.59.4 h1:dY6ktQ8OfUkI6fTs0R9/3mAbYC6N1wEbjsGq2PLFms4= +github.com/aws/aws-sdk-go-v2/service/configservice v1.59.4/go.mod h1:8pBCQK4k6Qpff8QKM6gcCt2ZsluQFsNtNaa8ouEZLFc= +github.com/aws/aws-sdk-go-v2/service/connect v1.146.0 h1:fL4XXNHdfBmVWSGgsBzoezErUf7knnLK5cCUe1F3eoQ= +github.com/aws/aws-sdk-go-v2/service/connect v1.146.0/go.mod h1:4S/3f30iB9LArrLNHVRw/IWyGEGturV5Z5DF1rp3NsE= +github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.3 h1:ZcrD31NLG/brevUHw8XSn74VHShleHUm5xy8uJC/1ek= +github.com/aws/aws-sdk-go-v2/service/connectcases v1.34.3/go.mod h1:g0V7qnDiTliogqzfAiJrhrOAEKnY+XY3u7/FJ8sZEYU= +github.com/aws/aws-sdk-go-v2/service/controltower v1.27.2 h1:D5zM7WP5IWp4DMbtY8NdTemanN/MxGyp2vm8Eis0gQE= +github.com/aws/aws-sdk-go-v2/service/controltower v1.27.2/go.mod h1:ZQuFo9/qnryEiHaDdXGo0pgsC+uHYHheHzGq+Vem8xM= +github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.4 h1:aCPRvahOg+fH79Sk9wOZslIrQVAAPgC1JpGzj1s5ZBo= +github.com/aws/aws-sdk-go-v2/service/costandusagereportservice v1.34.4/go.mod h1:z4Y8J/t7ktcqMxLtf4korP74Tg42Ov97FjuTDyFfJKw= +github.com/aws/aws-sdk-go-v2/service/costexplorer v1.60.0 h1:nZrsl4tViAlW9+xkUpc4GXa9t0p3RIzGz9csmRrXR/s= +github.com/aws/aws-sdk-go-v2/service/costexplorer v1.60.0/go.mod h1:sP89eC3imDzTgMk/N+gDwDqjeQgLLEt0PuU5NMBHBCo= +github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.21.0 h1:8oTOAr895uaekGOozHzfH1zHGfBhSHZwpardvitnaCI= +github.com/aws/aws-sdk-go-v2/service/costoptimizationhub v1.21.0/go.mod h1:Ouo0lXAlK9jTlJeMt6LTL+G6kKOfoK7xks0TT5AwdlQ= +github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.5 h1:XJUCroqsUAG80W0jVK/Rb4QPF/YbZu/oVtmiGvF8gjI= +github.com/aws/aws-sdk-go-v2/service/customerprofiles v1.54.5/go.mod h1:86sgcd46latOOSvQKbctenNsiEHnow3vip0OnwSqC54= +github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.60.0 h1:cJZPHHPjft5N0BNv9X0bsUdDNGGbTQiT2b7jiN+NYv4= +github.com/aws/aws-sdk-go-v2/service/databasemigrationservice v1.60.0/go.mod h1:Sc22CT1GPF61n0yJdqquFNvqoyfnQCZ+WS7Uz8daW8c= +github.com/aws/aws-sdk-go-v2/service/databrew v1.39.5 h1:gQDXbDgv5AW3treUAsfQGEeU3+ZmSEfb1TTpiDD7Gc8= +github.com/aws/aws-sdk-go-v2/service/databrew v1.39.5/go.mod h1:hu5s2BoJ9fqmyMoVVvYbAtTFOFg8lsr4TzgJnK58n2Q= +github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.5 h1:P9xrOXwbBxBzq30eiCFUlVE8lUUe6YnHs8j9dQx4YEM= +github.com/aws/aws-sdk-go-v2/service/dataexchange v1.40.5/go.mod h1:rwA2QoV4mz3TSrr4QirNyAndfs3EmwbVrGx5nMtTdz0= +github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.11 h1:ZmEqPDpJsiqkVqsRD7pi5SLO0VMyDavr9vlhF2R9iVM= +github.com/aws/aws-sdk-go-v2/service/datapipeline v1.30.11/go.mod h1:WZjvFO/jWbSRaxdkTmbL5GZu1HmPV2+DrDFmUCH0BKk= +github.com/aws/aws-sdk-go-v2/service/datasync v1.55.6 h1:pxK2rp4xZ073UMj7KUIX3Bwao02V6P+GXwvhOJW2Qkg= +github.com/aws/aws-sdk-go-v2/service/datasync v1.55.6/go.mod h1:35IO7OkYfIGQJeJ8IOFN7dPrregYgMMxBlSGpR0dEj8= +github.com/aws/aws-sdk-go-v2/service/datazone v1.48.0 h1:ON4CIIi/LgvXPKl+9FcuHI6evqfbFWbKvpngpS2IqvY= +github.com/aws/aws-sdk-go-v2/service/datazone v1.48.0/go.mod h1:ELpY+QIvAO5sH048NMmxDNMDuAKWbRmHCl0rrNR4V5s= +github.com/aws/aws-sdk-go-v2/service/dax v1.29.7 h1:d+Iq53DFhoJ4m+PKRCCosIodRTuWvlsh+LAWuOe7zWE= +github.com/aws/aws-sdk-go-v2/service/dax v1.29.7/go.mod h1:LqCHisA88LmdWAT7R/FsvLksZZs7ghdIUwZsZSu0xKs= +github.com/aws/aws-sdk-go-v2/service/detective v1.38.4 h1:iR9Cjiohq4R9veZr6DadbXEbKj1FADofRNJZ3hEjuwY= +github.com/aws/aws-sdk-go-v2/service/detective v1.38.4/go.mod h1:cOhEIcmxoL4V4Uavp0LRUV30gYNTGiTd2G0/ECJlIls= +github.com/aws/aws-sdk-go-v2/service/devicefarm v1.37.0 h1:VdU+oiTksNqUwRw5xv6AkoVKq6RecX6HrZmWGm/7lpY= +github.com/aws/aws-sdk-go-v2/service/devicefarm v1.37.0/go.mod h1:DOlSchQTITKhdLgShZBymT+x+kX6jSJx8ArGf2jvFVs= +github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.3 h1:pyh8Q7gwaW9mKsPG52ql7tarNkBn7jiYKmhXwzOAEO0= +github.com/aws/aws-sdk-go-v2/service/devopsguru v1.40.3/go.mod h1:pOx5GDFaf6hXYuvqq18r+Op5BCfuMuZKX2ZJgacqWNk= +github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.5 h1:XLpifFvzfFmQ0i4EX/xosiSt/yYEN7Wtw1LqffT3o0c= +github.com/aws/aws-sdk-go-v2/service/directconnect v1.38.5/go.mod h1:ozhPmvMQlk6trPDKahoaHUUEzmgiRxuHjXMWqdBy/Is= +github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.6 h1:33I5jbO/kG0WEg/U4GyMYR1RfOfEk+hRQhUmiBOrFBE= +github.com/aws/aws-sdk-go-v2/service/directoryservice v1.38.6/go.mod h1:yv/LQu/I+t1HsDl5wBlBxhnFDmLe8sk+6EkFW1WTb10= +github.com/aws/aws-sdk-go-v2/service/dlm v1.35.6 h1:D7GyrH7x87n6IwM4sdujnhYdm+tRR3M6j9Q/uZV6GEI= +github.com/aws/aws-sdk-go-v2/service/dlm v1.35.6/go.mod h1:rP4rq5uek/rreEV2CzUzGPNcD36+ZLDeh9HzyxePFnE= +github.com/aws/aws-sdk-go-v2/service/docdb v1.48.3 h1:4VZq8ExlKiUtoFswYkkA36jHO4DwMHJe+EINHAbtVnc= +github.com/aws/aws-sdk-go-v2/service/docdb v1.48.3/go.mod h1:13D9OjKPmSXbWE+20zVYaesIuFSUtx1pEouI2hu8yp0= +github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.4 h1:0BkoVJIQfd3qMdianq8AUXcOxY9325OVroccwV3MGg4= +github.com/aws/aws-sdk-go-v2/service/docdbelastic v1.20.4/go.mod h1:GXVZTuVYCRQvfLiT+fKmnXLYap5xGTfz+UD47bxJEKE= +github.com/aws/aws-sdk-go-v2/service/drs v1.36.4 h1:HH+yOVt1hVdw3q5OyG6dYjMi5mg+pGC7aza93j0sMNw= +github.com/aws/aws-sdk-go-v2/service/drs v1.36.4/go.mod h1:qO9+wcb7meZj7R8VQd8QnHb+ZPRWdODsexKGr3ru7cA= +github.com/aws/aws-sdk-go-v2/service/dsql v1.11.2 h1:+dLCcQdBv+JiLDp25/cDm5GiK2vKg5+y1n+Lm+ve3zY= +github.com/aws/aws-sdk-go-v2/service/dsql v1.11.2/go.mod h1:qAIMlh9aATA3n6dbs3aHQD7MOCAN8km548KABpaxqUs= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.0 h1:oyaZ6mvMgqy3Vm2RMD6ni2sQi4G9T6ntOXP5/PFtnVs= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.53.0/go.mod h1:6eUUnWOJ8sucL5Uk8rPkFo8FYioM0CTNGHga8hwzXVc= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.272.0 h1:zWYlsIUX88ZSDiKQR4603gVjPLR7Wn1+/hv76lsrMvA= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.272.0/go.mod h1:NDdDLLW5PtLLXN661gKcvJvqAH5OBXsfhMlmKVu1/pY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.53.0 h1:ReOAhAmW/8c2yLfr7fuLeD6WgXrp12yL27CCQMP6eQM= +github.com/aws/aws-sdk-go-v2/service/ecr v1.53.0/go.mod h1:1NVD1KuMjH2GqnPwMotPndQaT/MreKkWpjkF12d6oKU= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.4 h1:0rqbFeBlrTHNEIdrcH9g1yW0QjBOaCrGcTQ6sLcsH9w= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.4/go.mod h1:x7gU4CAyAz4BsM9hlRkhHiYw2GIr1QCmN45uwQw9l/E= +github.com/aws/aws-sdk-go-v2/service/ecs v1.68.0 h1:eKgxT+0Aj9zkdw2qcfCP9FyfrQlQwsfH7lQyeqwODmY= +github.com/aws/aws-sdk-go-v2/service/ecs v1.68.0/go.mod h1:rrhqfkXfa2DSNq0RyFhnnFEAyI+yJB4+2QlZKeJvMjs= +github.com/aws/aws-sdk-go-v2/service/efs v1.41.4 h1:Uk/tvWjdaeVQxmKTjleCJ05SPoXL5Upgq+rffBcolZI= +github.com/aws/aws-sdk-go-v2/service/efs v1.41.4/go.mod h1:ddWcpZJhvKugMHfwzBsq3dtaBLH7PsTgtAyiL3BEdxo= +github.com/aws/aws-sdk-go-v2/service/eks v1.74.9 h1:ugqH9Vu52QlUhpTbW75rsv0WA9k704DEwOCoxWsLy+4= +github.com/aws/aws-sdk-go-v2/service/eks v1.74.9/go.mod h1:xHVz3A2oEVl3UzjCOSEz/fBeBoFrS6FJ3cc/jo0WLyM= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.3 h1:a7jZ0M15w4FAGi7VsRvNSfUZk6ozGiFNz/eJ7DySiiE= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.51.3/go.mod h1:m21nBoJHIHVbICAgJgvaZuO2AEfamKO53hl05xQ1ZUQ= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.13 h1:l4FFXPDGzjr3bXU3tamm1cAmz4c7OWOiHPSekTdRllg= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.33.13/go.mod h1:V3Yl2vXro/+nzAmexAXOc1GdkTmEE+UHp0YMuTn5G5k= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.13 h1:VygvbUZq3ancO3iutKRr5zsdVR3X5wQPFoYMD1P8hhg= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.33.13/go.mod h1:ImGbJ8W4fb8KZekLSWCnuuabYN5WusCD7cnW4Nz7i14= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.53.0 h1:FW40Wq7eYkzoBc/7X4Ds7OLKXv+CM5w7n1mMN+qxSRI= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.53.0/go.mod h1:Uyo8wjqYyZaHVqoe+APHe4+THRGv4pctJzItYYnRe5Q= +github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.13 h1:hqyzd5cRYxvjVLa9FmmR39IM76hSNf+ROudLUpZviSE= +github.com/aws/aws-sdk-go-v2/service/elasticsearchservice v1.37.13/go.mod h1:GXyWYhCWYQQhGzxzNDU6CRL++zIsBgguWJFTa/iTOqI= +github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.12 h1:Aqvjf0SzPHFEq7stD7515Osa/l8dXxnkdZiwjTrGE6c= +github.com/aws/aws-sdk-go-v2/service/elastictranscoder v1.32.12/go.mod h1:hV8KFAz+flqQ0eHBEJYGU4NWzTqQBtrRyqVwfm3Gi2Q= +github.com/aws/aws-sdk-go-v2/service/emr v1.56.0 h1:g185SYMRcklpYhul88jlO00EMsuOpfAwcXoys9KaeNk= +github.com/aws/aws-sdk-go-v2/service/emr v1.56.0/go.mod h1:NZatCe1XK65DogTuEG2emmEN3NIZtwLsXtJzWpkqSx0= +github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.8 h1:h4R+o2xRhtn4SPIao+6aU1TVTYBk0CfoLd9bhXZ3OTw= +github.com/aws/aws-sdk-go-v2/service/emrcontainers v1.40.8/go.mod h1:ncWhqV69Tim5BrNp98qdJfLvlD/WwCs5X3lBPgV62rs= +github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.3 h1:axxXrvkaQcqcmEfNoIhU5oRLX7ufI2sAX+2a1j8xN1k= +github.com/aws/aws-sdk-go-v2/service/emrserverless v1.37.3/go.mod h1:osVEDevOxiptmGI1/Q3CCm0FFIRf0MhwnWoL8Br0Pso= +github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.12 h1:KsjKcIasbPhVthcDQcAJAyouihkQq5ZS5UJDMwx7yMM= +github.com/aws/aws-sdk-go-v2/service/eventbridge v1.45.12/go.mod h1:WVMQLFJTxCpu7h7eKnItFtVWitmVRJLsHTbZFYOmkTs= +github.com/aws/aws-sdk-go-v2/service/evidently v1.28.11 h1:Gz7BrxUHRme9DZt145R0WhRk6Kc4a8W5Wdl6Mw7oDp0= +github.com/aws/aws-sdk-go-v2/service/evidently v1.28.11/go.mod h1:3Dt+ChkPyMq1eJTpXmBu4AUtsXN0oqfYph09KNICC6Q= +github.com/aws/aws-sdk-go-v2/service/evs v1.5.8 h1:DBvUxll31Wr0ZiahXp+xzR4cuFmO1eFXXk41FopsAl4= +github.com/aws/aws-sdk-go-v2/service/evs v1.5.8/go.mod h1:/IUqdRVJhNRM7OjN7cdlxnM2j+nuf8b1C6j20YzKTeg= +github.com/aws/aws-sdk-go-v2/service/finspace v1.33.12 h1:f88cDjxWDscEu/9pLvTEn+xISRibEuceOFpX4xwoOxw= +github.com/aws/aws-sdk-go-v2/service/finspace v1.33.12/go.mod h1:L9hrtvHZKfvGwvP3rZcNgaZhhH0QWarqvcuw66JUqR8= +github.com/aws/aws-sdk-go-v2/service/firehose v1.42.3 h1:EwlA0X8pv8N6/sVK4r0A4JlZyib7nos8yU9YJSaiKV8= +github.com/aws/aws-sdk-go-v2/service/firehose v1.42.3/go.mod h1:tHbE62j5gxIYxqmus+zqDQEZama0aWmglUnAk5+lAUs= +github.com/aws/aws-sdk-go-v2/service/fis v1.37.11 h1:Z0sI7NcI76E0ok3s29O5TVM0ye2Qi4YGeeRGr7qDP9A= +github.com/aws/aws-sdk-go-v2/service/fis v1.37.11/go.mod h1:Ja2eowkEbK8dfjWqxg96k4lkVjnf7YTUpEtQKHflynQ= +github.com/aws/aws-sdk-go-v2/service/fms v1.44.12 h1:wqtKrEUifaZHVItsMfgAcHzHce8UUQfOvP6vDb2XqpY= +github.com/aws/aws-sdk-go-v2/service/fms v1.44.12/go.mod h1:qKGD0P+Hxcbq4w6Q6PUrDDLd0C2PcgwLtIS2BT6+2yo= +github.com/aws/aws-sdk-go-v2/service/fsx v1.64.0 h1:pIzBzYXgK8naqPgQ0H7VDd6hEi05rZG6DCrAxsn9f2Q= +github.com/aws/aws-sdk-go-v2/service/fsx v1.64.0/go.mod h1:MCyHv+eBeciHOldY/pOKwp7j02Jo2HS1cpvThq2hSqs= +github.com/aws/aws-sdk-go-v2/service/gamelift v1.48.2 h1:cdqUPiNlaSdNumcrBGIag7Qpi6rHwLZHxBvjP08LDBs= +github.com/aws/aws-sdk-go-v2/service/gamelift v1.48.2/go.mod h1:dcVPaAeS/WE1PQeOldz0EuPud1gttdoQXajAKhNf0rE= +github.com/aws/aws-sdk-go-v2/service/glacier v1.31.12 h1:8Az5fIk1L9pRU81KubxXn8QzUZJbticx8KBbTrc+s5c= +github.com/aws/aws-sdk-go-v2/service/glacier v1.31.12/go.mod h1:qkG1pn5qsa79Ovau5ZJ3DpYa9Ar534RyQU8PjjMalCM= +github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.5 h1:h80nAJssBG0S3yD8ZHoigFjmVFJIiL6jfx5FTUihdwo= +github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.35.5/go.mod h1:La9wJnRUasTkBLOLqH2JVrApk1WG0vui4MVyr+rGS8Y= +github.com/aws/aws-sdk-go-v2/service/glue v1.133.0 h1:bIzOBSUg62ENeRK0t7p8TjdXDhGgVZppSVrSNYSzSgQ= +github.com/aws/aws-sdk-go-v2/service/glue v1.133.0/go.mod h1:KBo/tKQu4KUTMQ88jWZR79PNgEeDCD8QrO8oMmAq8ng= +github.com/aws/aws-sdk-go-v2/service/grafana v1.32.5 h1:eTAfP6KrOmbUK4at7wlX8vG7qc8Ao110th4/Lw7xxI4= +github.com/aws/aws-sdk-go-v2/service/grafana v1.32.5/go.mod h1:6tjVI48fzvjSAKY486cvKQPNeuIcV5YULNlFyAPZ+UU= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.12 h1:0OhsswAs8h4vSCyGYx283pH+3Ks4Qngui0/g/KOhUYc= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.32.12/go.mod h1:wXnnE8KHU07d8VHPGTibk+Kx2TXFaCsL92wJoPPvCvM= +github.com/aws/aws-sdk-go-v2/service/groundstation v1.39.2 h1:BsyqAKq5RduYyz1muDRvvsKwXHd6yG/C+9TpdD+8O/o= +github.com/aws/aws-sdk-go-v2/service/groundstation v1.39.2/go.mod h1:mg5Mut9Q671xNH+VvfaPBVvS4U9vLw1R5wz4bJvPjd4= +github.com/aws/aws-sdk-go-v2/service/guardduty v1.68.0 h1:CMWFVQQDypdxhS1d4V19fP/Y3XNB72WLyteyafQMCsI= +github.com/aws/aws-sdk-go-v2/service/guardduty v1.68.0/go.mod h1:U8kxZNr/dDtSqvr9L8e+fyqVmU/BNyI9fKWAatpu1CE= +github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.4 h1:Dt34+Yu6fRgiZgSMoO6J65IMKawDGjJn7BkPvjrI0ns= +github.com/aws/aws-sdk-go-v2/service/healthlake v1.36.4/go.mod h1:1GUJHZK3s9RIYhn/cLwh5/08/EfcnpCllSHWeJ23nVg= +github.com/aws/aws-sdk-go-v2/service/iam v1.52.0 h1:tXH4OrcRq053tqoWcmk9V3yfeedhgoa8o1J04S5JeYc= +github.com/aws/aws-sdk-go-v2/service/iam v1.52.0/go.mod h1:cuEMbL1mNtO1sUyT+DYDNIA8Y7aJG1oIdgHqUk29Uzk= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.34.2 h1:Ch+EIqM8RIEtVQqQl14XazfYBCzzxiZ1f7jbrOJ5D+8= +github.com/aws/aws-sdk-go-v2/service/identitystore v1.34.2/go.mod h1:uuQmaV23i5w+5Jy2XFnquY0Z41iR6oDDdu+Sqz6bsNg= +github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.49.0 h1:VTKPR2R1q0o7N7T0ilqSajWWTlKNjsSzxvu319pLitc= +github.com/aws/aws-sdk-go-v2/service/imagebuilder v1.49.0/go.mod h1:VD7bLCk88KQgyRB+yIQH9BNmtmSpwgRQ0Q7Wp1bsCuk= +github.com/aws/aws-sdk-go-v2/service/inspector v1.30.11 h1:I2WBSlw0rFVTTMDdg+7a77/kQFNKxJh1lJDZyI77ZTc= +github.com/aws/aws-sdk-go-v2/service/inspector v1.30.11/go.mod h1:Ce8Iac726mzXgIOgFkMllAZsgb5XTOjzC5og1vPkHu0= +github.com/aws/aws-sdk-go-v2/service/inspector2 v1.45.0 h1:gQW64ZGON3XG+UX2hDSHEXyRGd0YRxEqnyAYQRBK8tQ= +github.com/aws/aws-sdk-go-v2/service/inspector2 v1.45.0/go.mod h1:btzexzBLvYxamIptsxWMmHhXXx/FFmdKGgH96IM6HE8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.4 h1:NvMjwvv8hpGUILarKw7Z4Q0w1H9anXKsesMxtw++MA4= @@ -303,272 +303,272 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13 h1:zhBJXdhWIFZ1acfDYIhu4+LCzdUS2Vbcum7D01dXlHQ= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.13/go.mod h1:JaaOeCE368qn2Hzi3sEzY6FgAZVCIYcC2nwbro2QCh8= -github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.2 h1:R3iBZpeWSueilpxnZqptm7//UzoW2mAwSbGfpwrgHas= -github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.2/go.mod h1:1J+jvIbqr9u7BwNyDWrriI1BsFBVMBEi6XP2T8QSAXw= -github.com/aws/aws-sdk-go-v2/service/invoicing v1.6.12 h1:b+ezLKuapXzffpj0V4lxpBrlUvgMi0Ddp1Ynpi9pgWo= -github.com/aws/aws-sdk-go-v2/service/invoicing v1.6.12/go.mod h1:077SFzwNIDjtHm35vjTtBHkweLVXtd3ahiPqfxo9Jms= -github.com/aws/aws-sdk-go-v2/service/iot v1.69.9 h1:rsNyU/ki3ze6KbSmeQERIuWiWXGbd1iN3wOJ4WjIqeI= -github.com/aws/aws-sdk-go-v2/service/iot v1.69.9/go.mod h1:Qsm1SgHzgKxy9TPqGfVBL+ULu/LW1iIOTn7kbsFhWE8= -github.com/aws/aws-sdk-go-v2/service/ivs v1.48.3 h1:hbSN4lzuMWMUM63kQuGZax6fUJUFHGqFsbTaTFbF49Q= -github.com/aws/aws-sdk-go-v2/service/ivs v1.48.3/go.mod h1:LWpDgCXaAZgKF5EH2xincNziWa0GkknDhx+ig0pAWzo= -github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.9 h1:yPmlx3GZDtjBsc348D9z7oxfs73+NX2uh2uUr0HvaPA= -github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.9/go.mod h1:gHijQmBJujk/KV3Y+trzDPVZ16MS5JkITQX5MqO3wiA= -github.com/aws/aws-sdk-go-v2/service/kafka v1.44.3 h1:rtf6o1k1DV/iuZXAx8ApQ3w0m4a+hx9QNF1zxDAq9NE= -github.com/aws/aws-sdk-go-v2/service/kafka v1.44.3/go.mod h1:Duj0BV8XyPzvoVF2LYtLDTCoQkIJ+NU1ui7QyMyCM/Y= -github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.10 h1:6wwedFSTr7XOFiqJirGQG1fGtELNpJDdzVfJ0S4qSUY= -github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.10/go.mod h1:wnbOw77+1dcXjlDl1JhSQmsO0+r3np9nFxvaX4HgUQ0= -github.com/aws/aws-sdk-go-v2/service/kendra v1.60.10 h1:sa9ZsmYBxXbpy8ATgyKBbgXS9IkQ2jCdZFv0jO7Fw2U= -github.com/aws/aws-sdk-go-v2/service/kendra v1.60.10/go.mod h1:KeQsf6zSp1LMwzIHnjOGuBzDWisc1sXHoJkLBFrsZ9c= -github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.3 h1:92nm3I/RtA49i3xgVdX4vs3FzxKWnlNoCRDf/AAt9eg= -github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.3/go.mod h1:W3i/Z8SlfqFwSoCNyYtKGd/LgR1vi08/35YQ1bxcEh8= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.1 h1:dSwPbGWGhA37laPvoToLp1b1wHRKUuPMorKCL/E+pi8= -github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.1/go.mod h1:jTDNZao/9uv/6JeaeDWEqA4s+l6c8+cqaDeYFpM+818= -github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.10 h1:F2leRXPB8l3bERzuAA5yE3Vmul8vodlOgwkLXtNNelw= -github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.10/go.mod h1:LHFWG4nhpu6EEIU4ZReJbmDVVL/up6CVhgkUTacFVyM= -github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.11 h1:z2Hkz9wcDTzCspYMf5YaTU3gw2ChPkSvUGfPlctUvMM= -github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.11/go.mod h1:tzsKwzVe1LFyj0teoeHk5bMpNCUNaHwX76Fw0Tc7xZg= -github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.9 h1:IBoHR14X2/wkLpJwCIK1YTKQyhHz0MheLspTJDK+qAY= -github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.9/go.mod h1:ml4xarTHw7hFk3uIw4wioNdFnATCJQhvlbGBHIMTRH0= -github.com/aws/aws-sdk-go-v2/service/kms v1.47.1 h1:6+C0RoGF4HJQALrsecOXN7cm/l5rgNHCw2xbcvFgpH4= -github.com/aws/aws-sdk-go-v2/service/kms v1.47.1/go.mod h1:VJcNH6BLr+3VJwinRKdotLOMglHO8mIKlD3ea5c7hbw= -github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.9 h1:DQkbOooOIjsmjey98tb+fNB1BYONPTYuUHLDad6xmsM= -github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.9/go.mod h1:1oR3VqBIi345fZEqaBh7HbB/GKLZU5F1+nbXQV5csnY= -github.com/aws/aws-sdk-go-v2/service/lambda v1.81.1 h1:s+T+4SWN2H4xTl/U1K6yTMEyos4Y7J5AhmKpw19y5H8= -github.com/aws/aws-sdk-go-v2/service/lambda v1.81.1/go.mod h1:X9xD+03BeNMi9vA0zcJ0rL4jaGRaBpB/54ukKjhz6ik= -github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.10 h1:ecPwW7d6Z67LossPeGqZ+QWbAzroa/G9+eaX6x+0n68= -github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.10/go.mod h1://3iRAUIqql/dPeYQI4lIv4JA8FiZzgIifX0EiX+9uU= -github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.3 h1:nwhmZ1Zg2TiaIfqXUlCvh+t6BAIfWFY8gGUkx+yeEHM= -github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.3/go.mod h1:iE4e1/ovGtt3keD9WWXuHfjoascElN+sEwN0Ff5Tys4= -github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.56.10 h1:Br0sxO83x7IDEZOq/uOkBKsb9Hm8RtYR/2ppiWaS3oA= -github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.56.10/go.mod h1:jcWBQtwCe0xBJLEVkz4ny1N+SRNRQQdpPUT1MKRwyu0= -github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.10 h1:tYEfcHgpwNLOKWksg/3cVq8xk+BjUqXQk7IxIJTxLW0= -github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.10/go.mod h1:jXdt+CSYTcfzhA60pRhvdlBEGWkHdb96/4+v8hJrYxU= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.4 h1:/1o2AYwHJojUDeMvQNyJiKZwcWCc3e4kQuTXqRLuThc= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.4/go.mod h1:Nn2xx6HojGuNMtUFxxz/nyNLSS+tHMRsMhe3+W3wB5k= -github.com/aws/aws-sdk-go-v2/service/location v1.50.2 h1:/TMbkCN8tXLQDW7ioTiyXeywn0Tj1HajEdZhPU6z8Sc= -github.com/aws/aws-sdk-go-v2/service/location v1.50.2/go.mod h1:XqDleYNKtPYvlUb14t3vWzJL/j81V1wyxALzAkhakfs= +github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.4 h1:i0+jLDeUbGVMnbM062bNuqXSRGvxChArs5Z/HcetByo= +github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.26.4/go.mod h1:1J+jvIbqr9u7BwNyDWrriI1BsFBVMBEi6XP2T8QSAXw= +github.com/aws/aws-sdk-go-v2/service/invoicing v1.8.0 h1:GmwiBzG6DhuL9w4MgrbUUHE+GFCJ9diSxbTAX27zTdo= +github.com/aws/aws-sdk-go-v2/service/invoicing v1.8.0/go.mod h1:077SFzwNIDjtHm35vjTtBHkweLVXtd3ahiPqfxo9Jms= +github.com/aws/aws-sdk-go-v2/service/iot v1.69.11 h1:E1iadLmKaX8iqk4lIOenXnd52iORtxQItB5kOID2J48= +github.com/aws/aws-sdk-go-v2/service/iot v1.69.11/go.mod h1:Qsm1SgHzgKxy9TPqGfVBL+ULu/LW1iIOTn7kbsFhWE8= +github.com/aws/aws-sdk-go-v2/service/ivs v1.48.5 h1:S7hZ3yWMpTG7jDJIQhWoob0vjAbS7g8VMmqDs+Rr0v8= +github.com/aws/aws-sdk-go-v2/service/ivs v1.48.5/go.mod h1:LWpDgCXaAZgKF5EH2xincNziWa0GkknDhx+ig0pAWzo= +github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.11 h1:3O57ECBVWgTITHZTmIsDdpaUUxGN2YULXDhBtea4A+Q= +github.com/aws/aws-sdk-go-v2/service/ivschat v1.21.11/go.mod h1:gHijQmBJujk/KV3Y+trzDPVZ16MS5JkITQX5MqO3wiA= +github.com/aws/aws-sdk-go-v2/service/kafka v1.46.0 h1:hOOY9fQ95Rfv/L6XRFiJTZlcf52dFQ5txxw49VbFT5k= +github.com/aws/aws-sdk-go-v2/service/kafka v1.46.0/go.mod h1:Duj0BV8XyPzvoVF2LYtLDTCoQkIJ+NU1ui7QyMyCM/Y= +github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.12 h1:7ZayGxzuj2qFwCTUUVGHYS6hxHb5Uly1W4Lbau4BTXs= +github.com/aws/aws-sdk-go-v2/service/kafkaconnect v1.27.12/go.mod h1:wnbOw77+1dcXjlDl1JhSQmsO0+r3np9nFxvaX4HgUQ0= +github.com/aws/aws-sdk-go-v2/service/kendra v1.60.12 h1:MSoRxnPxbIaotIGof/+4CCw1ftfVnvTfB0h+0xDuAJA= +github.com/aws/aws-sdk-go-v2/service/kendra v1.60.12/go.mod h1:KeQsf6zSp1LMwzIHnjOGuBzDWisc1sXHoJkLBFrsZ9c= +github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.5 h1:8xc7vsJS13R7ikYhbREO8XJrekgAzju/kUNML/mibqc= +github.com/aws/aws-sdk-go-v2/service/keyspaces v1.24.5/go.mod h1:W3i/Z8SlfqFwSoCNyYtKGd/LgR1vi08/35YQ1bxcEh8= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.3 h1:A2HNxrABEFha5831yAU05G0mYNxaxYH4WG85FV6ZWIQ= +github.com/aws/aws-sdk-go-v2/service/kinesis v1.42.3/go.mod h1:jTDNZao/9uv/6JeaeDWEqA4s+l6c8+cqaDeYFpM+818= +github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.12 h1:WAfQy/LSjjyAeWtCndtEkJA1tqADh7bqA3eEImVOsQo= +github.com/aws/aws-sdk-go-v2/service/kinesisanalytics v1.30.12/go.mod h1:LHFWG4nhpu6EEIU4ZReJbmDVVL/up6CVhgkUTacFVyM= +github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.13 h1:m0QZX2HW98IKt/tS4DJFJwt/Qra46XXCfroHX/kvmA4= +github.com/aws/aws-sdk-go-v2/service/kinesisanalyticsv2 v1.36.13/go.mod h1:tzsKwzVe1LFyj0teoeHk5bMpNCUNaHwX76Fw0Tc7xZg= +github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.11 h1:P1mPzg4L38jehlGOWnZIc9kCV4OD2Fjk0sJqdDWutzg= +github.com/aws/aws-sdk-go-v2/service/kinesisvideo v1.32.11/go.mod h1:ml4xarTHw7hFk3uIw4wioNdFnATCJQhvlbGBHIMTRH0= +github.com/aws/aws-sdk-go-v2/service/kms v1.48.2 h1:aL8Y/AbB6I+uw0MjLbdo68NQ8t5lNs3CY3S848HpETk= +github.com/aws/aws-sdk-go-v2/service/kms v1.48.2/go.mod h1:VJcNH6BLr+3VJwinRKdotLOMglHO8mIKlD3ea5c7hbw= +github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.11 h1:hF1Qozl8Fh6C1bUeNaL0xLbTlsHaKmxHKFfA08q5mU8= +github.com/aws/aws-sdk-go-v2/service/lakeformation v1.45.11/go.mod h1:1oR3VqBIi345fZEqaBh7HbB/GKLZU5F1+nbXQV5csnY= +github.com/aws/aws-sdk-go-v2/service/lambda v1.82.0 h1:MrStO25Ef1TbXFzZr2pZPdwcFHyUgPxCX7MXz09Qk7k= +github.com/aws/aws-sdk-go-v2/service/lambda v1.82.0/go.mod h1:X9xD+03BeNMi9vA0zcJ0rL4jaGRaBpB/54ukKjhz6ik= +github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.12 h1:dN62fbhBm0z/WOjTqQm7+vRpAPrLjFQd08TIhjvOhlA= +github.com/aws/aws-sdk-go-v2/service/launchwizard v1.13.12/go.mod h1://3iRAUIqql/dPeYQI4lIv4JA8FiZzgIifX0EiX+9uU= +github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.5 h1:C/Qq1lPIUMssyiBXzlhvOEEMPuLBuSqarHoXpRvML1M= +github.com/aws/aws-sdk-go-v2/service/lexmodelbuildingservice v1.34.5/go.mod h1:iE4e1/ovGtt3keD9WWXuHfjoascElN+sEwN0Ff5Tys4= +github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.57.0 h1:alZjWGUSbcTTNYTrOhbFVh7B1mSgMuXEvmsxFybSKYo= +github.com/aws/aws-sdk-go-v2/service/lexmodelsv2 v1.57.0/go.mod h1:jcWBQtwCe0xBJLEVkz4ny1N+SRNRQQdpPUT1MKRwyu0= +github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.12 h1:e6Q/2pgy/KKhpG8uBEq51rboXTepDcMKqmJTn1sv/Hg= +github.com/aws/aws-sdk-go-v2/service/licensemanager v1.36.12/go.mod h1:jXdt+CSYTcfzhA60pRhvdlBEGWkHdb96/4+v8hJrYxU= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.6 h1:cMYT6YsNkZjo4vguBxkgGCVffhaS0Dc2BZs/nGr4uLs= +github.com/aws/aws-sdk-go-v2/service/lightsail v1.50.6/go.mod h1:Nn2xx6HojGuNMtUFxxz/nyNLSS+tHMRsMhe3+W3wB5k= +github.com/aws/aws-sdk-go-v2/service/location v1.50.4 h1:95HV4iCeSPGfTTiPI5JjmZAHud0YCn0wB1KViqk+Epk= +github.com/aws/aws-sdk-go-v2/service/location v1.50.4/go.mod h1:XqDleYNKtPYvlUb14t3vWzJL/j81V1wyxALzAkhakfs= github.com/aws/aws-sdk-go-v2/service/lookoutmetrics v1.37.2 h1:IXo/4IslBFio+k7Pm0gLptSh+B2GvSZQKRTDwfs9jkc= github.com/aws/aws-sdk-go-v2/service/lookoutmetrics v1.37.2/go.mod h1:tF6+C2s8Ru1RIyN1jPJR4VVk10Zz7pBhrYgZ72rFy7c= -github.com/aws/aws-sdk-go-v2/service/m2 v1.26.3 h1:LYEBwyFvctVmWjCz7weoxd054/zULftuyl1zGvyxSKE= -github.com/aws/aws-sdk-go-v2/service/m2 v1.26.3/go.mod h1:TcXLSXdIt/knslZsVOxLz85TXJHYftEnZp2Pkqcmd/g= -github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.2 h1:NkC/s9Wsghaskt8Iqt2wCtffsz7hJreXa4rnkiQL7pw= -github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.2/go.mod h1:UqgjJRAxzo2p/JJAaa4U10r468sb5dB7XdTojQM3J6I= -github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.45.4 h1:M2J4MEpldjlDZXOFJgRHga6PzlD2swL7yVAHo8Uyr4E= -github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.45.4/go.mod h1:h8kJMoJzHMU0zZWycpQpGmcxYLKhrhfC8RI1O4E4lv0= -github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.84.1 h1:wh6KarQYC3sOqSztbLclDsuzbFmnNSTLqxsjsMwA2UA= -github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.84.1/go.mod h1:69w+ev30uz0EQ+Z3brr3IecMA4D7Pkr3PtnQc0VGEZs= -github.com/aws/aws-sdk-go-v2/service/medialive v1.85.3 h1:oxLrq/Utamhh1Zj3MW2qWDSRSkT5bbiHfvvayoqjWbk= -github.com/aws/aws-sdk-go-v2/service/medialive v1.85.3/go.mod h1:SRJh9enbB1Urr1hv5+LKTbRlmXlhbjzvy3AwZkB7AHY= -github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.10 h1:kHJkbuRjwDLvVVxSPBsJxeilUcns3u20i1wSSeFPvjs= -github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.10/go.mod h1:7As8fD4Tr7DZAKWm0YOPFaoNymtw3xsCUkjQobfsZ7E= -github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.32.3 h1:LubivQgq+rRgBHCBbBgZ2UBkAdQ6y0mFGX6C0wSmRPQ= -github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.32.3/go.mod h1:w/Cotl6ORtnl+0i3hsOfzeV3bq5msbjgTrDhN57KTQU= -github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.10 h1:ScPcd6NdvARaVn9gz+EexxAmCtyK2/JSOhwPXwy9eys= -github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.10/go.mod h1:eiBfqNKAQK1rLuvKJOc6n5r9JZjgvdcMjxHHJlQwO3o= -github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.10 h1:iftQsYTyrBgW985/f00n5D8EYIHUieecePLZr7jP08g= -github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.10/go.mod h1:p0DZlc3953qm+OFFjWYXI4pUVN0Vtx7wxn/0sT6HjrQ= -github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.3 h1:WK9HbxC3KkSPF+kOAAAm9erqWNfqqmRMSXNtZTLn/3M= -github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.3/go.mod h1:iehQZb2FgCH28RyIL7fJCWgxmjCilIHVMJ3LXuZakCI= -github.com/aws/aws-sdk-go-v2/service/mgn v1.38.2 h1:CIDOUFOqBbKbJOGYJXm5tQwgRujN0p6i58YVT4InmcM= -github.com/aws/aws-sdk-go-v2/service/mgn v1.38.2/go.mod h1:n6Jxq0qdghot9uUi6ckEeaz0QvYv41DnFnSkNEwkKa8= -github.com/aws/aws-sdk-go-v2/service/mq v1.34.8 h1:4GQVLusZe5utEVcNSGmnoJX/NDlAchlcWSG0oReg+XU= -github.com/aws/aws-sdk-go-v2/service/mq v1.34.8/go.mod h1:ygM6WHFaCHMQ4+Pn3cMqFhWpbc06reGq4VTsv89bBrA= -github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.10 h1:c91LfZold0Ygx7qIoqMlRteiDbfzom3IdrS2VhO+NfQ= -github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.10/go.mod h1:1D+jlQDjJVp+zWuj+7fkdWRAId2DbnWm92v/QxcaMec= -github.com/aws/aws-sdk-go-v2/service/neptune v1.43.1 h1:J+BtvVBstv7HTQ47wtjwvNvTM3kGM64hwRQIx3RdjWs= -github.com/aws/aws-sdk-go-v2/service/neptune v1.43.1/go.mod h1:zZ58Zd5x0GGqnSgDLV4R3C1Xazzg3htNhg3kUpNB94M= -github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.9 h1:OxURddFfKJUKvUGnuhfltbn1xYG+tYMJ5rcVgSVaJEw= -github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.9/go.mod h1:dUFhAeruwm9ZYvMRk2JU6AR+YFcQ+4h34C3yNmz4T88= -github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.57.5 h1:JXSsiFYuM7CTUgN6H1pxsjh+svN/QS6ZNeOj2E8jEGo= -github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.57.5/go.mod h1:wCjIj4guias8uhaV3dqeSag/7v04X3xJQa4Ur9zJttc= -github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.10.3 h1:Pp2ZNKYqmhfmOAmK2N1PjdugfhoAP3W3IJgQJ7M5Fi4= -github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.10.3/go.mod h1:jIxhoFIXY3j5+i8UsPKY1jSMSGP8wKG4rHh1nF8fmzw= -github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.3 h1:HFzSq5FvyfkDE1A7Ti4jLypH79cI89g2lAOAfxec/hE= -github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.3/go.mod h1:nikytN6kEOGDn0q0o2NzpF93khMy4sO69ZVnh7D0owM= -github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.2 h1:DOVeRifiygskHYwQUCF/PMieAP2/Q2yj+o7TZxiP5kI= -github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.2/go.mod h1:6T6POkqNtemejwenhFM2l1sipv8saMi+Xewc2Q+4C+Y= -github.com/aws/aws-sdk-go-v2/service/notifications v1.7.8 h1:+KOW2yg8EyKwqpv45u1LK7BEK01AlLkKD0wOj6o5xyI= -github.com/aws/aws-sdk-go-v2/service/notifications v1.7.8/go.mod h1:DKnhbgXWeGgz1mzRZ+0b/jKqB3xy9yuy8LKIHUnv1ZM= -github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.12 h1:yBU2PHHrJCr7rJBsEkuRIomoaFZx/idWgfQPhKf+ZZY= -github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.12/go.mod h1:D6RFOazSGFCJcdxSEgw0ukJ+k2QgFfOdB3dVYNcHPVA= -github.com/aws/aws-sdk-go-v2/service/oam v1.23.3 h1:HOEc+yEjv38MAJWP+iT2HNILzq7/zAlN0uLQz3Fz1NQ= -github.com/aws/aws-sdk-go-v2/service/oam v1.23.3/go.mod h1:pz+AbYsaeY7dySgPSGl/Zr1zPJMOyOE/mR9+XtyhV9c= -github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.4 h1:Icp0wxQQJhKXiSic7BeYky9JnNdXoheSDQ+iJ5hPskU= -github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.4/go.mod h1:2GvP5es3RAok0PA4Fx95x5fJ0Xn7muSESZFHw1vp1BM= -github.com/aws/aws-sdk-go-v2/service/odb v1.5.4 h1:hYYhhdEqm0iOTXUX8Q5Ca4hPOy78t7P5NKxGW4ICogQ= -github.com/aws/aws-sdk-go-v2/service/odb v1.5.4/go.mod h1:jhCkBILzvRrCEyX2Wl+xn2BOBmrBedW7On1p1gzf3rA= -github.com/aws/aws-sdk-go-v2/service/opensearch v1.52.10 h1:XqBD+3vofEFRqlKEmtN2/0RtZ/yVSDOXHspT4D7GMEo= -github.com/aws/aws-sdk-go-v2/service/opensearch v1.52.10/go.mod h1:iVj8M5s79sFaX4eWUnBihWn+7PPHSdmCH6EqWQoySE4= -github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.2 h1:klZ+r7LYiIiuly4jKAaeSXvbka2NSMcAG3NnKJETxgM= -github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.2/go.mod h1:oLdL9Vhmp6N8H/f8Ttak+0SdUKk1E7Iwe84z9doZ87Q= -github.com/aws/aws-sdk-go-v2/service/organizations v1.46.2 h1:loLB5u3fRKxsz+gSnJCoCSV+0w3JT5C1nyihgOblc4w= -github.com/aws/aws-sdk-go-v2/service/organizations v1.46.2/go.mod h1:tnWiGtBYsKa4astPsL0YPaysffUcAp2C4Y0cZw6ZzGA= -github.com/aws/aws-sdk-go-v2/service/osis v1.21.3 h1:87bUk7OyHl5/KLqZkgyebx5sSFZj3ZFSCbONN8bkcZA= -github.com/aws/aws-sdk-go-v2/service/osis v1.21.3/go.mod h1:QGkOJj++ElJ2YmESnpRrwM7R38qf4ViMCCFIZVOHNgg= -github.com/aws/aws-sdk-go-v2/service/outposts v1.57.4 h1:ogkjd1atvA8QPECHRwFxzm1OBoRKtctlzDIgI8KgKlE= -github.com/aws/aws-sdk-go-v2/service/outposts v1.57.4/go.mod h1:rPsJtWQtj/V1kgdAFC9WyswmqrvJaOgHfLwibijL52o= -github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.1 h1:4hNk4DkVShk2Ngq/VM/gMAkqBAWXJH5ZrOF0l4AyHP0= -github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.1/go.mod h1:GqTw5UV5AIwHTpaKzHzt2KjETEO+hoBdIxbA/s7Fxzc= -github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.10 h1:gB/aU/UNi+E1AmpLKQw3UJLJApyjn9TKNVzhb8aX4wY= -github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.10/go.mod h1:GeIQIKjm5JhrcR/BB7x5DWPo2Bfhfm+Ui4w8x5TFz0I= -github.com/aws/aws-sdk-go-v2/service/pcs v1.14.4 h1:z8ZWB9WbgiePC+cFfLeoQ+swnH4R/p48SWTiddN/5Ko= -github.com/aws/aws-sdk-go-v2/service/pcs v1.14.4/go.mod h1:lG3E3PuHFsK508yCPxHBtDoM7S5bVuZOCaqECHkEM64= -github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.10 h1:3sFhl9X+yE2gReZ3bTcYdDw1eQ5KW9UQaIoZntfAK7A= -github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.10/go.mod h1:TmcGUQZpICbZKTvzURsi73eQMl/psfpgY/xse7pPf/4= -github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.0 h1:QDvzfJjdWFuy1KO9nfxzHSL1o7MVEM189YvEZ0NHQ3U= -github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.0/go.mod h1:eGDzes2BcpQDsKZ37KPgnrUujaLjA6B9doY+PmlROQE= -github.com/aws/aws-sdk-go-v2/service/pipes v1.23.9 h1:fO84zgGs2EguurOOTaDmnlvnqwnn3dN4amkKObK6jus= -github.com/aws/aws-sdk-go-v2/service/pipes v1.23.9/go.mod h1:vIeg0zOANsRAyRGYsXQLdaYh9XGmKMhY8r20NzkPPvg= -github.com/aws/aws-sdk-go-v2/service/polly v1.54.3 h1:luhA1og9lYf6GsNxZiVtY/ABnL/9/EvhlOPooH3sJew= -github.com/aws/aws-sdk-go-v2/service/polly v1.54.3/go.mod h1:IR55PMJ6jNjEu62EfCEP5v5oB4oGuRL3DvECBy0X1ps= -github.com/aws/aws-sdk-go-v2/service/pricing v1.40.3 h1:hyCsLZJCCn3pBNPmq/SUJARPSDSie+LYjvyZiWDbWmI= -github.com/aws/aws-sdk-go-v2/service/pricing v1.40.3/go.mod h1:qlgOQg0EL8GDTAPe5CcbgpaJGfSzA6ndypXctsMiW9E= -github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.10 h1:V/ryIi0WAS9kosnR2+hmexVnQKasn2bAsg1DVs8qbfs= -github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.10/go.mod h1:GrEm52MEfQXhAXsGFZEFiPt8AKvlD1uMkJ8KWRdlft0= +github.com/aws/aws-sdk-go-v2/service/m2 v1.26.5 h1:36dEuPAWGx9dmFvxAbsaoueMqEx24E1VYQEcJiaamF4= +github.com/aws/aws-sdk-go-v2/service/m2 v1.26.5/go.mod h1:TcXLSXdIt/knslZsVOxLz85TXJHYftEnZp2Pkqcmd/g= +github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.4 h1:9RF/3sDLXY55O2MJJl9iejd1IDuTMztpNdpYe9BigVk= +github.com/aws/aws-sdk-go-v2/service/macie2 v1.50.4/go.mod h1:UqgjJRAxzo2p/JJAaa4U10r468sb5dB7XdTojQM3J6I= +github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.46.0 h1:ZISa5LjOv1UP8/i0NZiFVFn0TRcLI8iceeW4MzyWOlk= +github.com/aws/aws-sdk-go-v2/service/mediaconnect v1.46.0/go.mod h1:h8kJMoJzHMU0zZWycpQpGmcxYLKhrhfC8RI1O4E4lv0= +github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.85.0 h1:IQwKEYP9sQ4USJc+xX5N/P85SyLAsWk0Kxx2Bx/xz4k= +github.com/aws/aws-sdk-go-v2/service/mediaconvert v1.85.0/go.mod h1:69w+ev30uz0EQ+Z3brr3IecMA4D7Pkr3PtnQc0VGEZs= +github.com/aws/aws-sdk-go-v2/service/medialive v1.87.0 h1:nkvCXOE1zFYMaq9A7SMAeY+TWPQ/fe0BTkls8SrfyDM= +github.com/aws/aws-sdk-go-v2/service/medialive v1.87.0/go.mod h1:SRJh9enbB1Urr1hv5+LKTbRlmXlhbjzvy3AwZkB7AHY= +github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.12 h1:jw/o+ERI9EecbrQLGzrzHCPlpjd52ysHRkHV2G3T0lw= +github.com/aws/aws-sdk-go-v2/service/mediapackage v1.39.12/go.mod h1:7As8fD4Tr7DZAKWm0YOPFaoNymtw3xsCUkjQobfsZ7E= +github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.33.0 h1:0kXTtfY0fCyncN3yEf6UjeVRyouqUPLzrDCF/sRJqsE= +github.com/aws/aws-sdk-go-v2/service/mediapackagev2 v1.33.0/go.mod h1:w/Cotl6ORtnl+0i3hsOfzeV3bq5msbjgTrDhN57KTQU= +github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.12 h1:3uZcDQNSq2K8+l26JGiI5ruvs8C4ZjG/uiUDU81LLok= +github.com/aws/aws-sdk-go-v2/service/mediapackagevod v1.39.12/go.mod h1:eiBfqNKAQK1rLuvKJOc6n5r9JZjgvdcMjxHHJlQwO3o= +github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.12 h1:NcvtI4JsJXem0VZSkt2u7ODCF7GZpoXr6hakfgOdbqs= +github.com/aws/aws-sdk-go-v2/service/mediastore v1.29.12/go.mod h1:p0DZlc3953qm+OFFjWYXI4pUVN0Vtx7wxn/0sT6HjrQ= +github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.5 h1:jLxCVjcFucXlpF4LFHMPbmeDjyRP0ssZ0+/RlC1Hglk= +github.com/aws/aws-sdk-go-v2/service/memorydb v1.33.5/go.mod h1:iehQZb2FgCH28RyIL7fJCWgxmjCilIHVMJ3LXuZakCI= +github.com/aws/aws-sdk-go-v2/service/mgn v1.38.4 h1:OSiWqiIVbyUiQcwyuPGc+BJRED9cfp8IV7ToFGitzl8= +github.com/aws/aws-sdk-go-v2/service/mgn v1.38.4/go.mod h1:n6Jxq0qdghot9uUi6ckEeaz0QvYv41DnFnSkNEwkKa8= +github.com/aws/aws-sdk-go-v2/service/mq v1.34.10 h1:LkV65nQNkhPblwXWKB6jree3BEgfPtmC93NFRsp+Nuo= +github.com/aws/aws-sdk-go-v2/service/mq v1.34.10/go.mod h1:ygM6WHFaCHMQ4+Pn3cMqFhWpbc06reGq4VTsv89bBrA= +github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.12 h1:GzwknGap79FTpA5CbbD2OF0rDnl0/bqN23zqwzHkdFg= +github.com/aws/aws-sdk-go-v2/service/mwaa v1.39.12/go.mod h1:1D+jlQDjJVp+zWuj+7fkdWRAId2DbnWm92v/QxcaMec= +github.com/aws/aws-sdk-go-v2/service/neptune v1.43.3 h1:PFGZA4R64W8ZvC+MF4qE7Qkav/2LoexbhpdRAGvrQW8= +github.com/aws/aws-sdk-go-v2/service/neptune v1.43.3/go.mod h1:zZ58Zd5x0GGqnSgDLV4R3C1Xazzg3htNhg3kUpNB94M= +github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.11 h1:aHQda8rOysKlF7xSoPu9Qk5t2Ph5fyvrh/HWNEuNwYA= +github.com/aws/aws-sdk-go-v2/service/neptunegraph v1.21.11/go.mod h1:dUFhAeruwm9ZYvMRk2JU6AR+YFcQ+4h34C3yNmz4T88= +github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.58.0 h1:gH0mo9odFg6ZI2g6pHcvihWMfCEjyOF0U271zEprUoc= +github.com/aws/aws-sdk-go-v2/service/networkfirewall v1.58.0/go.mod h1:wCjIj4guias8uhaV3dqeSag/7v04X3xJQa4Ur9zJttc= +github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.11.0 h1:UiALLI9ec1KVMT+AJcXXIaknC3zkC7zzYoR/9DaX5K4= +github.com/aws/aws-sdk-go-v2/service/networkflowmonitor v1.11.0/go.mod h1:jIxhoFIXY3j5+i8UsPKY1jSMSGP8wKG4rHh1nF8fmzw= +github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.5 h1:yVU4b7twe9pLU5dxkC0D6lUEgcZa7zWizXuRbvHp/d8= +github.com/aws/aws-sdk-go-v2/service/networkmanager v1.40.5/go.mod h1:nikytN6kEOGDn0q0o2NzpF93khMy4sO69ZVnh7D0owM= +github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.4 h1:PmyRpUoTfR2J1CfvGB2qz6kBiOROgDoR95N6CWG2SbA= +github.com/aws/aws-sdk-go-v2/service/networkmonitor v1.13.4/go.mod h1:6T6POkqNtemejwenhFM2l1sipv8saMi+Xewc2Q+4C+Y= +github.com/aws/aws-sdk-go-v2/service/notifications v1.7.10 h1:i3wbNbKZdi40cAs+qyBEtG75DUOpbJJV/HwqGg35DkE= +github.com/aws/aws-sdk-go-v2/service/notifications v1.7.10/go.mod h1:DKnhbgXWeGgz1mzRZ+0b/jKqB3xy9yuy8LKIHUnv1ZM= +github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.14 h1:jbaCixU9rvfTGNli4NSkT1jwJeoVWTKR5vlta/E5smM= +github.com/aws/aws-sdk-go-v2/service/notificationscontacts v1.5.14/go.mod h1:D6RFOazSGFCJcdxSEgw0ukJ+k2QgFfOdB3dVYNcHPVA= +github.com/aws/aws-sdk-go-v2/service/oam v1.23.5 h1:DJqoutE8UpAtbqWeT/T62W3t9scS9ZZKAJJh6dGb8cY= +github.com/aws/aws-sdk-go-v2/service/oam v1.23.5/go.mod h1:pz+AbYsaeY7dySgPSGl/Zr1zPJMOyOE/mR9+XtyhV9c= +github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.6 h1:MsffOU8pULJVmQcvo8DarlR1rXAazOvITj7XuJB3QWo= +github.com/aws/aws-sdk-go-v2/service/observabilityadmin v1.8.6/go.mod h1:2GvP5es3RAok0PA4Fx95x5fJ0Xn7muSESZFHw1vp1BM= +github.com/aws/aws-sdk-go-v2/service/odb v1.5.6 h1:JLUu5UEdUX210Ojg5uTjzeRw5auZe6/10dd1vuCFlso= +github.com/aws/aws-sdk-go-v2/service/odb v1.5.6/go.mod h1:jhCkBILzvRrCEyX2Wl+xn2BOBmrBedW7On1p1gzf3rA= +github.com/aws/aws-sdk-go-v2/service/opensearch v1.54.0 h1:hN7HAN0qO5eLnh08ezJPfqsBBdNj6AWD7w5YQSLtYiM= +github.com/aws/aws-sdk-go-v2/service/opensearch v1.54.0/go.mod h1:iVj8M5s79sFaX4eWUnBihWn+7PPHSdmCH6EqWQoySE4= +github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.4 h1:7ijoIap1uO5GkJR6lzllEYYJxYp31nGQbKuyCbMMCZs= +github.com/aws/aws-sdk-go-v2/service/opensearchserverless v1.27.4/go.mod h1:oLdL9Vhmp6N8H/f8Ttak+0SdUKk1E7Iwe84z9doZ87Q= +github.com/aws/aws-sdk-go-v2/service/organizations v1.46.4 h1:a8FVhpNC4CSPnlXcgHzyIxm2/8LpQ9F60WPV6+tyFmU= +github.com/aws/aws-sdk-go-v2/service/organizations v1.46.4/go.mod h1:tnWiGtBYsKa4astPsL0YPaysffUcAp2C4Y0cZw6ZzGA= +github.com/aws/aws-sdk-go-v2/service/osis v1.21.5 h1:02dpYRwi3zGFWKll5a0IVr2u0g0QGZCB7+PfvtR2eCA= +github.com/aws/aws-sdk-go-v2/service/osis v1.21.5/go.mod h1:QGkOJj++ElJ2YmESnpRrwM7R38qf4ViMCCFIZVOHNgg= +github.com/aws/aws-sdk-go-v2/service/outposts v1.57.6 h1:FXA9OzvJlakCrbvKw3qmLrRG6q3EDt9FZnaS4Tx3upQ= +github.com/aws/aws-sdk-go-v2/service/outposts v1.57.6/go.mod h1:rPsJtWQtj/V1kgdAFC9WyswmqrvJaOgHfLwibijL52o= +github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.3 h1:Cws5mb47NYtqUZxkcCRR/9T0gwXmrXoweeVDeD0sRRI= +github.com/aws/aws-sdk-go-v2/service/paymentcryptography v1.26.3/go.mod h1:GqTw5UV5AIwHTpaKzHzt2KjETEO+hoBdIxbA/s7Fxzc= +github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.12 h1:VIxyAXmasuMqPn26ayhxZX6FK2yD+1iHHL0WDcGVIgk= +github.com/aws/aws-sdk-go-v2/service/pcaconnectorad v1.15.12/go.mod h1:GeIQIKjm5JhrcR/BB7x5DWPo2Bfhfm+Ui4w8x5TFz0I= +github.com/aws/aws-sdk-go-v2/service/pcs v1.15.0 h1:jODJJvvzp3BtBc2rREK0foH2e8vyEhaCZ2z+nnOI/oE= +github.com/aws/aws-sdk-go-v2/service/pcs v1.15.0/go.mod h1:lG3E3PuHFsK508yCPxHBtDoM7S5bVuZOCaqECHkEM64= +github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.12 h1:fvCN4jZKj+gNhl/miNYBAs0OnVDKYwqrWLjpWdIV/zU= +github.com/aws/aws-sdk-go-v2/service/pinpoint v1.39.12/go.mod h1:TmcGUQZpICbZKTvzURsi73eQMl/psfpgY/xse7pPf/4= +github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.2 h1:LUeDu/bWhIz1eO8ANBlxcxm7bjv3BY6r4fF7p2CIDQE= +github.com/aws/aws-sdk-go-v2/service/pinpointsmsvoicev2 v1.26.2/go.mod h1:eGDzes2BcpQDsKZ37KPgnrUujaLjA6B9doY+PmlROQE= +github.com/aws/aws-sdk-go-v2/service/pipes v1.23.11 h1:PiQERt6yzJUeuPtcKgZ+HKhcJfFdLEU75rPX4O0XCqY= +github.com/aws/aws-sdk-go-v2/service/pipes v1.23.11/go.mod h1:vIeg0zOANsRAyRGYsXQLdaYh9XGmKMhY8r20NzkPPvg= +github.com/aws/aws-sdk-go-v2/service/polly v1.54.5 h1:72kDYtnJAiFF/9xzKpPEUZBGNetCC9tiNK6K8Moypkk= +github.com/aws/aws-sdk-go-v2/service/polly v1.54.5/go.mod h1:IR55PMJ6jNjEu62EfCEP5v5oB4oGuRL3DvECBy0X1ps= +github.com/aws/aws-sdk-go-v2/service/pricing v1.40.5 h1:H10gQvrDF1MX5vzVlTgQxH4UipAZunirvOSLHLO1QMc= +github.com/aws/aws-sdk-go-v2/service/pricing v1.40.5/go.mod h1:qlgOQg0EL8GDTAPe5CcbgpaJGfSzA6ndypXctsMiW9E= +github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.12 h1:5cOyDQZyhL094oRlmMiRtn1QhaESZWyTvIBIJkMMozo= +github.com/aws/aws-sdk-go-v2/service/qbusiness v1.33.12/go.mod h1:GrEm52MEfQXhAXsGFZEFiPt8AKvlD1uMkJ8KWRdlft0= github.com/aws/aws-sdk-go-v2/service/qldb v1.32.2 h1:tSctQisNHgXnDmyoOdLXkSQmHYo5yPQuvYK+4c4QiNI= github.com/aws/aws-sdk-go-v2/service/qldb v1.32.2/go.mod h1:m6bmXbLs5XiGnTLcgKn9eNk5+GCO5e/wHQsIuN7d1Tw= -github.com/aws/aws-sdk-go-v2/service/quicksight v1.95.4 h1:c0jYoV8b/sLbu8lPGd13mN3l3nOs1drpBHyXQxPkr5I= -github.com/aws/aws-sdk-go-v2/service/quicksight v1.95.4/go.mod h1:I8KrlgJxmNejc1VR3BWJ+J/uJuoLgaqTS/u/tJHIKA8= -github.com/aws/aws-sdk-go-v2/service/ram v1.34.11 h1:I8owg2znzlb5VJj5eeYOnsHS8iel8WPGIAkcveFqyLk= -github.com/aws/aws-sdk-go-v2/service/ram v1.34.11/go.mod h1:XVmWvCpgKVITq+ThzyDzJkCbVycgzv8P8KzdhwijsyQ= -github.com/aws/aws-sdk-go-v2/service/rbin v1.26.11 h1:+6YOD+rzIionatIPp5qpYzoH/aRwfpIR1dMVyZntPRI= -github.com/aws/aws-sdk-go-v2/service/rbin v1.26.11/go.mod h1:HSYlwezMfkOFle385IG72Np892kUVbGvYsdM+BEG+9U= -github.com/aws/aws-sdk-go-v2/service/rds v1.108.7 h1:q/854OSiNabB+vVTXG15TPHEcY3WpFB31JMy71Yr69w= -github.com/aws/aws-sdk-go-v2/service/rds v1.108.7/go.mod h1:mGQNxzRLKlj1cQU5uaMIjAhle0HkSeZDwoPfP+/nRYk= -github.com/aws/aws-sdk-go-v2/service/redshift v1.59.5 h1:Sg/jqBPF7A1UYtiGsXwVzyKBqfRjGzKola3RbH7cLwQ= -github.com/aws/aws-sdk-go-v2/service/redshift v1.59.5/go.mod h1:nroSRWOCQNS3b/vooHNsxwT5KRXzO+A8ouHyKsQenRc= -github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.10 h1:gYym5cRE9v1OEjwZLTWB5/uXDRePT11wiumfq49ffcs= -github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.10/go.mod h1:9beFz0fgqQr+Lkcz0lD54cquuuPUIV54fRbnLDQ7MNI= -github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.13 h1:h1LRp/NOYs+7OPyHnkFsVnLjjtdP/JhMK3vty1SZAG8= -github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.13/go.mod h1:fgg+LQ1jrDB3K18lra3Qx4tTGCZE9yX+eUQzxUjMhAs= -github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.9 h1:NbwYC74ooF+i6GYHhsO/HfSKizrH8p2cw70IURp0K2U= -github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.9/go.mod h1:r0M9WlvDeB2fPsZk2es9ZrjyUNIRPKoxm8xEU+CKbE0= -github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.2 h1:+wYMhcZrpqSNRXHY7wdylkgKvOx5NojGwgvUuvAgJoo= -github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.2/go.mod h1:efsKs5+XMP1JeFtYuLvLfHrBN3GmitdOUgKqDW2Xp9M= -github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.4 h1:WiOOC5M8n45IG+RaJD3N6q+Mv2VHbQhCkJM7NdwAyDI= -github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.4/go.mod h1:3A/lTLOEWLwbIFsOrriZuVdhibD0E4riboU0VaoV1mc= -github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.12 h1:/FDiAb1xNW3rnd/LHRhMLP74aVoAjDC1jkLA2EnhU2M= -github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.12/go.mod h1:6k9FPdJPkYmyrO0PFg1R+k3Rw5RYJT4MGdNqvodIGGY= -github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.30.11 h1:Ry8CcxRQeHUa4fw2yg+3xMC1BwdeQ29ccyWX+g+KPqw= -github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.30.11/go.mod h1:+nL0z6xUm9NK9bOAkam66NQDgNH8Qa6T6SS3f8dkzXU= -github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.10 h1:WvM1EXw1uU/75IS8QGgUtRahGTN5bIoIw5wx/1PufOg= -github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.10/go.mod h1:/WVeeJKvbKmaTWEtt7y2005MHRKlh+Ee5Nr3qmPMQpY= -github.com/aws/aws-sdk-go-v2/service/route53 v1.59.3 h1:YZrYzMaF4J0GbZwxlgSwXgHLBnYzklW3GakKFoOJQik= -github.com/aws/aws-sdk-go-v2/service/route53 v1.59.3/go.mod h1:TUbfYOisWZWyT2qjmlMh93ERw1Ry8G4q/yT2Q8TsDag= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.8 h1:77szvLM4Q3adxgXKL0RzgygnRi0WwgV5j4Nyj+xF7dU= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.8/go.mod h1:lxTo/orhKjYQIgzo0ED2KQyU5yC7zPw6vgImZBp5Opc= -github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.10 h1:jP72mUNCxMX25D6KOJzgs9lWpEjaD3KWDaa79c/pK/o= -github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.10/go.mod h1:Nvyw2yEW8po15FmApho3Biz63mgQirrO6dxseYQb1u8= -github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.3 h1:OE8VfFmM2yrBOF9OTwmsxM8+yqOY/ENMf7JJBUrKbWs= -github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.3/go.mod h1:uuKkzsDRNyxWABenHqS3Ms7KoEUf+3EHsNCnMBVMslo= -github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.10 h1:c9HRNESb/DZO1JmgOXRp6xf0q9sIpr56fdNE7kbXAyA= -github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.10/go.mod h1:FPoma320xUxwC7BRaqJPYjpyIgbuxrAF//JdP9ybfjQ= -github.com/aws/aws-sdk-go-v2/service/route53resolver v1.40.10 h1:nsmB5RhnPqbDDK0ZfA2fmlv2+BF6G1ejIAVLfVNyJKQ= -github.com/aws/aws-sdk-go-v2/service/route53resolver v1.40.10/go.mod h1:RtTRuj33VUDMd7i7eDEuhX2x69JWtPkWODE2b2TeiS4= -github.com/aws/aws-sdk-go-v2/service/rum v1.29.2 h1:tSG82w0z96VIuR+f30qXknzk5DHH0ezj8qKsWXEbMe0= -github.com/aws/aws-sdk-go-v2/service/rum v1.29.2/go.mod h1:aoij2zkJWvNtGzPvyaOZtNazKNjMBEVOmdDystHnh8g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2 h1:xgBWsgaeUESl8A8k80p6yBdexMWDVeiDmJ/pkjohJ7c= -github.com/aws/aws-sdk-go-v2/service/s3 v1.89.2/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw= -github.com/aws/aws-sdk-go-v2/service/s3control v1.66.7 h1:YMrm0OzfAv9KKuMYqV4reUMFNn9RnpRz3cBtIpsn8Rg= -github.com/aws/aws-sdk-go-v2/service/s3control v1.66.7/go.mod h1:c+ERB7DbWT1uR6QvBn7W0gB2YczXacCEoLegFLwPAE8= -github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.1 h1:PLLJqTqozJOGAWidlJIZhp/15PDLi1livXevOs6ZZ1k= -github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.1/go.mod h1:4XtnGsaxnIiUsurxxTMzn9Wl9/utEAN46rcMPVKLGAM= -github.com/aws/aws-sdk-go-v2/service/s3tables v1.10.9 h1:v3sRC7iJnffnh2WJpxufO09tnu/1o+d0wtSpq9HD2FE= -github.com/aws/aws-sdk-go-v2/service/s3tables v1.10.9/go.mod h1:t1l6loaBQWttife9bosS3OspbGv+CP18UbGxMIQie4A= -github.com/aws/aws-sdk-go-v2/service/s3vectors v1.4.12 h1:Bxhm/mRfKKNsKOIS0REnk6Ll6exvm0hPwt2lk51nF+Q= -github.com/aws/aws-sdk-go-v2/service/s3vectors v1.4.12/go.mod h1:+sgMaDJqPLY3w2QXsvbhgSlvIaQ4+4cYk6Cdp388Swg= -github.com/aws/aws-sdk-go-v2/service/sagemaker v1.219.1 h1:1CvE2DPquhIlym4eqtZElsmIs9sTHmMT7nHHqYgwzRo= -github.com/aws/aws-sdk-go-v2/service/sagemaker v1.219.1/go.mod h1:JnrlXHI1oM/gVNI0/NH1Ru4UZr4sWx/WZclCsJtbmCM= -github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.9 h1:DEk7LCDFI32irAvdrsVtqUr5OHtojMUL0JcUXjvRUB8= -github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.9/go.mod h1:UohrBXfiKjUlaqaMzj3jtBBfrNFSCjq+LLwDbtsvAIo= -github.com/aws/aws-sdk-go-v2/service/schemas v1.34.1 h1:pDHoETz2rncUE0tny2qug/GarMIcRaYD2shjjoXMxN0= -github.com/aws/aws-sdk-go-v2/service/schemas v1.34.1/go.mod h1:ipui3c5k/ozPT734rqfqsFgieDEny9ABk4sp7zCWjkM= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.11 h1:DouhxUREBjfnNJFp1yNn/p1Gk5pzr1YNixcIOIudI2g= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.39.11/go.mod h1:QgVIY03/XoQs2iFr0MbQuQ/Tf1RwlkOvuySWMh1wph4= -github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.2 h1:JhuxQSODGqdC3H0/K/4mtHlGiLdZyA8kANEA/Aexu/k= -github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.2/go.mod h1:QaXNTOs7OkNR7y9uFWajUymXwUh28Q7cTz3tqWiE6sc= -github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.2 h1:UtpQrbgUyjeTTZMgsB1VhVypFNAaIhAaS92pZvIIzD8= -github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.2/go.mod h1:8psZ/OINrXmUJhyXWm0NzLaKP5bp1t/dh0/D2Pj/YAo= -github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.1 h1:5OGkJWlC0B6jiyl69Q8ufrHweM4h0RsPqKtwSXgAvcg= -github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.1/go.mod h1:OmVOd812JbwvNOwaQMpeMmj2bnN6dgUZnVaD1UIvyVg= -github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.1 h1:z39h5nEO73EhUUzWvXN9Pg/WhA54HlCrBEePsKHgTUE= -github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.1/go.mod h1:fA60HaKYi8WBwj1uf+n2sZkyefVWWUTkKB69Th3pTB0= -github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.10 h1:eaBZKLRCRUs7THKWGT+mpd57ZoP9f4m9nzJ17YnA3Kk= -github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.10/go.mod h1:H/pz3dQJmZHdKf3DMgD0znZwoP0h8Umx9uPhBRXOkxE= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.14 h1:O/7WE5d5cWpOA71mudgEvyawhAPEI/C3ZTkFYZFSyNc= -github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.14/go.mod h1:lYyuDbeQ6vtjRP4gb9h2MReluEb0US5u+07X84akGKg= -github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.5 h1:nifPvTgsPLFy9a5eAWQ/+oSdY4MOvzgHpGZhvJBZ9vo= -github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.5/go.mod h1:TvpkfbD0qaLoadCivfVCzpgavaEJvmRpG0pzZOo4pX0= -github.com/aws/aws-sdk-go-v2/service/ses v1.34.9 h1:hrUBTmbCLLQ+X21wdcoK78sjRW3HGspp/vkAL3TkMx4= -github.com/aws/aws-sdk-go-v2/service/ses v1.34.9/go.mod h1:CeGX4LAFCsrBp24qazKmO/dwxghNCGbAoTbi64dGSEM= -github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.2 h1:na42MutKh8BRm7cKhf/h57kXPVP6yxhHJD1wyrJ4azo= -github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.2/go.mod h1:uxpQTTvKs2FUajNzmQic0lqMB5X0zjX8jpalkvkhIQI= -github.com/aws/aws-sdk-go-v2/service/sfn v1.39.11 h1:ALX8T3GCfowrsodpsh6WDM55BFG1APIT5pKNSMpRHsg= -github.com/aws/aws-sdk-go-v2/service/sfn v1.39.11/go.mod h1:fhG61r7sW7WsxXcZAips5CFQta1i2sQwRaEQeQwSrks= -github.com/aws/aws-sdk-go-v2/service/shield v1.34.10 h1:KUgzVt14lPJ1vLWYTIa4rAfDgeQwWk8S4NxtpIwPoJI= -github.com/aws/aws-sdk-go-v2/service/shield v1.34.10/go.mod h1:6B2EvRYLO2QsWbNoEsxazaKhVufZBDPApqPkpQ2arJI= -github.com/aws/aws-sdk-go-v2/service/signer v1.31.10 h1:6PDee9gY2Hho7TdAu9vL4qG7idlMds1jNaafA5d874U= -github.com/aws/aws-sdk-go-v2/service/signer v1.31.10/go.mod h1:F44pi85d2IzaTcwWULuLl2cdYjFkKr948NbU7gCmcKY= -github.com/aws/aws-sdk-go-v2/service/sns v1.39.3 h1:/i7MD7ZNdjf9BSiD5KQtS5G00902dU477E6zaR85eBE= -github.com/aws/aws-sdk-go-v2/service/sns v1.39.3/go.mod h1:1LvRsmADXI6174y66InuSDQiEztkQgCLbcw62VLC0FQ= -github.com/aws/aws-sdk-go-v2/service/sqs v1.42.13 h1:gfwPJhrWDHUeisN2p7bji+wocVmoJLJ3jgEQCKSiiMo= -github.com/aws/aws-sdk-go-v2/service/sqs v1.42.13/go.mod h1:ZS67woOy/ftzvKK2+P53u2NPqImAPTWz+hBn+tchP7k= -github.com/aws/aws-sdk-go-v2/service/ssm v1.66.4 h1:UmkF0ipNy0Ps6csJl/ZRJ3K+DWe9q0A7LT3xfxoHbgg= -github.com/aws/aws-sdk-go-v2/service/ssm v1.66.4/go.mod h1:uNHuYAQazkHqpD+hVomA2+eDSuKJzerno7Fnha6N6/Y= -github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.3 h1:kLuz4YTmXq+aINLty7O+x0XolYNYNK0feRIJLYOfmbw= -github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.3/go.mod h1:m9mkIFFGnEY00U3IpPs/TZLbbgOxARLDtqsDbGqzjik= -github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.9 h1:TWDKCXLDwxAhTHBqLUvKaYSN6Nim+ZvLIn5z4gl/Cag= -github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.9/go.mod h1:TUCeZ43VbibNN5TTa0oWium4Cj2ee/Xg93xNRVx+iUw= -github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.10 h1:luxs8NtvzPvhSKrZuRKtH+Fh11Ou/+qpF8RP7Xlgslo= -github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.10/go.mod h1:h/ogxk4gxt67ItMvhzCJSST5AHjaYYuMC/wdLMBLOrI= -github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.9 h1:xPbieVqdcD/IlQKyAzmW+cet+XbyhYydsDhSXJ+ISf4= -github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.9/go.mod h1:9/Q7dAszR79doau18RBveSfZX9RASAs4Tubh196QR8A= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 h1:0JPwLz1J+5lEOfy/g0SURC9cxhbQ1lIMHMa+AHZSzz0= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.1/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= -github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.6 h1:UDapqbyf6JQcmFlYdzcwgModRtkuGvf9JBYDiza/mrQ= -github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.6/go.mod h1:CzDlwLoYGIK0Q7ISrzqCD1/Zgf6nsIdct4f0ZoyKoHI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 h1:OWs0/j2UYR5LOGi88sD5/lhN6TDLG6SfA7CqsQO9zF0= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= -github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.2 h1:gsG5dor2az8bej9BK1n00zk3azWSicYgnXXpUKwt6Nc= -github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.2/go.mod h1:JKIFhh/dRv/Ft85RarJH3G3ewl419X6gmD/1fEXjDnI= -github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 h1:mLlUgHn02ue8whiR4BmxxGJLR2gwU6s6ZzJ5wDamBUs= -github.com/aws/aws-sdk-go-v2/service/sts v1.39.1/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= -github.com/aws/aws-sdk-go-v2/service/swf v1.33.4 h1:RYnaNdZP2odU51vYnGW2PO9ubU455kW6JTbLiPmINNk= -github.com/aws/aws-sdk-go-v2/service/swf v1.33.4/go.mod h1:mmUGhXHOTZ0YLexnps/Zn0u5T+p9QkpGRpXuf5L2b7A= -github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.2 h1:ZwpnnzJUcb1MiH7HeotM4w2tAXATbJY3GSGHD/9QrVM= -github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.2/go.mod h1:NoN2h4JljGuHzAYWNB3WVGKnuKczRbHoqVh5Z7Z4YdM= -github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.10 h1:U+qf8OLSdxYntNgJhugFBuVs992P49gkYoeldflom6I= -github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.10/go.mod h1:mch3G+DUo5AjLDfRe7XL3QhVf1K+tk+u1WQiAj5tvzs= -github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.4 h1:3gsL0XSo0kEEhiejnaZmbaJi4iyPbekbIs/tplNA/98= -github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.4/go.mod h1:ATSASzt7xr2/Xcj8ZjMQg9woL5SyhrghAPCb7nArWVY= -github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.3 h1:aCLSUkSfQWKTFYW+lwgM6BNIQ2tZ2DVzXlRJeTZcNY8= -github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.3/go.mod h1:b34PXpekNN9TeyqzUNcFiOEAm3DFd4e+viL/XbQtzuk= -github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.9 h1:dxRHB2qTysfdmeDNV2X2HMP3OAvz0WPZs+SLMZhey2I= -github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.9/go.mod h1:WOhN8208dG/kUp22L0kch06lMtCQJ/+Ypv2W3TTC6vg= -github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.4 h1:TD/9gwYUVEQHUs1Z08iTH3krJ1Z/TlJc+ByrD2FQ4C8= -github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.4/go.mod h1:juatw/4IEOV9unN2B/ZmVXIGA8YnhDTXzY/ZdIBS11w= -github.com/aws/aws-sdk-go-v2/service/transfer v1.67.4 h1:MzHFkeGONTed2UaI8sA36lI5sKwvL2j+wOTinw0Pe4A= -github.com/aws/aws-sdk-go-v2/service/transfer v1.67.4/go.mod h1:X1hqrnuqgk5EY3Ic+agUr6P4/CJCrp8HrcC343qi/74= -github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.29.9 h1:NYKTbEwnpUEnfC48JCtlxZe01lwymCCQykJQAk3l5ds= -github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.29.9/go.mod h1:m3YeM8yB49t1fzKYEe43wiowaSO7x/3YmHS/UGOaks8= -github.com/aws/aws-sdk-go-v2/service/vpclattice v1.19.4 h1:xKm2EasIL5Nlt1GTUwzceJwlsWU0bt3aCnrD8e8seNA= -github.com/aws/aws-sdk-go-v2/service/vpclattice v1.19.4/go.mod h1:fp9PvIVx7/jyef3CaWCemFPGK+ghu2Du2XJFGaqc4iE= -github.com/aws/aws-sdk-go-v2/service/waf v1.30.9 h1:C7RzuDKL7ClRunLCUq7YIZ9fm/InzZub4gismnTJ5bk= -github.com/aws/aws-sdk-go-v2/service/waf v1.30.9/go.mod h1:/wwPzZRBcPxG/kAOAzei/UX/FKo2H+aZcx0x99xJPpA= -github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.10 h1:wJ7JtFsctEc/A5XzBQnNPR6inkmc1JrOedkn6kQJjUM= -github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.10/go.mod h1:eaFrizONYIw5QJPDxoBUr8NNM21ISTZDjFhkGVt4NZY= -github.com/aws/aws-sdk-go-v2/service/wafv2 v1.68.4 h1:vcsrFjqOXQnerenkA0/RwskchKgFeP7eJUgOq8X4VSs= -github.com/aws/aws-sdk-go-v2/service/wafv2 v1.68.4/go.mod h1:RtLkquPOQfQASVPWLuXr4hJgaZ5ChNq7eWahkj/CoCQ= -github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.10 h1:vybsh+OcmReX2OnJ5TJa6OixiEH8aCrUchqzAdiv9a8= -github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.10/go.mod h1:t6nyl94d8gQdt34LEo0SH4uGPNruy0T3oMaxcOHdWUU= -github.com/aws/aws-sdk-go-v2/service/workmail v1.36.8 h1:oHtcXkhT12ePAHIaagvFTxtLAI9rtGnwQm/PmvqKCrQ= -github.com/aws/aws-sdk-go-v2/service/workmail v1.36.8/go.mod h1:JW6rMNuboHOnWx7I1fZfHAG1kcUiBZfTkZuD69oNw2w= -github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.2 h1:U1NCC1loRNJZmPyZ4fChpmaXXMNc6Z7sobgKcaIJ8KY= -github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.2/go.mod h1:TmJI48Dm4ftRxBmMoZOeC8Et2WEStJoPpv8BoXZ/eZw= -github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.33.3 h1:79PtELyWQItacygUX3OdYvBBbGuZ4jdhlcRbiTM00tE= -github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.33.3/go.mod h1:V4nPCxgIBn6Yf5JhnI3Cs0iKVTB+wkzXG8fEGYqLYkU= -github.com/aws/aws-sdk-go-v2/service/xray v1.36.9 h1:oxLVMnJFpR7VSUMsPk0Uel0CbVE/tvTQWMp8g1GAuS0= -github.com/aws/aws-sdk-go-v2/service/xray v1.36.9/go.mod h1:JghyUyM7u0syGGk+S5Res2mLfceuyLigCgtcrpsEESM= +github.com/aws/aws-sdk-go-v2/service/quicksight v1.96.2 h1:OLAvMy2oEGGNRh7qjf+cGzupp/dEW57yH4oJ8eLfp9E= +github.com/aws/aws-sdk-go-v2/service/quicksight v1.96.2/go.mod h1:I8KrlgJxmNejc1VR3BWJ+J/uJuoLgaqTS/u/tJHIKA8= +github.com/aws/aws-sdk-go-v2/service/ram v1.34.13 h1:cr/kal5RvNdcBTmjjzOaRoBALpH9I/owczic7k/Ir18= +github.com/aws/aws-sdk-go-v2/service/ram v1.34.13/go.mod h1:XVmWvCpgKVITq+ThzyDzJkCbVycgzv8P8KzdhwijsyQ= +github.com/aws/aws-sdk-go-v2/service/rbin v1.26.13 h1:NHQqKZhCNB6K7hNanxoMKZQ9ZSY7Osg9wJ/4JFmY4lU= +github.com/aws/aws-sdk-go-v2/service/rbin v1.26.13/go.mod h1:HSYlwezMfkOFle385IG72Np892kUVbGvYsdM+BEG+9U= +github.com/aws/aws-sdk-go-v2/service/rds v1.109.0 h1:kAHatNQ1iaWVqVoFcZr5k0+o3dNSrnd+QZRFq4uTvZY= +github.com/aws/aws-sdk-go-v2/service/rds v1.109.0/go.mod h1:mGQNxzRLKlj1cQU5uaMIjAhle0HkSeZDwoPfP+/nRYk= +github.com/aws/aws-sdk-go-v2/service/redshift v1.60.0 h1:Kmh10uuGvak38mlg3FcveihltgP5rXbVcguCj9j3Ms8= +github.com/aws/aws-sdk-go-v2/service/redshift v1.60.0/go.mod h1:nroSRWOCQNS3b/vooHNsxwT5KRXzO+A8ouHyKsQenRc= +github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.12 h1:oGiE4s2UAJmarRMSjui8/um4sqXnk2LFwPL+A1KV3UI= +github.com/aws/aws-sdk-go-v2/service/redshiftdata v1.37.12/go.mod h1:9beFz0fgqQr+Lkcz0lD54cquuuPUIV54fRbnLDQ7MNI= +github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.15 h1:q9nTCnHFttPjoz2vMC7u35u4jONksuXE060nBOcXD6E= +github.com/aws/aws-sdk-go-v2/service/redshiftserverless v1.31.15/go.mod h1:fgg+LQ1jrDB3K18lra3Qx4tTGCZE9yX+eUQzxUjMhAs= +github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.11 h1:bs3xqr92wJuHiHkNhlkipDe2HSY1LZ4hUkEAek/N4X4= +github.com/aws/aws-sdk-go-v2/service/rekognition v1.51.11/go.mod h1:r0M9WlvDeB2fPsZk2es9ZrjyUNIRPKoxm8xEU+CKbE0= +github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.4 h1:8yORXc5cW+paBUU1f7z41+ZpwMjt4FHUS3kJEC+YQo0= +github.com/aws/aws-sdk-go-v2/service/resiliencehub v1.35.4/go.mod h1:efsKs5+XMP1JeFtYuLvLfHrBN3GmitdOUgKqDW2Xp9M= +github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.6 h1:kkoaQ06wQZ5AlqoJ+QYaqMs/WSho8Eii+E++PI5g+H8= +github.com/aws/aws-sdk-go-v2/service/resourceexplorer2 v1.22.6/go.mod h1:3A/lTLOEWLwbIFsOrriZuVdhibD0E4riboU0VaoV1mc= +github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.14 h1:257Y5fn4QZOqofLk8ckt9yJT8LV57lpDEHKO4lchu6U= +github.com/aws/aws-sdk-go-v2/service/resourcegroups v1.33.14/go.mod h1:6k9FPdJPkYmyrO0PFg1R+k3Rw5RYJT4MGdNqvodIGGY= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.0 h1:W8c1GPeHBlwIeuz+DuwvYaoRBrSDy1Cp8DwXIzXTAWg= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.0/go.mod h1:+nL0z6xUm9NK9bOAkam66NQDgNH8Qa6T6SS3f8dkzXU= +github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.12 h1:voPlA/Poy1EatBhjehk4yVWnC+os9+Wn0VwxAB6aPzs= +github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.21.12/go.mod h1:/WVeeJKvbKmaTWEtt7y2005MHRKlh+Ee5Nr3qmPMQpY= +github.com/aws/aws-sdk-go-v2/service/route53 v1.60.0 h1:UlmdpHo/xdaEB/80wOqcBVkzsPdmct02FuOfg5Rrd3U= +github.com/aws/aws-sdk-go-v2/service/route53 v1.60.0/go.mod h1:TUbfYOisWZWyT2qjmlMh93ERw1Ry8G4q/yT2Q8TsDag= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.10 h1:+eeUZjA6+GoTYmFjOlfx21du3eljT6fea39jI3TWjDw= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.34.10/go.mod h1:lxTo/orhKjYQIgzo0ED2KQyU5yC7zPw6vgImZBp5Opc= +github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.12 h1:6W3ERfxp0q+oNMinc59z4Uzcd5vDC4NOsIxFl71CNmI= +github.com/aws/aws-sdk-go-v2/service/route53profiles v1.9.12/go.mod h1:Nvyw2yEW8po15FmApho3Biz63mgQirrO6dxseYQb1u8= +github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.5 h1:hT6/2e3FTRRh/QPYW73GRJlLZLH6hqxDn+F76EL1Gxg= +github.com/aws/aws-sdk-go-v2/service/route53recoverycontrolconfig v1.32.5/go.mod h1:uuKkzsDRNyxWABenHqS3Ms7KoEUf+3EHsNCnMBVMslo= +github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.12 h1:Iury32NIQy7GGFzQzPAUJlydeeo6O+Gf1iheLW8Ax9Y= +github.com/aws/aws-sdk-go-v2/service/route53recoveryreadiness v1.26.12/go.mod h1:FPoma320xUxwC7BRaqJPYjpyIgbuxrAF//JdP9ybfjQ= +github.com/aws/aws-sdk-go-v2/service/route53resolver v1.41.0 h1:8dRPme2++LKhXPTD3VbiCGkwZ1tfPgwjkFwhpiMF1Yk= +github.com/aws/aws-sdk-go-v2/service/route53resolver v1.41.0/go.mod h1:RtTRuj33VUDMd7i7eDEuhX2x69JWtPkWODE2b2TeiS4= +github.com/aws/aws-sdk-go-v2/service/rum v1.30.0 h1:EVwrOhq7sTe0luu/k/blau3VyU4ub/Mkw8yuTbF4yuU= +github.com/aws/aws-sdk-go-v2/service/rum v1.30.0/go.mod h1:aoij2zkJWvNtGzPvyaOZtNazKNjMBEVOmdDystHnh8g= +github.com/aws/aws-sdk-go-v2/service/s3 v1.91.0 h1:b8FQI84BFRqCHjInLKS7bo+iSH8oVJ9C2noKC2H3jwY= +github.com/aws/aws-sdk-go-v2/service/s3 v1.91.0/go.mod h1:+wArOOrcHUevqdto9k1tKOF5++YTe9JEcPSc9Tx2ZSw= +github.com/aws/aws-sdk-go-v2/service/s3control v1.66.9 h1:1GWUaLfzsa0AzsRQW3KUNkO1ZnD7ngR1aPedX9HwqxY= +github.com/aws/aws-sdk-go-v2/service/s3control v1.66.9/go.mod h1:c+ERB7DbWT1uR6QvBn7W0gB2YczXacCEoLegFLwPAE8= +github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.3 h1:iCv2rBKUo+ZbWwZW+/sEjmAX+X0HsT9bgs9DqORRaPc= +github.com/aws/aws-sdk-go-v2/service/s3outposts v1.34.3/go.mod h1:4XtnGsaxnIiUsurxxTMzn9Wl9/utEAN46rcMPVKLGAM= +github.com/aws/aws-sdk-go-v2/service/s3tables v1.12.0 h1:11XumI/hI9fLn3MXs0rAAzU+c01TPpnXmgDGX2gprVU= +github.com/aws/aws-sdk-go-v2/service/s3tables v1.12.0/go.mod h1:t1l6loaBQWttife9bosS3OspbGv+CP18UbGxMIQie4A= +github.com/aws/aws-sdk-go-v2/service/s3vectors v1.5.2 h1:QX1IetutOdnutzPJ+FD9YnkguYqnIKGv9wDcZLaphWM= +github.com/aws/aws-sdk-go-v2/service/s3vectors v1.5.2/go.mod h1:+sgMaDJqPLY3w2QXsvbhgSlvIaQ4+4cYk6Cdp388Swg= +github.com/aws/aws-sdk-go-v2/service/sagemaker v1.224.0 h1:HJdoaripEfZVveELxCCgNdMsRXc9/5zNNMpr++nB2Lk= +github.com/aws/aws-sdk-go-v2/service/sagemaker v1.224.0/go.mod h1:JnrlXHI1oM/gVNI0/NH1Ru4UZr4sWx/WZclCsJtbmCM= +github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.12 h1:VOBt5H2SeS7yGq7YIOp38dW2cLeEMjIULi68tvP6iE0= +github.com/aws/aws-sdk-go-v2/service/scheduler v1.17.12/go.mod h1:UohrBXfiKjUlaqaMzj3jtBBfrNFSCjq+LLwDbtsvAIo= +github.com/aws/aws-sdk-go-v2/service/schemas v1.34.3 h1:s+siGYfqvmOJGiQJRRz/eUzsDJDZoQ6oN3F5m+AEL0I= +github.com/aws/aws-sdk-go-v2/service/schemas v1.34.3/go.mod h1:ipui3c5k/ozPT734rqfqsFgieDEny9ABk4sp7zCWjkM= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.0 h1:Wm8i2WjGbemRw3adxuKQAbzi3Uq7DgynajCxVnKGQyQ= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.0/go.mod h1:QgVIY03/XoQs2iFr0MbQuQ/Tf1RwlkOvuySWMh1wph4= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.4 h1:PkMuUN9eBC5BrK3msGCz5lajFeCjG8qBJsK3e81pUzo= +github.com/aws/aws-sdk-go-v2/service/securityhub v1.65.4/go.mod h1:QaXNTOs7OkNR7y9uFWajUymXwUh28Q7cTz3tqWiE6sc= +github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.4 h1:8wd+JhD0YwePy+QiMLpm/jMwNKhN6SdCZTJtB/nDiWI= +github.com/aws/aws-sdk-go-v2/service/securitylake v1.25.4/go.mod h1:8psZ/OINrXmUJhyXWm0NzLaKP5bp1t/dh0/D2Pj/YAo= +github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.3 h1:b6b1QcN9yzuAQw4bq34kAF75u5ToRBFgmTuBC4dnksI= +github.com/aws/aws-sdk-go-v2/service/serverlessapplicationrepository v1.30.3/go.mod h1:OmVOd812JbwvNOwaQMpeMmj2bnN6dgUZnVaD1UIvyVg= +github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.3 h1:IcQ+ja++SXCVUvsvp7lKUHZqB+Ee6KhktY4OINyknUs= +github.com/aws/aws-sdk-go-v2/service/servicecatalog v1.39.3/go.mod h1:fA60HaKYi8WBwj1uf+n2sZkyefVWWUTkKB69Th3pTB0= +github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.12 h1:5f7+VPi0JMU1U0fdmvh4u3h1BzCXYl21S72hMrTTXqk= +github.com/aws/aws-sdk-go-v2/service/servicecatalogappregistry v1.35.12/go.mod h1:H/pz3dQJmZHdKf3DMgD0znZwoP0h8Umx9uPhBRXOkxE= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.16 h1:lzAqM9zMFwAy3ghxjeJfROdwnzO/KCPY8RYEAYpGbCM= +github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.39.16/go.mod h1:lYyuDbeQ6vtjRP4gb9h2MReluEb0US5u+07X84akGKg= +github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.7 h1:f0u4ARkdAWxISBgm7RtckKuKHyn8BWprVOLjyM31Loo= +github.com/aws/aws-sdk-go-v2/service/servicequotas v1.33.7/go.mod h1:TvpkfbD0qaLoadCivfVCzpgavaEJvmRpG0pzZOo4pX0= +github.com/aws/aws-sdk-go-v2/service/ses v1.34.11 h1:DZpXGSoAP6ZB0//dl31ZkRCrEVwmGzgT6AR86WeThbo= +github.com/aws/aws-sdk-go-v2/service/ses v1.34.11/go.mod h1:CeGX4LAFCsrBp24qazKmO/dwxghNCGbAoTbi64dGSEM= +github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.4 h1:T8XudbCBzHztu2uYYUzlAQhSMxWJVk7zya/7/RLocZE= +github.com/aws/aws-sdk-go-v2/service/sesv2 v1.54.4/go.mod h1:uxpQTTvKs2FUajNzmQic0lqMB5X0zjX8jpalkvkhIQI= +github.com/aws/aws-sdk-go-v2/service/sfn v1.40.0 h1:nbTZ7tF36OMkm6anz5M35t9iqRKYGSInHCrHRWMvQQE= +github.com/aws/aws-sdk-go-v2/service/sfn v1.40.0/go.mod h1:fhG61r7sW7WsxXcZAips5CFQta1i2sQwRaEQeQwSrks= +github.com/aws/aws-sdk-go-v2/service/shield v1.34.12 h1:+TCfMnn82wi0zO4NzoqRNHlFIwWn0nQVGYxUZggnSFM= +github.com/aws/aws-sdk-go-v2/service/shield v1.34.12/go.mod h1:6B2EvRYLO2QsWbNoEsxazaKhVufZBDPApqPkpQ2arJI= +github.com/aws/aws-sdk-go-v2/service/signer v1.31.12 h1:HieRc7Lr0KPod0rv7dIa3F51/cGcV5yYCaUZNocJ6SA= +github.com/aws/aws-sdk-go-v2/service/signer v1.31.12/go.mod h1:F44pi85d2IzaTcwWULuLl2cdYjFkKr948NbU7gCmcKY= +github.com/aws/aws-sdk-go-v2/service/sns v1.39.5 h1:SKUhwz9XqabTspg48L5ZTP2D5pdbNHttPFeG0Fljqtg= +github.com/aws/aws-sdk-go-v2/service/sns v1.39.5/go.mod h1:1LvRsmADXI6174y66InuSDQiEztkQgCLbcw62VLC0FQ= +github.com/aws/aws-sdk-go-v2/service/sqs v1.42.15 h1:uoPRUh1/r/E2Vn3Witk0tZppmmsCXmsAuBmx3QorXDk= +github.com/aws/aws-sdk-go-v2/service/sqs v1.42.15/go.mod h1:ZS67woOy/ftzvKK2+P53u2NPqImAPTWz+hBn+tchP7k= +github.com/aws/aws-sdk-go-v2/service/ssm v1.67.2 h1:ybM2UK1Fx4AeurfSGzLKdnjw5j6g6mwVI0Lsr7ZnuEc= +github.com/aws/aws-sdk-go-v2/service/ssm v1.67.2/go.mod h1:uNHuYAQazkHqpD+hVomA2+eDSuKJzerno7Fnha6N6/Y= +github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.5 h1:56hyzh8TcjBUxUNg05wj427i+fBMc2y31grE28B37nI= +github.com/aws/aws-sdk-go-v2/service/ssmcontacts v1.31.5/go.mod h1:m9mkIFFGnEY00U3IpPs/TZLbbgOxARLDtqsDbGqzjik= +github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.11 h1:X3FuvC+O/n15wFyRhUct0uR3u68GvQwpngvFHrZ6d+o= +github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.39.11/go.mod h1:TUCeZ43VbibNN5TTa0oWium4Cj2ee/Xg93xNRVx+iUw= +github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.12 h1:a03QlxefOXmq1sVd60DDteR70yaT7X2Q2zaXAz2i3Z0= +github.com/aws/aws-sdk-go-v2/service/ssmquicksetup v1.8.12/go.mod h1:h/ogxk4gxt67ItMvhzCJSST5AHjaYYuMC/wdLMBLOrI= +github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.11 h1:i2bIm3mt03P2bH1oybSOAID7FRm0IZD2+C5cUMmcYEo= +github.com/aws/aws-sdk-go-v2/service/ssmsap v1.25.11/go.mod h1:9/Q7dAszR79doau18RBveSfZX9RASAs4Tubh196QR8A= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 h1:NjShtS1t8r5LUfFVtFeI8xLAHQNTa7UI0VawXlrBMFQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.3/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.8 h1:7g2FaXrm2gJyjcVjyC1jweXVNRhlK9X52wJ7wcUBISA= +github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.8/go.mod h1:CzDlwLoYGIK0Q7ISrzqCD1/Zgf6nsIdct4f0ZoyKoHI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 h1:gTsnx0xXNQ6SBbymoDvcoRHL+q4l/dAFsQuKfDWSaGc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= +github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.4 h1:bz3k661WLBZIXESAlqqumtcYSQp2m8rjT8m1/b0QLUE= +github.com/aws/aws-sdk-go-v2/service/storagegateway v1.43.4/go.mod h1:JKIFhh/dRv/Ft85RarJH3G3ewl419X6gmD/1fEXjDnI= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.0 h1:JoO/STlEltv5nSbzbg709MLNW0/BWgyK2t/R9OWcCyQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.0/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/aws-sdk-go-v2/service/swf v1.33.6 h1:VsuWtkucF7FwWd7cBXwXPx5BOU853UEws1maHKmY0iQ= +github.com/aws/aws-sdk-go-v2/service/swf v1.33.6/go.mod h1:mmUGhXHOTZ0YLexnps/Zn0u5T+p9QkpGRpXuf5L2b7A= +github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.4 h1:XO316jX9V7JywHSsmjhgp19K0NUzFAXbGRUSIl5zABU= +github.com/aws/aws-sdk-go-v2/service/synthetics v1.42.4/go.mod h1:NoN2h4JljGuHzAYWNB3WVGKnuKczRbHoqVh5Z7Z4YdM= +github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.12 h1:m20Zhil+oCtuHCpNrkoG2ihK3xjbsGWJRdv7jX3U2bU= +github.com/aws/aws-sdk-go-v2/service/taxsettings v1.16.12/go.mod h1:mch3G+DUo5AjLDfRe7XL3QhVf1K+tk+u1WQiAj5tvzs= +github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.6 h1:wYMxv6TtFtGARWlzQ4IAR8+VbTHB9Lncg+Gi5nB06h4= +github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb v1.17.6/go.mod h1:ATSASzt7xr2/Xcj8ZjMQg9woL5SyhrghAPCb7nArWVY= +github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.5 h1:qZgibsVrtn0JVsk+g6eb5jQiQFtpvngQMn0MtwMPwz8= +github.com/aws/aws-sdk-go-v2/service/timestreamquery v1.36.5/go.mod h1:b34PXpekNN9TeyqzUNcFiOEAm3DFd4e+viL/XbQtzuk= +github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.11 h1:ylTUvLe7i1rEk7nTsL1qW2kUIdZSqYw5Jb0XFfnp6H8= +github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.35.11/go.mod h1:WOhN8208dG/kUp22L0kch06lMtCQJ/+Ypv2W3TTC6vg= +github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.6 h1:2k93IkW8MnhrLQdAJDqKKTL9mjvy7N0GhE8lQi/Gy0A= +github.com/aws/aws-sdk-go-v2/service/transcribe v1.53.6/go.mod h1:juatw/4IEOV9unN2B/ZmVXIGA8YnhDTXzY/ZdIBS11w= +github.com/aws/aws-sdk-go-v2/service/transfer v1.67.6 h1:yJnWTq8tYhxl677goBXEHi/JQ12gQB+yb8JEZQC+Jv8= +github.com/aws/aws-sdk-go-v2/service/transfer v1.67.6/go.mod h1:X1hqrnuqgk5EY3Ic+agUr6P4/CJCrp8HrcC343qi/74= +github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.30.2 h1:OpOUGQJm2fHX/miVu6DS1rlreleaoNihxaxrQFpanLM= +github.com/aws/aws-sdk-go-v2/service/verifiedpermissions v1.30.2/go.mod h1:m3YeM8yB49t1fzKYEe43wiowaSO7x/3YmHS/UGOaks8= +github.com/aws/aws-sdk-go-v2/service/vpclattice v1.20.2 h1:WLmuDZpc9IlVVKQ+XID+bebCjtbxbrvCfg7Kb6LBiKw= +github.com/aws/aws-sdk-go-v2/service/vpclattice v1.20.2/go.mod h1:fp9PvIVx7/jyef3CaWCemFPGK+ghu2Du2XJFGaqc4iE= +github.com/aws/aws-sdk-go-v2/service/waf v1.30.11 h1:Lq4PpRIWw/3HSansKRRhycylCwp85287783VTCNfJMo= +github.com/aws/aws-sdk-go-v2/service/waf v1.30.11/go.mod h1:/wwPzZRBcPxG/kAOAzei/UX/FKo2H+aZcx0x99xJPpA= +github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.12 h1:kkie0K7P3VOnwJhaaofC4lbJpc82e3rbGKmXW+PjhHE= +github.com/aws/aws-sdk-go-v2/service/wafregional v1.30.12/go.mod h1:eaFrizONYIw5QJPDxoBUr8NNM21ISTZDjFhkGVt4NZY= +github.com/aws/aws-sdk-go-v2/service/wafv2 v1.70.0 h1:mZMnchrgTVjUinijiTKDh0tvz5HhzAoMXfIjOAWpdB4= +github.com/aws/aws-sdk-go-v2/service/wafv2 v1.70.0/go.mod h1:RtLkquPOQfQASVPWLuXr4hJgaZ5ChNq7eWahkj/CoCQ= +github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.12 h1:niwCZWFfIaglbSRA1Cbc7fMCOfsmAfeaWX8ll25sfOI= +github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.39.12/go.mod h1:t6nyl94d8gQdt34LEo0SH4uGPNruy0T3oMaxcOHdWUU= +github.com/aws/aws-sdk-go-v2/service/workmail v1.36.10 h1:lznZYmkvDu6gHqSKpornaZw2WCwYDN/NYSpfziIgsr8= +github.com/aws/aws-sdk-go-v2/service/workmail v1.36.10/go.mod h1:JW6rMNuboHOnWx7I1fZfHAG1kcUiBZfTkZuD69oNw2w= +github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.4 h1:yX/JSkp/zildXMrGuqm7VRUn+S8an7dZt0Jyy8L6DVg= +github.com/aws/aws-sdk-go-v2/service/workspaces v1.64.4/go.mod h1:TmJI48Dm4ftRxBmMoZOeC8Et2WEStJoPpv8BoXZ/eZw= +github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.34.0 h1:gfDV7Oa2SA+xTJxWZwPiGF/aBew2/OVIGRZ1qipeZ6Q= +github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.34.0/go.mod h1:V4nPCxgIBn6Yf5JhnI3Cs0iKVTB+wkzXG8fEGYqLYkU= +github.com/aws/aws-sdk-go-v2/service/xray v1.36.11 h1:K0g9kBUVHv8da1OpfeLbvteZyTy2dUWBO2ZfwYXw1D8= +github.com/aws/aws-sdk-go-v2/service/xray v1.36.11/go.mod h1:JghyUyM7u0syGGk+S5Res2mLfceuyLigCgtcrpsEESM= github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= @@ -579,8 +579,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= -github.com/cedar-policy/cedar-go v1.2.9 h1:Wza6MAH6zdr4eYtujcfFoTj8FJbtDHJVjGUl4QpPn14= -github.com/cedar-policy/cedar-go v1.2.9/go.mod h1:h5+3CVW1oI5LXVskJG+my9TFCYI5yjh/+Ul3EJie6MI= +github.com/cedar-policy/cedar-go v1.3.0 h1:QOyZgY1jOFB0si7b6pCFIrqOSVHArUHdeJu8mk070FM= +github.com/cedar-policy/cedar-go v1.3.0/go.mod h1:h5+3CVW1oI5LXVskJG+my9TFCYI5yjh/+Ul3EJie6MI= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= @@ -656,6 +656,8 @@ github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshf github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-set/v3 v3.0.1 h1:ZwO15ZYmIrFYL9zSm2wBuwcRiHxVdp46m/XA/MUlM6I= +github.com/hashicorp/go-set/v3 v3.0.1/go.mod h1:0oPQqhtitglZeT2ZiWnRIfUG6gJAHnn7LzrS7SbgNY4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -758,6 +760,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/shoenig/test v1.12.1 h1:mLHfnMv7gmhhP44WrvT+nKSxKkPDiNkIuHGdIGI9RLU= +github.com/shoenig/test v1.12.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= @@ -810,25 +814,25 @@ go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42s golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -841,25 +845,25 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= diff --git a/version/VERSION b/version/VERSION index c70e8167e167..df0e6cfa6346 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -6.19.1 \ No newline at end of file +6.21.1 \ No newline at end of file diff --git a/website/docs/actions/dynamodb_create_backup.html.markdown b/website/docs/actions/dynamodb_create_backup.html.markdown new file mode 100644 index 000000000000..a9262c5b913c --- /dev/null +++ b/website/docs/actions/dynamodb_create_backup.html.markdown @@ -0,0 +1,74 @@ +--- +subcategory: "DynamoDB" +layout: "aws" +page_title: "AWS: aws_dynamodb_create_backup" +description: |- + Creates an on-demand backup of a DynamoDB table. +--- + +# Action: aws_dynamodb_create_backup + +~> **Note:** `aws_dynamodb_create_backup` is in beta. Its interface and behavior may change as the feature evolves, and breaking changes are possible. It is offered as a technical preview without compatibility guarantees until Terraform 1.14 is generally available. + +Creates an on-demand backup of a DynamoDB table. This action will initiate a backup and wait for it to complete, providing progress updates during execution. + +For information about DynamoDB backups, see the [DynamoDB Developer Guide](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BackupRestore.html). For specific information about creating backups, see the [CreateBackup](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateBackup.html) page in the DynamoDB API Reference. + +~> **Note:** On-demand backups do not consume provisioned throughput and have no impact on table performance. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_dynamodb_table" "example" { + name = "example-table" + billing_mode = "PAY_PER_REQUEST" + hash_key = "id" + + attribute { + name = "id" + type = "S" + } +} + +action "aws_dynamodb_create_backup" "example" { + config { + table_name = aws_dynamodb_table.example.name + } +} + +resource "terraform_data" "backup_trigger" { + input = "trigger-backup" + + lifecycle { + action_trigger { + events = [after_create] + actions = [action.aws_dynamodb_create_backup.example] + } + } +} +``` + +### Backup with Custom Name + +```terraform +action "aws_dynamodb_create_backup" "named" { + config { + table_name = aws_dynamodb_table.production.name + backup_name = "production-backup-${formatdate("YYYY-MM-DD", timestamp())}" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `table_name` - (Required) Name or ARN of the DynamoDB table to backup. Must be between 1 and 1024 characters. + +The following arguments are optional: + +* `backup_name` - (Optional) Name for the backup. If not provided, a unique name will be generated automatically using the table name and a unique identifier. Must be between 3 and 255 characters and contain only alphanumeric characters, underscores, periods, and hyphens. +* `timeout` - (Optional) Timeout in minutes for the backup operation. Defaults to 10 minutes. +* `region` - (Optional) Region where this action should be [run](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). diff --git a/website/docs/d/connect_routing_profile.html.markdown b/website/docs/d/connect_routing_profile.html.markdown index 005882b55f99..67401aab407c 100644 --- a/website/docs/d/connect_routing_profile.html.markdown +++ b/website/docs/d/connect_routing_profile.html.markdown @@ -57,6 +57,11 @@ A `media_concurrencies` block supports the following attributes: * `channel` - Channels that agents can handle in the Contact Control Panel (CCP). Valid values are `VOICE`, `CHAT`, `TASK`. * `concurrency` - Number of contacts an agent can have on a channel simultaneously. Valid Range for `VOICE`: Minimum value of 1. Maximum value of 1. Valid Range for `CHAT`: Minimum value of 1. Maximum value of 10. Valid Range for `TASK`: Minimum value of 1. Maximum value of 10. +* `cross_channel_behavior` - Configuration block for cross-channel behavior. Documented below. + +A `cross_channel_behavior` block supports the following attributes: + +* `behavior_type` - Cross-channel behavior for routing contacts across multiple channels. Valid values are `ROUTE_CURRENT_CHANNEL_ONLY`, `ROUTE_ANY_CHANNEL`. A `queue_configs` block supports the following attributes: diff --git a/website/docs/d/ecs_service.html.markdown b/website/docs/d/ecs_service.html.markdown index e524834186ac..3f4ce00f5f44 100644 --- a/website/docs/d/ecs_service.html.markdown +++ b/website/docs/d/ecs_service.html.markdown @@ -33,13 +33,168 @@ This data source supports the following arguments: This data source exports the following attributes in addition to the arguments above: * `arn` - ARN of the ECS Service +* `availability_zone_rebalancing` - Whether Availability Zone rebalancing is enabled +* `capacity_provider_strategy` - Capacity provider strategy for the service. See [`capacity_provider_strategy` Block](#capacity_provider_strategy-block) for details. +* `created_at` - Time when the service was created (RFC3339 format) +* `created_by` - Principal that created the service +* `deployment_configuration` - Deployment configuration for the service. See [`deployment_configuration` Block](#deployment_configuration-block) for details. +* `deployment_controller` - Deployment controller configuration. See [`deployment_controller` Block](#deployment_controller-block) for details. +* `deployments` - Current deployments for the service. See [`deployments` Block](#deployments-block) for details. * `desired_count` - Number of tasks for the ECS Service +* `enable_ecs_managed_tags` - Whether ECS managed tags are enabled +* `enable_execute_command` - Whether execute command functionality is enabled +* `events` - Recent service events. See [`events` Block](#events-block) for details. +* `health_check_grace_period_seconds` - Grace period for health checks +* `iam_role` - ARN of the IAM role associated with the service * `launch_type` - Launch type for the ECS Service * `load_balancer` - Load balancers for the ECS Service. See [`load_balancer` Block](#load_balancer-block) for details. +* `network_configuration` - Network configuration for the service. See [`network_configuration` Block](#network_configuration-block) for details. +* `ordered_placement_strategy` - Placement strategy for tasks. See [`ordered_placement_strategy` Block](#ordered_placement_strategy-block) for details. +* `pending_count` - Number of tasks in PENDING state +* `placement_constraints` - Placement constraints for tasks. See [`placement_constraints` Block](#placement_constraints-block) for details. +* `platform_family` - Platform family for Fargate tasks +* `platform_version` - Platform version for Fargate tasks +* `propagate_tags` - Whether tags are propagated from task definition or service +* `running_count` - Number of tasks in RUNNING state * `scheduling_strategy` - Scheduling strategy for the ECS Service -* `task_definition` - Family for the latest ACTIVE revision or full ARN of the task definition. +* `service_registries` - Service discovery registries. See [`service_registries` Block](#service_registries-block) for details. +* `status` - Status of the service +* `task_definition` - Family for the latest ACTIVE revision or full ARN of the task definition +* `task_sets` - Task sets for the service. See [`task_sets` Block](#task_sets-block) for details. * `tags` - Resource tags. +### `capacity_provider_strategy` Block + +The `capacity_provider_strategy` block exports the following attributes: + +* `base` - Number of tasks using the specified capacity provider +* `capacity_provider` - Name of the capacity provider +* `weight` - Relative percentage of total tasks to launch + +### `deployment_configuration` Block + +The `deployment_configuration` block exports the following attributes: + +* `alarms` - CloudWatch alarms configuration. See [`alarms` Block](#alarms-block) for details. +* `bake_time_in_minutes` - Time to wait after deployment before terminating old tasks +* `canary_configuration` - Canary deployment configuration. See [`canary_configuration` Block](#canary_configuration-block) for details. +* `deployment_circuit_breaker` - Circuit breaker configuration. See [`deployment_circuit_breaker` Block](#deployment_circuit_breaker-block) for details. +* `linear_configuration` - Linear deployment configuration. See [`linear_configuration` Block](#linear_configuration-block) for details. +* `lifecycle_hook` - Lifecycle hooks for deployments. See [`lifecycle_hook` Block](#lifecycle_hook-block) for details. +* `maximum_percent` - Upper limit on tasks during deployment +* `minimum_healthy_percent` - Lower limit on healthy tasks during deployment +* `strategy` - Deployment strategy (ROLLING, BLUE_GREEN, LINEAR, or CANARY) + +### `alarms` Block + +The `alarms` block exports the following attributes: + +* `alarm_names` - List of CloudWatch alarm names +* `enable` - Whether alarms are enabled +* `rollback` - Whether to rollback on alarm + +### `canary_configuration` Block + +The `canary_configuration` block exports the following attributes: + +* `canary_bake_time_in_minutes` - Time to wait before shifting remaining traffic +* `canary_percent` - Percentage of traffic to route to canary deployment + +### `deployment_circuit_breaker` Block + +The `deployment_circuit_breaker` block exports the following attributes: + +* `enable` - Whether circuit breaker is enabled +* `rollback` - Whether to rollback on failure + +### `linear_configuration` Block + +The `linear_configuration` block exports the following attributes: + +* `step_bake_time_in_minutes` - Time to wait between deployment steps +* `step_percent` - Percentage of traffic to shift in each step + +### `lifecycle_hook` Block + +The `lifecycle_hook` block exports the following attributes: + +* `hook_details` - Additional details for the hook +* `hook_target_arn` - ARN of the Lambda function to invoke +* `lifecycle_stages` - Deployment stages when hook is invoked +* `role_arn` - ARN of the IAM role for invoking the hook + +### `deployment_controller` Block + +The `deployment_controller` block exports the following attributes: + +* `type` - Deployment controller type (ECS, CODE_DEPLOY, or EXTERNAL) + +### `deployments` Block + +The `deployments` block exports the following attributes: + +* `created_at` - Time when deployment was created (RFC3339 format) +* `desired_count` - Desired number of tasks +* `id` - Deployment ID +* `pending_count` - Number of pending tasks +* `running_count` - Number of running tasks +* `status` - Deployment status +* `task_definition` - Task definition ARN +* `updated_at` - Time when deployment was last updated (RFC3339 format) + +### `events` Block + +The `events` block exports the following attributes: + +* `created_at` - Time when event occurred (RFC3339 format) +* `id` - Event ID +* `message` - Event message + +### `network_configuration` Block + +The `network_configuration` block exports the following attributes: + +* `assign_public_ip` - Whether tasks receive public IP addresses +* `security_groups` - Security groups associated with tasks +* `subnets` - Subnets associated with tasks + +### `ordered_placement_strategy` Block + +The `ordered_placement_strategy` block exports the following attributes: + +* `field` - Field to apply placement strategy against +* `type` - Placement strategy type + +### `placement_constraints` Block + +The `placement_constraints` block exports the following attributes: + +* `expression` - Cluster query language expression +* `type` - Constraint type + +### `service_registries` Block + +The `service_registries` block exports the following attributes: + +* `container_name` - Container name for service discovery +* `container_port` - Container port for service discovery +* `port` - Port value for service discovery +* `registry_arn` - ARN of the service registry + +### `task_sets` Block + +The `task_sets` block exports the following attributes: + +* `arn` - ARN of the task set +* `created_at` - Time when task set was created (RFC3339 format) +* `id` - Task set ID +* `pending_count` - Number of pending tasks +* `running_count` - Number of running tasks +* `stability_status` - Stability status of the task set +* `status` - Task set status +* `task_definition` - Task definition ARN +* `updated_at` - Time when task set was last updated (RFC3339 format) + ### `load_balancer` Block The `load_balancer` block exports the following attributes: diff --git a/website/docs/d/lb_listener_rule.html.markdown b/website/docs/d/lb_listener_rule.html.markdown index 0a7e05573313..697eb347799e 100644 --- a/website/docs/d/lb_listener_rule.html.markdown +++ b/website/docs/d/lb_listener_rule.html.markdown @@ -76,6 +76,8 @@ This data source exports the following attributes in addition to the arguments a [Detailed below](#fixed_response). * `forward` - An action to forward the request. [Detailed below](#forward). +* `jwt_validation` - An action to validate using JWT. + [Detailed below](#jwt_validation). * `redirect` - An action to redirect the request. [Detailed below](#redirect). @@ -133,6 +135,18 @@ This data source exports the following attributes in addition to the arguments a * `arn` - ARN of the target group. * `weight` - Weight of the target group. +#### `jwt_validation` + +* `issuer` - Issuer of the JWT. +* `jwks_endpoint` - JSON Web Key Set (JWKS) endpoint. +* `additional_claim` - Additional claims to validate. + +#### `additional_claim` + +* `format` - Format of the claim value. +* `name` - Name of the claim to validate. +* `values` - List of expected values of the claim. + #### `redirect` * `host` - The hostname. diff --git a/website/docs/d/odb_db_servers.html.markdown b/website/docs/d/odb_db_servers.html.markdown index 66067f0ba465..499c287fef4e 100644 --- a/website/docs/d/odb_db_servers.html.markdown +++ b/website/docs/d/odb_db_servers.html.markdown @@ -46,7 +46,7 @@ This data source exports the following attributes in addition to the arguments a * `cpu_core_count` - The number of CPU cores enabled on the database server. * `created_at` - The date and time when the database server was created. * `db_node_storage_size_in_gbs` - The amount of local node storage, in gigabytes (GB), that's allocated on the database server. -* `db_server_id` - The unique identifier of the database server. +* `id` - The unique identifier of the database server. * `db_server_patching_details` - The scheduling details for the quarterly maintenance window. Patching and system updates take place during the maintenance window. * `display_name` - The user-friendly name of the database server. The name doesn't need to be unique. * `exadata_infrastructure_id` - The ID of the Exadata infrastructure that hosts the database server. diff --git a/website/docs/d/opensearch_domain.html.markdown b/website/docs/d/opensearch_domain.html.markdown index d98ac77d1740..88025a4e40bb 100644 --- a/website/docs/d/opensearch_domain.html.markdown +++ b/website/docs/d/opensearch_domain.html.markdown @@ -89,6 +89,11 @@ This data source exports the following attributes in addition to the arguments a * `kms_key_id` - KMS key id used to encrypt data at rest. * `endpoint` - Domain-specific endpoint used to submit index, search, and data upload requests. * `endpoint_v2` - V2 domain-specific endpoint that works with both IPv4 and IPv6 addresses, used to submit index, search, and data upload requests. +* `identity_center_options` - Configuration for enabling and managing IAM Identity Center integration within a domain. + * `enabled_api_access` - Boolean whether IAM Identity Center is enabled for API access. + * `identity_center_instance_arn` - ARN of the IAM Identity Center instance to create an OpenSearch UI application that uses IAM Identity Center for authentication. + * `roles_key` - Attribute that contains the backend role identifier (such as group name or group ID) in IAM Identity Center. + * `subject_key` - Attribute that contains the subject identifier (such as username, user ID, or email) in IAM Identity Center. * `ip_address_type` - Type of IP addresses supported by the endpoint for the domain. * `log_publishing_options` - Domain log publishing related options. * `log_type` - Type of OpenSearch log being published. diff --git a/website/docs/d/organizations_policies.html.markdown b/website/docs/d/organizations_policies.html.markdown index 38ef475aa843..2816121b97ca 100644 --- a/website/docs/d/organizations_policies.html.markdown +++ b/website/docs/d/organizations_policies.html.markdown @@ -29,7 +29,7 @@ data "aws_organizations_policy" "example" { The following arguments are required: -* `filter` - (Required) The type of policies to be returned in the response. Valid values are `AISERVICES_OPT_OUT_POLICY | BACKUP_POLICY | RESOURCE_CONTROL_POLICY | SERVICE_CONTROL_POLICY | TAG_POLICY` +* `filter` - (Required) The type of policies to be returned in the response. Valid values are `AISERVICES_OPT_OUT_POLICY | BACKUP_POLICY | CHATBOT_POLICY | DECLARATIVE_POLICY_EC2 | RESOURCE_CONTROL_POLICY | SERVICE_CONTROL_POLICY | TAG_POLICY` ## Attribute Reference diff --git a/website/docs/d/organizations_policies_for_target.html.markdown b/website/docs/d/organizations_policies_for_target.html.markdown index 4effa3e36f4a..7e3c0a3b8bbc 100644 --- a/website/docs/d/organizations_policies_for_target.html.markdown +++ b/website/docs/d/organizations_policies_for_target.html.markdown @@ -33,7 +33,7 @@ data "aws_organizations_policy" "example" { The following arguments are required: * `target_id` - (Required) The root (string that begins with "r-" followed by 4-32 lowercase letters or digits), account (12 digit string), or Organizational Unit (string starting with "ou-" followed by 4-32 lowercase letters or digits. This string is followed by a second "-" dash and from 8-32 additional lowercase letters or digits.) -* `filter` - (Required) Must supply one of the 5 different policy filters for a target (AISERVICES_OPT_OUT_POLICY | BACKUP_POLICY | RESOURCE_CONTROL_POLICY | SERVICE_CONTROL_POLICY | TAG_POLICY) +* `filter` - (Required) Must supply one of the 7 different policy filters for a target (AISERVICES_OPT_OUT_POLICY | BACKUP_POLICY | CHATBOT_POLICY | DECLARATIVE_POLICY_EC2 | RESOURCE_CONTROL_POLICY | SERVICE_CONTROL_POLICY | TAG_POLICY) ## Attribute Reference diff --git a/website/docs/d/organizations_policy.html.markdown b/website/docs/d/organizations_policy.html.markdown index 19f67e24f8e2..13a96161945e 100644 --- a/website/docs/d/organizations_policy.html.markdown +++ b/website/docs/d/organizations_policy.html.markdown @@ -41,4 +41,4 @@ This data source exports the following attributes in addition to the arguments a * `content` - The text content of the policy. * `description` - The description of the policy. * `name` - The friendly name of the policy. -* `type` - The type of policy values can be `AISERVICES_OPT_OUT_POLICY | BACKUP_POLICY | RESOURCE_CONTROL_POLICY | SERVICE_CONTROL_POLICY | TAG_POLICY` +* `type` - The type of policy values can be `AISERVICES_OPT_OUT_POLICY | BACKUP_POLICY | CHATBOT_POLICY | DECLARATIVE_POLICY_EC2 | RESOURCE_CONTROL_POLICY | SERVICE_CONTROL_POLICY | TAG_POLICY` diff --git a/website/docs/d/route53_zone.html.markdown b/website/docs/d/route53_zone.html.markdown index 8109b4391a31..ef0bb144ccd9 100644 --- a/website/docs/d/route53_zone.html.markdown +++ b/website/docs/d/route53_zone.html.markdown @@ -31,19 +31,36 @@ resource "aws_route53_record" "www" { } ``` +The following example shows how to get a Hosted Zone from a unique combination of its tags: + +```terraform +data "aws_route53_zone" "selected" { + tags { + scope = "local" + category = "api" + } +} + +output "local_api_zone" { + value = data.aws_route53_zone.selected.zone_id +} +``` + ## Argument Reference This data source supports the following arguments: -* `zone_id` - (Optional) Hosted Zone id of the desired Hosted Zone. -* `name` - (Optional) Hosted Zone name of the desired Hosted Zone. -* `private_zone` - (Optional) Used with `name` field to get a private Hosted Zone. -* `vpc_id` - (Optional) Used with `name` field to get a private Hosted Zone associated with the vpc_id (in this case, private_zone is not mandatory). -* `tags` - (Optional) Used with `name` field. A map of tags, each pair of which must exactly match a pair on the desired Hosted Zone. +* `zone_id` - (Optional) Directly return the Hosted Zone with the specified Zone ID. No further filtering is performed. +* `name` - (Optional) Hosted Zone name of the desired Hosted Zone. If blank, then accept any name, filtering on only `private_zone`, `vpc_id` and `tags`. +* `private_zone` - (Optional) Filter to only private Hosted Zones. +* `vpc_id` - (Optional, string) Filter to private Hosted Zones associated with the specified `vpc_id`. +* `tags` - (Optional) A map of tags, each pair of which must exactly match a pair on the desired Hosted Zone. + +The arguments of this data source act as filters for querying the available Hosted Zone. -The arguments of this data source act as filters for querying the available -Hosted Zone. You have to use `zone_id` or `name`, not both of them. The given filter must match exactly one -Hosted Zone. If you use `name` field for private Hosted Zone, you need to add `private_zone` field to `true`. +- The given filter must match exactly one Hosted Zone. +- `zone_id` and `name` are mutually exclusive. +- If you use the `name` argument for a private Hosted Zone, you need to set the `private_zone` argument to `true`. ## Attribute Reference diff --git a/website/docs/d/route_table.html.markdown b/website/docs/d/route_table.html.markdown index be888289131d..f59ebb8e2ae4 100644 --- a/website/docs/d/route_table.html.markdown +++ b/website/docs/d/route_table.html.markdown @@ -55,6 +55,7 @@ The following arguments are required: This data source exports the following attributes in addition to the arguments above: +* `id` – The ID of the route table. * `arn` - ARN of the route table. * `associations` - List of associations with attributes detailed below. * `owner_id` - ID of the AWS account that owns the route table. diff --git a/website/docs/ephemeral-resources/cognito_identity_openid_token_for_developer_identity.markdown b/website/docs/ephemeral-resources/cognito_identity_openid_token_for_developer_identity.html.markdown similarity index 100% rename from website/docs/ephemeral-resources/cognito_identity_openid_token_for_developer_identity.markdown rename to website/docs/ephemeral-resources/cognito_identity_openid_token_for_developer_identity.html.markdown diff --git a/website/docs/ephemeral-resources/ecr_authorization_token.html.markdown b/website/docs/ephemeral-resources/ecr_authorization_token.html.markdown new file mode 100644 index 000000000000..8fb52bb4fe11 --- /dev/null +++ b/website/docs/ephemeral-resources/ecr_authorization_token.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "ECR (Elastic Container Registry)" +layout: "aws" +page_title: "AWS: aws_ecr_authorization_token" +description: |- + Retrieve an authentication token to communicate with an ECR repository. +--- + +# Ephemeral: aws_ecr_authorization_token + +Retrieve an authentication token to communicate with an ECR repository. + +~> **NOTE:** Ephemeral resources are a new feature and may evolve as we continue to explore their most effective uses. [Learn more](https://developer.hashicorp.com/terraform/language/resources/ephemeral). + +~> **NOTE:** The returned authorization token can be used to access any Amazon ECR registry that the IAM principal has access to. The token's permissions scope is determined by the IAM principal's permissions, not by any specific registry. + +## Example Usage + +```terraform +ephemeral "aws_ecr_authorization_token" "token" {} + +provider "docker" { + registry_auth { + address = ephemeral.aws_ecr_authorization_token.token.proxy_endpoint + username = ephemeral.aws_ecr_authorization_token.token.user_name + password = ephemeral.aws_ecr_authorization_token.token.password + } +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `authorization_token` - Temporary IAM authentication credentials to access the ECR repository encoded in base64 in the form of `user_name:password`. +* `expires_at` - Time in UTC RFC3339 format when the authorization token expires. +* `password` - Password decoded from the authorization token. +* `proxy_endpoint` - Registry URL to use in the docker login command. +* `user_name` - User name decoded from the authorization token. diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index d6227a412372..71f775d2f0f3 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -9,7 +9,7 @@ description: |- The Amazon Web Services (AWS) provider is Terraform’s most widely-used provider and the industry-standard way to manage AWS infrastructure as code. It is an indispensable part of how leading technology companies, global banks, government agencies, and some of the largest enterprises in the world build and operate in the cloud. Every day, it provisions and orchestrates billions of dollars of AWS infrastructure across thousands of organizations. -With 1,561 resources and 630 data sources, the AWS provider spans the full breadth of AWS services—from foundational capabilities like compute, storage, networking, and identity management to advanced services for AI, analytics, and event-driven architectures, including Lambda, RDS, SageMaker, and Bedrock. Whether automating a single S3 bucket or orchestrating a multi-region, enterprise-scale environment, the provider delivers consistent, reliable workflows that scale with your needs. +With 1,567 resources and 630 data sources, the AWS provider spans the full breadth of AWS services—from foundational capabilities like compute, storage, networking, and identity management to advanced services for AI, analytics, and event-driven architectures, including Lambda, RDS, SageMaker, and Bedrock. Whether automating a single S3 bucket or orchestrating a multi-region, enterprise-scale environment, the provider delivers consistent, reliable workflows that scale with your needs. Configure the provider with your AWS credentials, and you can immediately begin creating and managing infrastructure in a safe, repeatable way. Use the navigation on the left to explore the available resources, or start with our [Get Started tutorials](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/infrastructure-as-code?in=terraform/aws-get-started&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) to learn the fundamentals. For deeper guidance on specific AWS services, visit the [AWS services tutorials](https://developer.hashicorp.com/terraform/tutorials/aws?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS). diff --git a/website/docs/r/account_region.markdown b/website/docs/r/account_region.html.markdown similarity index 100% rename from website/docs/r/account_region.markdown rename to website/docs/r/account_region.html.markdown diff --git a/website/docs/r/api_gateway_rest_api_put.markdown b/website/docs/r/api_gateway_rest_api_put.html.markdown similarity index 100% rename from website/docs/r/api_gateway_rest_api_put.markdown rename to website/docs/r/api_gateway_rest_api_put.html.markdown diff --git a/website/docs/r/backup_logically_air_gapped_vault.html.markdown b/website/docs/r/backup_logically_air_gapped_vault.html.markdown index 2f67e50d2973..b384b4aa4eba 100644 --- a/website/docs/r/backup_logically_air_gapped_vault.html.markdown +++ b/website/docs/r/backup_logically_air_gapped_vault.html.markdown @@ -30,6 +30,7 @@ This resource supports the following arguments: * `name` - (Required) Name of the Logically Air Gapped Backup Vault to create. * `max_retention_days` - (Required) Maximum retention period that the Logically Air Gapped Backup Vault retains recovery points. * `min_retention_days` - (Required) Minimum retention period that the Logically Air Gapped Backup Vault retains recovery points. +* `encryption_key_arn` - (Optional) The AWS KMS key identifier (ARN) used to encrypt the backups in the logically air-gapped vault. * `tags` - (Optional) Metadata that you can assign to help organize the resources that you create. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ## Attribute Reference diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 29125c6e87f8..d25ab2183c34 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -184,6 +184,7 @@ The `pinecone_configuration` configuration block supports the following argument * `credentials_secret_arn` - (Required) ARN of the secret that you created in AWS Secrets Manager that is linked to your Amazon RDS database. * `database_name` - (Required) Name of your Amazon RDS database. * `field_mapping` - (Required) Names of the fields to which to map information about the vector store. This block supports the following arguments: + * `custom_metadata_field` - (Optional) Name for the universal metadata field where Amazon Bedrock will store any custom metadata from your data source. * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. * `primary_key_field` - (Required) Name of the field in which Amazon Bedrock stores the ID for each entry. * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. diff --git a/website/docs/r/bedrockagentcore_agent_runtime.html.markdown b/website/docs/r/bedrockagentcore_agent_runtime.html.markdown index 08b983c4999a..e3e2e5b3b903 100644 --- a/website/docs/r/bedrockagentcore_agent_runtime.html.markdown +++ b/website/docs/r/bedrockagentcore_agent_runtime.html.markdown @@ -106,6 +106,32 @@ resource "aws_bedrockagentcore_agent_runtime" "example" { } ``` +### Agent runtime artifact from S3 with Code Configuration + +```terraform +resource "aws_bedrockagentcore_agent_runtime" "example" { + agent_runtime_name = "example_agent_runtime" + role_arn = aws_iam_role.example.arn + + agent_runtime_artifact { + code_configuration { + entry_point = ["main.py"] + runtime = "PYTHON_3_13" + code { + s3 { + bucket = "example-bucket" + prefix = "example-agent-runtime-code.zip" + } + } + } + } + + network_configuration { + network_mode = "PUBLIC" + } +} +``` + ## Argument Reference The following arguments are required: @@ -130,7 +156,30 @@ The following arguments are optional: The `agent_runtime_artifact` block supports the following: -* `container_configuration` - (Required) Container configuration block. See [`container_configuration`](#container_configuration) below. +* `code_configuration` - (Optional) Code configuration block for the agent runtime artifact, including the source code location and execution settings. Exactly one of `code_configuration` or `container_configuration` must be specified. See [`code_configuration`](#code_configuration) below. +* `container_configuration` - (Optional) Container configuration block for the agent artifact. Exactly one of `code_configuration` or `container_configuration` must be specified. See [`container_configuration`](#container_configuration) below. + +### `code_configuration` + +The `code_configuration` block supports the following: + +* `code` - (Required) Configuration block for the source code location and configuration details. See [`code`](#code) below. +* `entry_point` - (Required) Array specifying the entry point for code execution, indicating the function or method to invoke when the code runs. The array must contain 1 or 2 elements. Examples: `["main.py"]`, `["opentelemetry-instrument", "main.py"]`. +* `runtime` - (Required) Runtime environment used to execute the code. Valid values: `PYTHON_3_10`, `PYTHON_3_11`, `PYTHON_3_12`, `PYTHON_3_13`. + +### `code` + +The `code` block supports the following: + +* `s3` - (Required) Configuration block for the Amazon S3 object that contains the source code for the agent runtime. See [`s3`](#s3) below. + +### `s3` + +The `s3` block supports the following: + +* `bucket` - (Required) Name of the Amazon S3 bucket. +* `prefix` - (Required) Key of the object containing the ZIP file of the source code for the agent runtime in the Amazon S3 bucket. +* `version_id` - (Optional) Version ID of the Amazon S3 object. If not specified, the latest version of the object is used. ### `container_configuration` diff --git a/website/docs/r/bedrockagentcore_browser.html.markdown b/website/docs/r/bedrockagentcore_browser.html.markdown index 79c35c06a5d9..7dc97a997677 100644 --- a/website/docs/r/bedrockagentcore_browser.html.markdown +++ b/website/docs/r/bedrockagentcore_browser.html.markdown @@ -34,7 +34,7 @@ resource "aws_bedrockagentcore_browser" "vpc_example" { network_configuration { network_mode = "VPC" - network_mode_config { + vpc_config { security_groups = ["sg-12345678"] subnets = ["subnet-12345678", "subnet-87654321"] } @@ -104,11 +104,11 @@ The following arguments are optional: The `network_configuration` object supports the following: * `network_mode` - (Required) Network mode for the browser. Valid values: `PUBLIC`, `VPC`. -* `network_mode_config` - (Optional) VPC configuration when `network_mode` is `VPC`. See [`network_mode_config`](#network_mode_config) below. +* `vpc_config` - (Optional) VPC configuration when `network_mode` is `VPC`. See [`vpc_config`](#vpc_config) below. -### `network_mode_config` +### `vpc_config` -The `network_mode_config` object supports the following: +The `vpc_config` object supports the following: * `security_groups` - (Required) Set of security group IDs for the VPC configuration. * `subnets` - (Required) Set of subnet IDs for the VPC configuration. diff --git a/website/docs/r/bedrockagentcore_gateway.html.markdown b/website/docs/r/bedrockagentcore_gateway.html.markdown index 078eb8636dc1..38b7aad9ee9d 100644 --- a/website/docs/r/bedrockagentcore_gateway.html.markdown +++ b/website/docs/r/bedrockagentcore_gateway.html.markdown @@ -119,7 +119,7 @@ The `protocol_configuration` block supports the following: The `mcp` block supports the following: * `instructions` - (Optional) Instructions for the MCP protocol configuration. -* `search_type` - (Optional) Search type for MCP. Valid values: `SEMANTIC`, `HYBRID`. +* `search_type` - (Optional) Search type for MCP. Valid values: `SEMANTIC`. * `supported_versions` - (Optional) Set of supported MCP protocol versions. ## Attribute Reference diff --git a/website/docs/r/bedrockagentcore_gateway_target.html.markdown b/website/docs/r/bedrockagentcore_gateway_target.html.markdown index dcbdc39de9d2..297fb9a13adf 100644 --- a/website/docs/r/bedrockagentcore_gateway_target.html.markdown +++ b/website/docs/r/bedrockagentcore_gateway_target.html.markdown @@ -294,11 +294,11 @@ The following arguments are required: * `name` - (Required) Name of the gateway target. * `gateway_identifier` - (Required) Identifier of the gateway that this target belongs to. -* `credential_provider_configuration` - (Required) Configuration for authenticating requests to the target. See [`credential_provider_configuration`](#credential_provider_configuration) below. * `target_configuration` - (Required) Configuration for the target endpoint. See [`target_configuration`](#target_configuration) below. The following arguments are optional: +* `credential_provider_configuration` - (Optional) Configuration for authenticating requests to the target. Required when using `lambda`, `open_api_schema` and `smithy_model` in `mcp` block. If using `mcp_server` in `mcp` block with no authorization, it should not be specified. See [`credential_provider_configuration`](#credential_provider_configuration) below. * `description` - (Optional) Description of the gateway target. * `region` - (Optional) AWS region where the resource will be created. If not provided, the region from the provider configuration will be used. @@ -338,6 +338,7 @@ The `target_configuration` block supports the following: The `mcp` block supports exactly one of the following: * `lambda` - (Optional) Lambda function target configuration. See [`lambda`](#lambda) below. +* `mcp_server` - (Optional) MCP server target configuration. See [`mcp_server`](#mcp_server) below. * `open_api_schema` - (Optional) OpenAPI schema-based target configuration. See [`api_schema_configuration`](#api_schema_configuration) below. * `smithy_model` - (Optional) Smithy model-based target configuration. See [`api_schema_configuration`](#api_schema_configuration) below. @@ -371,6 +372,12 @@ The `s3` block supports the following: * `uri` - (Optional) S3 URI where the tool schema is stored. * `bucket_owner_account_id` - (Optional) Account ID of the S3 bucket owner. +### `mcp_server` + +The `mcp_server` block supports the following: + +* `endpoint` - (Required) Endpoint for the MCP server target configuration. + ### `api_schema_configuration` The `api_schema_configuration` block supports exactly one of the following: diff --git a/website/docs/r/cloudwatch_log_delivery_destination.html.markdown b/website/docs/r/cloudwatch_log_delivery_destination.html.markdown index e7f77257e673..9a874bc57994 100644 --- a/website/docs/r/cloudwatch_log_delivery_destination.html.markdown +++ b/website/docs/r/cloudwatch_log_delivery_destination.html.markdown @@ -24,13 +24,23 @@ resource "aws_cloudwatch_log_delivery_destination" "example" { } ``` +### X-Ray Trace Delivery + +```terraform +resource "aws_cloudwatch_log_delivery_destination" "xray" { + name = "xray-traces" + delivery_destination_type = "XRAY" +} +``` + ## Argument Reference This resource supports the following arguments: * `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). -* `delivery_destination_configuration` - (Required) The AWS resource that will receive the logs. - * `destination_resource_arn` - (Required) The ARN of the AWS destination that this delivery destination represents. +* `delivery_destination_configuration` - (Optional) The AWS resource that will receive the logs. Required for CloudWatch Logs, Amazon S3, and Firehose destinations. Not required for X-Ray trace delivery destinations. + * `destination_resource_arn` - (Optional) The ARN of the AWS destination that this delivery destination represents. Required when `delivery_destination_configuration` is specified. +* `delivery_destination_type` - (Optional) The type of delivery destination. Valid values: `S3`, `CWL`, `FH`, `XRAY`. Required for X-Ray trace delivery destinations. For other destination types, this is computed from the `destination_resource_arn`. * `name` - (Required) The name for this delivery destination. * `output_format` - (Optional) The format of the logs that are sent to this delivery destination. Valid values: `json`, `plain`, `w3c`, `raw`, `parquet`. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. @@ -40,7 +50,6 @@ This resource supports the following arguments: This resource exports the following attributes in addition to the arguments above: * `arn` - The Amazon Resource Name (ARN) of the delivery destination. -* `delivery_destination_type` - Whether this delivery destination is CloudWatch Logs, Amazon S3, or Firehose. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Import diff --git a/website/docs/r/connect_routing_profile.html.markdown b/website/docs/r/connect_routing_profile.html.markdown index 833c7fb69537..b4ad49dd41cd 100644 --- a/website/docs/r/connect_routing_profile.html.markdown +++ b/website/docs/r/connect_routing_profile.html.markdown @@ -9,7 +9,7 @@ description: |- # Resource: aws_connect_routing_profile Provides an Amazon Connect Routing Profile resource. For more information see -[Amazon Connect: Getting Started](https://docs.aws.amazon.com/connect/latest/adminguide/amazon-connect-get-started.html) +[Amazon Connect: Getting Started](https://docs.aws.amazon.com/connect/latest/adminguide/amazon-connect-get-started.html). ## Example Usage @@ -23,6 +23,17 @@ resource "aws_connect_routing_profile" "example" { media_concurrencies { channel = "VOICE" concurrency = 1 + cross_channel_behavior { + behavior_type = "ROUTE_ANY_CHANNEL" + } + } + + media_concurrencies { + channel = "CHAT" + concurrency = 3 + cross_channel_behavior { + behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY" + } } queue_configs { @@ -52,12 +63,23 @@ This resource supports the following arguments: * `tags` - (Optional) Tags to apply to the Routing Profile. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. -A `media_concurrencies` block supports the following arguments: +### `media_concurrencies` Argument Reference + +The `media_concurrencies` block supports the following arguments: * `channel` - (Required) Specifies the channels that agents can handle in the Contact Control Panel (CCP). Valid values are `VOICE`, `CHAT`, `TASK`. -* `concurrency` - (Required) Specifies the number of contacts an agent can have on a channel simultaneously. Valid Range for `VOICE`: Minimum value of 1. Maximum value of 1. Valid Range for `CHAT`: Minimum value of 1. Maximum value of 10. Valid Range for `TASK`: Minimum value of 1. Maximum value of 10. +* `concurrency` - (Required) Specifies the number of contacts an agent can have on a channel simultaneously. Valid Range for `VOICE`: Minimum value of `1`. Maximum value of `1`. Valid Range for `CHAT`: Minimum value of `1`. Maximum value of `10`. Valid Range for `TASK`: Minimum value of `1`. Maximum value of `10`. +* `cross_channel_behavior` - (Optional) Defines the cross-channel routing behavior for each traffic type. **Out-of-band changes are only detected when this argument is explicitly configured in your Terraform configuration.** Documented below. + +#### `cross_channel_behavior` Argument Reference -A `queue_configs` block supports the following arguments: +The `cross_channel_behavior` block supports the following arguments: + +* `behavior_type` - (Required) Specifies the cross-channel behavior for routing contacts across multiple channels. Valid values are `ROUTE_CURRENT_CHANNEL_ONLY` and `ROUTE_ANY_CHANNEL`. `ROUTE_CURRENT_CHANNEL_ONLY` restricts agents to receive contacts only from the channel they are currently handling. `ROUTE_ANY_CHANNEL` allows agents to receive contacts from any channel regardless of what they are currently handling. + +### `queue_configs` Argument Reference + +The `queue_configs` block supports the following arguments: * `channel` - (Required) Specifies the channels agents can handle in the Contact Control Panel (CCP) for this routing profile. Valid values are `VOICE`, `CHAT`, `TASK`. * `delay` - (Required) Specifies the delay, in seconds, that a contact should be in the queue before they are routed to an available agent @@ -68,13 +90,15 @@ A `queue_configs` block supports the following arguments: This resource exports the following attributes in addition to the arguments above: -* `arn` - The Amazon Resource Name (ARN) of the Routing Profile. -* `id` - The identifier of the hosting Amazon Connect Instance and identifier of the Routing Profile separated by a colon (`:`). +* `arn` - Amazon Resource Name (ARN) of the Routing Profile. +* `id` - Identifier of the hosting Amazon Connect Instance and identifier of the Routing Profile separated by a colon (`:`). * `queue_configs` - In addition to the arguments used in the `queue_configs` argument block, there are additional attributes exported within the `queue_configs` block. These additional attributes are documented below. -* `routing_profile_id` - The identifier for the Routing Profile. +* `routing_profile_id` - Identifier for the Routing Profile. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). -A `queue_configs` block supports the following attributes in addition to the arguments defined earlier: +### `queue_configs` Attribute Reference + +The `queue_configs` block includes the following attributes in addition to the arguments defined earlier: * `queue_arn` - ARN for the queue. * `queue_name` - Name for the queue. diff --git a/website/docs/r/dynamodb_table.html.markdown b/website/docs/r/dynamodb_table.html.markdown index 6df6124189d2..09377bf7e686 100644 --- a/website/docs/r/dynamodb_table.html.markdown +++ b/website/docs/r/dynamodb_table.html.markdown @@ -108,9 +108,13 @@ resource "aws_dynamodb_table" "example" { A global table configured for Multi-Region strong consistency (MRSC) provides the ability to perform a strongly consistent read with multi-Region scope. Performing a strongly consistent read on an MRSC table ensures you're always reading the latest version of an item, irrespective of the Region in which you're performing the read. +You can configure a MRSC global table with three replicas, or with two replicas and one witness. A witness is a component of a MRSC global table that contains data written to global table replicas, and provides an optional alternative to a full replica while supporting MRSC's availability architecture. You cannot perform read or write operations on a witness. A witness is located in a different Region than the two replicas. + **Note** Please see detailed information, restrictions, caveats etc on the [AWS Support Page](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/multi-region-strong-consistency-gt.html). -Consistency Mode (`consistency_mode`) is a new argument on the embedded `replica` that allows you to configure consistency mode for Global Tables. +Consistency Mode (`consistency_mode`) on the embedded `replica` allows you to configure consistency mode for Global Tables. + +##### Consistency mode with 3 Replicas ```terraform resource "aws_dynamodb_table" "example" { @@ -137,6 +141,32 @@ resource "aws_dynamodb_table" "example" { } ``` +##### Consistency Mode with 2 Replicas and Witness Region + +```terraform +resource "aws_dynamodb_table" "example" { + name = "example" + hash_key = "TestTableHashKey" + billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" + + attribute { + name = "TestTableHashKey" + type = "S" + } + + replica { + region_name = "us-east-2" + consistency_mode = "STRONG" + } + + global_table_witness { + region_name = "us-west-2" + } +} +``` + ### Replica Tagging You can manage global table replicas' tags in various ways. This example shows using `replica.*.propagate_tags` for the first replica and the `aws_dynamodb_tag` resource for the other. @@ -213,6 +243,7 @@ The following arguments are optional: * `deletion_protection_enabled` - (Optional) Enables deletion protection for table. Defaults to `false`. * `import_table` - (Optional) Import Amazon S3 data into a new table. See below. * `global_secondary_index` - (Optional) Describe a GSI for the table; subject to the normal limits on the number of GSIs, projected attributes, etc. See below. +* `global_table_witness` - (Optional) Witness Region in a Multi-Region Strong Consistency deployment. **Note** This must be used alongside a single `replica` with `consistency_mode` set to `STRONG`. Other combinations will fail to provision. See below. * `local_secondary_index` - (Optional, Forces new resource) Describe an LSI on the table; these can only be allocated _at creation_ so you cannot change this definition after you have created the resource. See below. * `on_demand_throughput` - (Optional) Sets the maximum number of read and write units for the specified on-demand table. See below. * `point_in_time_recovery` - (Optional) Enable point-in-time recovery options. See below. @@ -275,6 +306,10 @@ The following arguments are optional: * `warm_throughput` - (Optional) Sets the number of warm read and write units for this index. See below. * `write_capacity` - (Optional) Number of write units for this index. Must be set if billing_mode is set to PROVISIONED. +### `global_table_witness` + +* `region_name` - (Required) Name of the AWS Region that serves as a witness for the MRSC global table. + ### `local_secondary_index` * `name` - (Required) Name of the index diff --git a/website/docs/r/ec2_allowed_images_settings.html.markdown b/website/docs/r/ec2_allowed_images_settings.html.markdown new file mode 100644 index 000000000000..a05a11d24938 --- /dev/null +++ b/website/docs/r/ec2_allowed_images_settings.html.markdown @@ -0,0 +1,94 @@ +--- +subcategory: "EC2 (Elastic Compute Cloud)" +layout: "aws" +page_title: "AWS: aws_ec2_allowed_images_settings" +description: |- + Provides EC2 allowed images settings. +--- + +# Resource: aws_ec2_allowed_images_settings + +Provides EC2 allowed images settings for an AWS account. This feature allows you to control which AMIs can be used to launch EC2 instances in your account based on specified criteria. + +For more information about the image criteria that can be set, see the [AWS documentation on Allowed AMIs JSON configuration](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-allowed-amis.html#allowed-amis-json-configuration). + +~> **NOTE:** The AWS API does not delete this resource. When you run `destroy`, the provider will attempt to disable the setting. + +~> **NOTE:** There is only one allowed images settings configuration per AWS account and region. Creating this resource will configure the account-level settings. + +## Example Usage + +### Enable with Amazon AMIs only + +```terraform +resource "aws_ec2_allowed_images_settings" "example" { + state = "enabled" + + image_criterion { + image_providers = ["amazon"] + } +} +``` + +### Enable audit mode with specific account IDs + +```terraform +resource "aws_ec2_allowed_images_settings" "example" { + state = "audit-mode" + + image_criterion { + image_providers = ["amazon", "123456789012"] + } +} +``` + +## Argument Reference + +This resource supports the following arguments: + +- `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +- `state` - (Required) State of the allowed images settings. Valid values are `enabled` or `audit-mode`. +- `image_criterion` - (Optional) List of image criteria. Maximum of 10 criterion blocks allowed. See [`image_criterion`](#image_criterion) below. + +### `image_criterion` + +The `image_criterion` block supports the following: + +- `image_names` - (Optional) Set of AMI name patterns to allow. Maximum of 50 names. +- `image_providers` - (Optional) Set of image providers to allow. Maximum of 200 providers. Valid values include `amazon`, `aws-marketplace`, `aws-backup-vault`, `none`, or a 12-digit AWS account ID. +- `marketplace_product_codes` - (Optional) Set of AWS Marketplace product codes to allow. Maximum of 50 product codes. +- `creation_date_condition` - (Optional) Condition based on AMI creation date. See [`creation_date_condition`](#creation_date_condition) below. +- `deprecation_time_condition` - (Optional) Condition based on AMI deprecation time. See [`deprecation_time_condition`](#deprecation_time_condition) below. + +### `creation_date_condition` + +The `creation_date_condition` block supports the following: + +- `maximum_days_since_created` - (Required) Maximum number of days since the AMI was created. + +### `deprecation_time_condition` + +The `deprecation_time_condition` block supports the following: + +- `maximum_days_since_deprecated` - (Required) Maximum number of days since the AMI was deprecated. Setting this to `0` means no deprecated images are allowed. + +## Attribute Reference + +This resource exports no additional attributes. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import EC2 allowed images settings. Since there is only one configuration per account and region, region is used as the resource ID. For example: + +```terraform +import { + to = aws_ec2_allowed_images_settings.example + id = "us-east-1" +} +``` + +Using `terraform import`, import EC2 allowed images settings. For example: + +```console +% terraform import aws_ec2_allowed_images_settings.example us-east-1 +``` diff --git a/website/docs/r/ec2_image_block_public_access.markdown b/website/docs/r/ec2_image_block_public_access.html.markdown similarity index 81% rename from website/docs/r/ec2_image_block_public_access.markdown rename to website/docs/r/ec2_image_block_public_access.html.markdown index 871599db420d..da311f5f89cb 100644 --- a/website/docs/r/ec2_image_block_public_access.markdown +++ b/website/docs/r/ec2_image_block_public_access.html.markdown @@ -26,6 +26,7 @@ resource "aws_ec2_image_block_public_access" "test" { This resource supports the following arguments: +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `state` - (Required) The state of block public access for AMIs at the account level in the configured AWS Region. Valid values: `unblocked` and `block-new-sharing`. ## Attribute Reference diff --git a/website/docs/r/ec2_serial_console_access.html.markdown b/website/docs/r/ec2_serial_console_access.html.markdown index 79e28aa28b9e..906d656a6862 100644 --- a/website/docs/r/ec2_serial_console_access.html.markdown +++ b/website/docs/r/ec2_serial_console_access.html.markdown @@ -24,8 +24,8 @@ resource "aws_ec2_serial_console_access" "example" { This resource supports the following arguments: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `enabled` - (Optional) Whether or not serial console access is enabled. Valid values are `true` or `false`. Defaults to `true`. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). ## Attribute Reference diff --git a/website/docs/r/ecs_service.html.markdown b/website/docs/r/ecs_service.html.markdown index e23197b8b597..01f41c8ef0b5 100644 --- a/website/docs/r/ecs_service.html.markdown +++ b/website/docs/r/ecs_service.html.markdown @@ -120,6 +120,48 @@ resource "aws_ecs_service" "example" { } ``` +### Linear Deployment Strategy + +```terraform +resource "aws_ecs_service" "example" { + name = "example" + cluster = aws_ecs_cluster.example.id + + # ... other configurations ... + + deployment_configuration { + strategy = "LINEAR" + bake_time_in_minutes = 10 + + linear_configuration { + step_percent = 25.0 + step_bake_time_in_minutes = 5 + } + } +} +``` + +### Canary Deployment Strategy + +```terraform +resource "aws_ecs_service" "example" { + name = "example" + cluster = aws_ecs_cluster.example.id + + # ... other configurations ... + + deployment_configuration { + strategy = "CANARY" + bake_time_in_minutes = 15 + + canary_configuration { + canary_percent = 10.0 + canary_bake_time_in_minutes = 5 + } + } +} +``` + ### Redeploy Service On Every Apply The key used with `triggers` is arbitrary. @@ -144,7 +186,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `alarms` - (Optional) Information about the CloudWatch alarms. [See below](#alarms). * `availability_zone_rebalancing` - (Optional) ECS automatically redistributes tasks within a service across Availability Zones (AZs) to mitigate the risk of impaired application availability due to underlying infrastructure failures and task lifecycle activities. The valid values are `ENABLED` and `DISABLED`. When creating a new service, if no value is specified, it defaults to `ENABLED` if the service is compatible with AvailabilityZoneRebalancing. When updating an existing service, if no value is specified it defaults to the existing service's AvailabilityZoneRebalancing value. If the service never had an AvailabilityZoneRebalancing value set, Amazon ECS treats this as `DISABLED`. * `capacity_provider_strategy` - (Optional) Capacity provider strategies to use for the service. Can be one or more. Updating this argument requires `force_new_deployment = true`. [See below](#capacity_provider_strategy). Conflicts with `launch_type`. @@ -168,6 +209,7 @@ The following arguments are optional: * `placement_constraints` - (Optional) Rules that are taken into consideration during task placement. Updates to this configuration will take effect next task deployment unless `force_new_deployment` is enabled. Maximum number of `placement_constraints` is `10`. [See below](#placement_constraints). * `platform_version` - (Optional) Platform version on which to run your service. Only applicable for `launch_type` set to `FARGATE`. Defaults to `LATEST`. More information about Fargate platform versions can be found in the [AWS ECS User Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/platform_versions.html). * `propagate_tags` - (Optional) Whether to propagate the tags from the task definition or the service to the tasks. The valid values are `SERVICE` and `TASK_DEFINITION`. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `scheduling_strategy` - (Optional) Scheduling strategy to use for the service. The valid values are `REPLICA` and `DAEMON`. Defaults to `REPLICA`. Note that [*Tasks using the Fargate launch type or the `CODE_DEPLOY` or `EXTERNAL` deployment controller types don't support the `DAEMON` scheduling strategy*](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html). * `service_connect_configuration` - (Optional) ECS Service Connect configuration for this service to discover and connect to services, and be discovered by, and connected from, other services within a namespace. [See below](#service_connect_configuration). * `service_registries` - (Optional) Service discovery registries for the service. The maximum number of `service_registries` blocks is `1`. [See below](#service_registries). @@ -191,32 +233,32 @@ The `alarms` configuration block supports the following: The `volume_configuration` configuration block supports the following: -* `name` - (Required) Name of the volume. * `managed_ebs_volume` - (Required) Configuration for the Amazon EBS volume that Amazon ECS creates and manages on your behalf. [See below](#managed_ebs_volume). +* `name` - (Required) Name of the volume. ### vpc_lattice_configurations `vpc_lattice_configurations` supports the following: +* `port_name` - (Required) The name of the port for a target group associated with the VPC Lattice configuration. * `role_arn` - (Required) The ARN of the IAM role to associate with this volume. This is the Amazon ECS infrastructure IAM role that is used to manage your AWS infrastructure. * `target_group_arn` - (Required) The full ARN of the target group or groups associated with the VPC Lattice configuration. -* `port_name` - (Required) The name of the port for a target group associated with the VPC Lattice configuration. ### managed_ebs_volume The `managed_ebs_volume` configuration block supports the following: -* `role_arn` - (Required) Amazon ECS infrastructure IAM role that is used to manage your Amazon Web Services infrastructure. Recommended using the Amazon ECS-managed `AmazonECSInfrastructureRolePolicyForVolumes` IAM policy with this role. * `encrypted` - (Optional) Whether the volume should be encrypted. Default value is `true`. * `file_system_type` - (Optional) Linux filesystem type for the volume. For volumes created from a snapshot, same filesystem type must be specified that the volume was using when the snapshot was created. Valid values are `ext3`, `ext4`, `xfs`. Default value is `xfs`. * `iops` - (Optional) Number of I/O operations per second (IOPS). * `kms_key_id` - (Optional) Amazon Resource Name (ARN) identifier of the Amazon Web Services Key Management Service key to use for Amazon EBS encryption. +* `role_arn` - (Required) Amazon ECS infrastructure IAM role that is used to manage your Amazon Web Services infrastructure. Recommended using the Amazon ECS-managed `AmazonECSInfrastructureRolePolicyForVolumes` IAM policy with this role. * `size_in_gb` - (Optional) Size of the volume in GiB. You must specify either a `size_in_gb` or a `snapshot_id`. You can optionally specify a volume size greater than or equal to the snapshot size. * `snapshot_id` - (Optional) Snapshot that Amazon ECS uses to create the volume. You must specify either a `size_in_gb` or a `snapshot_id`. +* `tag_specifications` - (Optional) The tags to apply to the volume. [See below](#tag_specifications). * `throughput` - (Optional) Throughput to provision for a volume, in MiB/s, with a maximum of 1,000 MiB/s. * `volume_initialization_rate` - (Optional) Volume Initialization Rate in MiB/s. You must also specify a `snapshot_id`. * `volume_type` - (Optional) Volume type. -* `tag_specifications` - (Optional) The tags to apply to the volume. [See below](#tag_specifications). ### capacity_provider_strategy @@ -230,18 +272,34 @@ The `capacity_provider_strategy` configuration block supports the following: The `deployment_configuration` configuration block supports the following: -* `strategy` - (Optional) Type of deployment strategy. Valid values: `ROLLING`, `BLUE_GREEN`. Default: `ROLLING`. -* `bake_time_in_minutes` - (Optional) Number of minutes to wait after a new deployment is fully provisioned before terminating the old deployment. Only used when `strategy` is set to `BLUE_GREEN`. +* `bake_time_in_minutes` - (Optional) Number of minutes to wait after a new deployment is fully provisioned before terminating the old deployment. Valid range: 0-1440 minutes. Used with `BLUE_GREEN`, `LINEAR`, and `CANARY` strategies. +* `canary_configuration` - (Optional) Configuration block for canary deployment strategy. Required when `strategy` is set to `CANARY`. [See below](#canary_configuration). * `lifecycle_hook` - (Optional) Configuration block for lifecycle hooks that are invoked during deployments. [See below](#lifecycle_hook). +* `linear_configuration` - (Optional) Configuration block for linear deployment strategy. Required when `strategy` is set to `LINEAR`. [See below](#linear_configuration). +* `strategy` - (Optional) Type of deployment strategy. Valid values: `ROLLING`, `BLUE_GREEN`, `LINEAR`, `CANARY`. Default: `ROLLING`. ### lifecycle_hook The `lifecycle_hook` configuration block supports the following: +* `hook_details` - (Optional) Custom parameters that Amazon ECS will pass to the hook target invocations (such as a Lambda function). * `hook_target_arn` - (Required) ARN of the Lambda function to invoke for the lifecycle hook. -* `role_arn` - (Required) ARN of the IAM role that grants the service permission to invoke the Lambda function. * `lifecycle_stages` - (Required) Stages during the deployment when the hook should be invoked. Valid values: `RECONCILE_SERVICE`, `PRE_SCALE_UP`, `POST_SCALE_UP`, `TEST_TRAFFIC_SHIFT`, `POST_TEST_TRAFFIC_SHIFT`, `PRODUCTION_TRAFFIC_SHIFT`, `POST_PRODUCTION_TRAFFIC_SHIFT`. -* `hook_details` - (Optional) Custom parameters that Amazon ECS will pass to the hook target invocations (such as a Lambda function). +* `role_arn` - (Required) ARN of the IAM role that grants the service permission to invoke the Lambda function. + +### linear_configuration + +The `linear_configuration` configuration block supports the following: + +* `step_bake_time_in_minutes` - (Optional) Number of minutes to wait between each step during a linear deployment. Valid range: 0-1440 minutes. +* `step_percent` - (Required) Percentage of traffic to shift in each step during a linear deployment. Valid range: 3.0-100.0. + +### canary_configuration + +The `canary_configuration` configuration block supports the following: + +* `canary_bake_time_in_minutes` - (Optional) Number of minutes to wait before shifting all traffic to the new deployment. Valid range: 0-1440 minutes. +* `canary_percent` - (Required) Percentage of traffic to route to the canary deployment. Valid range: 0.1-100.0. ### deployment_circuit_breaker @@ -260,11 +318,11 @@ The `deployment_controller` configuration block supports the following: `load_balancer` supports the following: -* `elb_name` - (Required for ELB Classic) Name of the ELB (Classic) to associate with the service. -* `target_group_arn` - (Required for ALB/NLB) ARN of the Load Balancer target group to associate with the service. +* `advanced_configuration` - (Optional) Configuration block for Blue/Green deployment settings. Required when using `BLUE_GREEN` deployment strategy. [See below](#advanced_configuration). * `container_name` - (Required) Name of the container to associate with the load balancer (as it appears in a container definition). * `container_port` - (Required) Port on the container to associate with the load balancer. -* `advanced_configuration` - (Optional) Configuration block for Blue/Green deployment settings. Required when using `BLUE_GREEN` deployment strategy. [See below](#advanced_configuration). +* `elb_name` - (Required for ELB Classic) Name of the ELB (Classic) to associate with the service. +* `target_group_arn` - (Required for ALB/NLB) ARN of the Load Balancer target group to associate with the service. -> **Version note:** Multiple `load_balancer` configuration block support was added in Terraform AWS Provider version 2.22.0. This allows configuration of [ECS service support for multiple target groups](https://aws.amazon.com/about-aws/whats-new/2019/07/amazon-ecs-services-now-support-multiple-load-balancer-target-groups/). @@ -281,9 +339,9 @@ The `advanced_configuration` configuration block supports the following: `network_configuration` support the following: -* `subnets` - (Required) Subnets associated with the task or service. -* `security_groups` - (Optional) Security groups associated with the task or service. If you do not specify a security group, the default security group for the VPC is used. * `assign_public_ip` - (Optional) Assign a public IP address to the ENI (Fargate launch type only). Valid values are `true` or `false`. Default `false`. +* `security_groups` - (Optional) Security groups associated with the task or service. If you do not specify a security group, the default security group for the VPC is used. +* `subnets` - (Required) Subnets associated with the task or service. For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-networking.html) @@ -291,11 +349,8 @@ For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonEC `ordered_placement_strategy` supports the following: +* `field` - (Optional) For the `spread` placement strategy, valid values are `instanceId` (or `host`, which has the same effect), or any platform or custom attribute that is applied to a container instance. For the `binpack` type, valid values are `memory` and `cpu`. For the `random` type, this attribute is not needed. For more information, see [Placement Strategy](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_PlacementStrategy.html). * `type` - (Required) Type of placement strategy. Must be one of: `binpack`, `random`, or `spread` -* `field` - (Optional) For the `spread` placement strategy, valid values are `instanceId` (or `host`, - which has the same effect), or any platform or custom attribute that is applied to a container instance. - For the `binpack` type, valid values are `memory` and `cpu`. For the `random` type, this attribute is not - needed. For more information, see [Placement Strategy](https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_PlacementStrategy.html). -> **Note:** for `spread`, `host` and `instanceId` will be normalized, by AWS, to be `instanceId`. This means the statefile will show `instanceId` but your config will differ if you use `host`. @@ -303,17 +358,17 @@ For more information, see [Task Networking](https://docs.aws.amazon.com/AmazonEC `placement_constraints` support the following: -* `type` - (Required) Type of constraint. The only valid values at this time are `memberOf` and `distinctInstance`. * `expression` - (Optional) Cluster Query Language expression to apply to the constraint. Does not need to be specified for the `distinctInstance` type. For more information, see [Cluster Query Language in the Amazon EC2 Container Service Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-query-language.html). +* `type` - (Required) Type of constraint. The only valid values at this time are `memberOf` and `distinctInstance`. ### service_registries `service_registries` support the following: -* `registry_arn` - (Required) ARN of the Service Registry. The currently supported service registry is Amazon Route 53 Auto Naming Service(`aws_service_discovery_service`). For more information, see [Service](https://docs.aws.amazon.com/Route53/latest/APIReference/API_autonaming_Service.html) -* `port` - (Optional) Port value used if your Service Discovery service specified an SRV record. -* `container_port` - (Optional) Port value, already specified in the task definition, to be used for your service discovery service. * `container_name` - (Optional) Container name value, already specified in the task definition, to be used for your service discovery service. +* `container_port` - (Optional) Port value, already specified in the task definition, to be used for your service discovery service. +* `port` - (Optional) Port value used if your Service Discovery service specified an SRV record. +* `registry_arn` - (Required) ARN of the Service Registry. The currently supported service registry is Amazon Route 53 Auto Naming Service(`aws_service_discovery_service`). For more information, see [Service](https://docs.aws.amazon.com/Route53/latest/APIReference/API_autonaming_Service.html) ### service_connect_configuration diff --git a/website/docs/r/emr_managed_scaling_policy.html.markdown b/website/docs/r/emr_managed_scaling_policy.html.markdown index a3f92fb6fe46..021b9a2b3197 100644 --- a/website/docs/r/emr_managed_scaling_policy.html.markdown +++ b/website/docs/r/emr_managed_scaling_policy.html.markdown @@ -46,6 +46,8 @@ This resource supports the following arguments: * `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `cluster_id` - (Required) ID of the EMR cluster * `compute_limits` - (Required) Configuration block with compute limit settings. Described below. +* `scaling_strategy` – (Optional) Specifies the scaling strategy. When set to `ADVANCED`, the `utilization_performance_index` argument can be used to configure an advanced scaling strategy. An advanced scaling strategy requires Amazon EMR on EC2 version 7.0 or later. Valid values: `ADVANCED`, `DEFAULT`. +* `utilization_performance_index` – (Optional) Integer value that represents the advanced scaling strategy. Higher values optimize for performance, while lower values optimize for resource conservation. A value of `50` provides a balance between performance and resource conservation. See [the AWS documentation](https://docs.aws.amazon.com/emr/latest/ManagementGuide/managed-scaling-allocation-strategy-optimized.html#managed-scaling-allocation-strategy-optimized-getting-started) for more details. Required when `scaling_strategy` is set to `ADVANCED`. Valid values: `1`, `25`, `50`, `75`, `100`. ### compute_limits diff --git a/website/docs/r/fis_experiment_template.html.markdown b/website/docs/r/fis_experiment_template.html.markdown index 5d450513f14e..11c0ae4288ac 100644 --- a/website/docs/r/fis_experiment_template.html.markdown +++ b/website/docs/r/fis_experiment_template.html.markdown @@ -208,7 +208,7 @@ For a list of parameters supported by each action, see [AWS FIS actions referenc #### `target` (`action.*.target`) -* `key` - (Required) Target type. Valid values are `AutoScalingGroups` (EC2 Auto Scaling groups), `Buckets` (S3 Buckets), `Cluster` (EKS Cluster), `Clusters` (ECS Clusters), `DBInstances` (RDS DB Instances), `Instances` (EC2 Instances), `ManagedResources` (EKS clusters, Application and Network Load Balancers, and EC2 Auto Scaling groups that are enabled for ARC zonal shift), `Nodegroups` (EKS Node groups), `Pods` (EKS Pods), `ReplicationGroups`(ElastiCache Redis Replication Groups), `Roles` (IAM Roles), `SpotInstances` (EC2 Spot Instances), `Subnets` (VPC Subnets), `Tables` (DynamoDB encrypted global tables), `Tasks` (ECS Tasks), `TransitGateways` (Transit gateways), `Volumes` (EBS Volumes). See the [documentation](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) for more details. +* `key` - (Required) Target type. Valid values are `AutoScalingGroups` (EC2 Auto Scaling groups), `Buckets` (S3 Buckets), `Cluster` (EKS Cluster), `Clusters` (ECS Clusters), `DBInstances` (RDS DB Instances), `Functions` (Lambda Functions), `Instances` (EC2 Instances), `ManagedResources` (EKS clusters, Application and Network Load Balancers, and EC2 Auto Scaling groups that are enabled for ARC zonal shift), `Nodegroups` (EKS Node groups), `Pods` (EKS Pods), `ReplicationGroups`(ElastiCache Redis Replication Groups), `Roles` (IAM Roles), `SpotInstances` (EC2 Spot Instances), `Subnets` (VPC Subnets), `Tables` (DynamoDB encrypted global tables), `Tasks` (ECS Tasks), `TransitGateways` (Transit gateways), `Volumes` (EBS Volumes). See the [documentation](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) for more details. * `value` - (Required) Target name, referencing a corresponding target. ### `stop_condition` @@ -248,7 +248,7 @@ For a list of parameters supported by each action, see [AWS FIS actions referenc #### `cloudwatch_logs_configuration` -* `log_group_arn` - (Required) The Amazon Resource Name (ARN) of the destination Amazon CloudWatch Logs log group. +* `log_group_arn` - (Required) The Amazon Resource Name (ARN) of the destination Amazon CloudWatch Logs log group. The ARN must end with `:*` #### `s3_configuration` diff --git a/website/docs/r/kms_key.html.markdown b/website/docs/r/kms_key.html.markdown index 63c427dc1c1b..bbcf9f77691f 100644 --- a/website/docs/r/kms_key.html.markdown +++ b/website/docs/r/kms_key.html.markdown @@ -316,7 +316,7 @@ This resource supports the following arguments: Defaults to `ENCRYPT_DECRYPT`. * `custom_key_store_id` - (Optional) ID of the KMS [Custom Key Store](https://docs.aws.amazon.com/kms/latest/developerguide/create-cmk-keystore.html) where the key will be stored instead of KMS (eg CloudHSM). * `customer_master_key_spec` - (Optional) Specifies whether the key contains a symmetric key or an asymmetric key pair and the encryption algorithms or signing algorithms that the key supports. -Valid values: `SYMMETRIC_DEFAULT`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `HMAC_224`, `HMAC_256`, `HMAC_384`, `HMAC_512`, `ECC_NIST_P256`, `ECC_NIST_P384`, `ECC_NIST_P521`, `ECC_SECG_P256K1`, `ML_DSA_44`, `ML_DSA_65`, `ML_DSA_87`, or `SM2` (China Regions only). Defaults to `SYMMETRIC_DEFAULT`. For help with choosing a key spec, see the [AWS KMS Developer Guide](https://docs.aws.amazon.com/kms/latest/developerguide/symm-asymm-choose.html). +Valid values: `SYMMETRIC_DEFAULT`, `RSA_2048`, `RSA_3072`, `RSA_4096`, `HMAC_224`, `HMAC_256`, `HMAC_384`, `HMAC_512`, `ECC_NIST_P256`, `ECC_NIST_P384`, `ECC_NIST_P521`, `ECC_SECG_P256K1`, `ML_DSA_44`, `ML_DSA_65`, `ML_DSA_87`, `SM2` (China Regions only), or `ECC_NIST_EDWARDS25519`. Defaults to `SYMMETRIC_DEFAULT`. For help with choosing a key spec, see the [AWS KMS Developer Guide](https://docs.aws.amazon.com/kms/latest/developerguide/symm-asymm-choose.html). * `policy` - (Optional) A valid policy JSON document. Although this is a key policy, not an IAM policy, an [`aws_iam_policy_document`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document), in the form that designates a principal, can be used. For more information about building policy documents with Terraform, see the [AWS IAM Policy Document Guide](https://learn.hashicorp.com/terraform/aws/iam-policy). ~> **NOTE:** Note: All KMS keys must have a key policy. If a key policy is not specified, AWS gives the KMS key a [default key policy](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html#key-policy-default) that gives all principals in the owning account unlimited access to all KMS operations for the key. This default key policy effectively delegates all access control to IAM policies and KMS grants. diff --git a/website/docs/r/lambda_invocation.html.markdown b/website/docs/r/lambda_invocation.html.markdown index 5ac0e64f8ff2..582d8d35235e 100644 --- a/website/docs/r/lambda_invocation.html.markdown +++ b/website/docs/r/lambda_invocation.html.markdown @@ -181,3 +181,23 @@ The following arguments are optional: This resource exports the following attributes in addition to the arguments above: * `result` - String result of the Lambda function invocation. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Lambda Invocation using the `function_name,qualifier,result_hash`. For example: + +```terraform +import { + to = aws_lambda_invocation.test_lambda + id = "my_test_lambda_function,$LATEST,b326b5062b2f0e69046810717534cb09" +} +``` + +Using `terraform import`, import Lambda Invocation using the `function_name,qualifier,result_hash`. For example: + +```console +% terraform import aws_lambda_invocation.test_lambda my_test_lambda_function,$LATEST,b326b5062b2f0e69046810717534cb09 +``` + +Because it is not possible to retrieve previous invocations, during the next apply `terraform` will update the resource calling again the function. +To compute the `result_hash`, it is necessary to hash it with the standard `md5` hash function. diff --git a/website/docs/r/lb_listener.html.markdown b/website/docs/r/lb_listener.html.markdown index f17a72c4bc30..05b47a4be1ce 100644 --- a/website/docs/r/lb_listener.html.markdown +++ b/website/docs/r/lb_listener.html.markdown @@ -225,6 +225,42 @@ resource "aws_lb_listener" "front_end" { } ``` +### JWT Validation Action + +```terraform +resource "aws_lb_listener" "test" { + load_balancer_arn = aws_lb.test.id + protocol = "HTTPS" + port = "443" + ssl_policy = "ELBSecurityPolicy-2016-08" + certificate_arn = aws_iam_server_certificate.test.arn + + default_action { + type = "jwt-validation" + + jwt_validation { + issuer = "https://example.com" + jwks_endpoint = "https://example.com/.well-known/jwks.json" + additional_claim { + format = "string-array" + name = "claim_name1" + values = ["value1", "value2"] + } + additional_claim { + format = "single-string" + name = "claim_name2" + values = ["value1"] + } + } + } + + default_action { + target_group_arn = aws_lb_target_group.test.id + type = "forward" + } +} +``` + ### Gateway Load Balancer Listener ```terraform @@ -332,15 +368,15 @@ The following arguments are optional: The following arguments are required: -* `type` - (Required) Type of routing action. Valid values are `forward`, `redirect`, `fixed-response`, `authenticate-cognito` and `authenticate-oidc`. +* `type` - (Required) Type of routing action. Valid values are `forward`, `redirect`, `fixed-response`, `authenticate-cognito`, `authenticate-oidc` and `jwt-validation`. The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `authenticate_cognito` - (Optional) Configuration block for using Amazon Cognito to authenticate users. Specify only when `type` is `authenticate-cognito`. See below. * `authenticate_oidc` - (Optional) Configuration block for an identity provider that is compliant with OpenID Connect (OIDC). Specify only when `type` is `authenticate-oidc`. See below. * `fixed_response` - (Optional) Information for creating an action that returns a custom HTTP response. Required if `type` is `fixed-response`. * `forward` - (Optional) Configuration block for creating an action that distributes requests among one or more target groups. Specify only if `type` is `forward`. See below. +* `jwt_validation` - (Optional) Configuration block for creating a JWT validation action. Required if `type` is `jwt-validation`. * `order` - (Optional) Order for the action. The action with the lowest value for order is performed first. Valid values are between `1` and `50000`. Defaults to the position in the list of actions. * `redirect` - (Optional) Configuration block for creating a redirect action. Required if `type` is `redirect`. See below. * `target_group_arn` - (Optional) ARN of the Target Group to which to route traffic. Specify only if `type` is `forward` and you want to route to a single target group. To route to one or more target groups, use a `forward` block instead. Can be specified with `forward` but ARNs must match. @@ -355,7 +391,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `authentication_request_extra_params` - (Optional) Query parameters to include in the redirect request to the authorization endpoint. Max: 10. See below. * `on_unauthenticated_request` - (Optional) Behavior if the user is not authenticated. Valid values are `deny`, `allow` and `authenticate`. * `scope` - (Optional) Set of user claims to be requested from the IdP. @@ -380,7 +415,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `authentication_request_extra_params` - (Optional) Query parameters to include in the redirect request to the authorization endpoint. Max: 10. * `on_unauthenticated_request` - (Optional) Behavior if the user is not authenticated. Valid values: `deny`, `allow` and `authenticate` * `scope` - (Optional) Set of user claims to be requested from the IdP. @@ -395,7 +429,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `message_body` - (Optional) Message body. * `status_code` - (Optional) HTTP response code. Valid values are `2XX`, `4XX`, or `5XX`. @@ -407,7 +440,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `stickiness` - (Optional) Configuration block for target group stickiness for the rule. See below. ##### target_group @@ -418,7 +450,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `weight` - (Optional) Weight. The range is 0 to 999. ##### stickiness @@ -429,9 +460,27 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `enabled` - (Optional) Whether target group stickiness is enabled. Default is `false`. +#### jwt_validation + +The following arguments are required: + +* `issuer` - (Required) Issuer of the JWT. +* `jwks_endpoint` - (Required) JSON Web Key Set (JWKS) endpoint. This endpoint contains JSON Web Keys (JWK) that are used to validate signatures from the provider. This must be a full URL, including the HTTPS protocol, the domain, and the path. + +The following arguments are optional: + +* `additional_claim` - (Optional) Repeatable configuration block for additional claims to validate. + +#### additional_claim + +The following arguments are required: + +* `format` - (Required) Format of the claim value. Valid values are `single-string`, `string-array` and `space-separated-values`. +* `name` - (Required) Name of the claim to validate. `exp`, `iss`, `nbf`, or `iat` cannot be specified because they are validated by default. +* `values` - (Required) List of expected values of the claim. + #### redirect ~> **NOTE::** You can reuse URI components using the following reserved keywords: `#{protocol}`, `#{host}`, `#{port}`, `#{path}` (the leading "/" is removed) and `#{query}`. @@ -442,7 +491,6 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `host` - (Optional) Hostname. This component is not percent-encoded. The hostname can contain `#{host}`. Defaults to `#{host}`. * `path` - (Optional) Absolute path, starting with the leading "/". This component is not percent-encoded. The path can contain #{host}, #{path}, and #{port}. Defaults to `/#{path}`. * `port` - (Optional) Port. Specify a value from `1` to `65535` or `#{port}`. Defaults to `#{port}`. diff --git a/website/docs/r/lb_listener_rule.html.markdown b/website/docs/r/lb_listener_rule.html.markdown index bea63266cdf1..c664f1651d4c 100644 --- a/website/docs/r/lb_listener_rule.html.markdown +++ b/website/docs/r/lb_listener_rule.html.markdown @@ -203,6 +203,36 @@ resource "aws_lb_listener_rule" "oidc" { } } +# JWT-validation Action + +resource "aws_lb_listener_rule" "oidc" { + listener_arn = aws_lb_listener.front_end.arn + + action { + type = "jwt-validation" + + jwt_validation { + issuer = "https://example.com" + jwks_endpoint = "https://example.com/.well-known/jwks.json" + additional_claim { + format = "string-array" + name = "claim_name1" + values = ["value1", "value2"] + } + additional_claim { + format = "single-string" + name = "claim_name2" + values = ["value1"] + } + } + } + + action { + type = "forward" + target_group_arn = aws_lb_target_group.static.arn + } +} + # With transform resource "aws_lb_listener_rule" "transform" { @@ -257,13 +287,14 @@ This resource supports the following arguments: Action Blocks (for `action`) support the following: -* `type` - (Required) The type of routing action. Valid values are `forward`, `redirect`, `fixed-response`, `authenticate-cognito` and `authenticate-oidc`. +* `type` - (Required) The type of routing action. Valid values are `forward`, `redirect`, `fixed-response`, `authenticate-cognito`, `authenticate-oidc` and `jwt-validation`. * `authenticate_cognito` - (Optional) Information for creating an authenticate action using Cognito. Required if `type` is `authenticate-cognito`. * `authenticate_oidc` - (Optional) Information for creating an authenticate action using OIDC. Required if `type` is `authenticate-oidc`. * `fixed_response` - (Optional) Information for creating an action that returns a custom HTTP response. Required if `type` is `fixed-response`. * `forward` - (Optional) Configuration block for creating an action that distributes requests among one or more target groups. Specify only if `type` is `forward`. Cannot be specified with `target_group_arn`. +* `jwt_validation` - (Optional) Information for creating a JWT validation action. Required if `type` is `jwt-validation`. * `order` - (Optional) Order for the action. The action with the lowest value for order is performed first. Valid values are between `1` and `50000`. @@ -336,6 +367,18 @@ Authentication Request Extra Params Blocks (for `authentication_request_extra_pa * `key` - (Required) The key of query parameter * `value` - (Required) The value of query parameter +JWT Validation Blocks (for `jwt_validation`) supports the following: + +* `issuer` - (Required) Issuer of the JWT. +* `jwks_endpoint` - (Required) JSON Web Key Set (JWKS) endpoint. This endpoint contains JSON Web Keys (JWK) that are used to validate signatures from the provider. This must be a full URL, including the HTTPS protocol, the domain, and the path. +* `additional_claim` - (Optional) Repeatable configuration block for additional claims to validate. + +Additional Claim Blocks (for `additional_claim`) supports the following: + +* `format` - (Required) Format of the claim value. Valid values are `single-string`, `string-array` and `space-separated-values`. +* `name` - (Required) Name of the claim to validate. `exp`, `iss`, `nbf`, or `iat` cannot be specified because they are validated by default. +* `values` - (Required) List of expected values of the claim. + ### Condition Blocks One or more condition blocks can be set per rule. Most condition types can only be specified once per rule except for `http-header` and `query-string` which can be specified multiple times. diff --git a/website/docs/r/networkflowmonitor_monitor.html.markdown b/website/docs/r/networkflowmonitor_monitor.html.markdown new file mode 100644 index 000000000000..e2a46feaa553 --- /dev/null +++ b/website/docs/r/networkflowmonitor_monitor.html.markdown @@ -0,0 +1,97 @@ +--- +subcategory: "CloudWatch NetworkFlow Monitor" +layout: "aws" +page_title: "AWS: aws_networkflowmonitor_monitor" +description: |- + Manages a Network Flow Monitor Monitor. +--- + +# Resource: aws_networkflowmonitor_monitor + +Manages a Network Flow Monitor Monitor. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_vpc" "example" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "example" + } +} + +resource "aws_networkflowmonitor_monitor" "example" { + monitor_name = "example-monitor" + scope_arn = aws_networkflowmonitor_scope.example.scope_arn + + local_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.example.arn + } + + remote_resource { + type = "AWS::EC2::VPC" + identifier = aws_vpc.example.arn + } + + tags = { + Name = "example" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `monitor_name` - (Required) The name of the monitor. Cannot be changed after creation. +* `scope_arn` - (Required) The Amazon Resource Name (ARN) of the scope for the monitor. Cannot be changed after creation. + +The following arguments are optional: + +* `local_resource` - (Optional) The local resources to monitor. A local resource in a workload is the location of the hosts where the Network Flow Monitor agent is installed. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `remote_resource` - (Optional) The remote resources to monitor. A remote resource is the other endpoint specified for the network flow of a workload, with a local resource. +* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +### local_resource and remote_resource + +The `local_resource` and `remote_resource` blocks support the following: + +* `type` - (Required) The type of the resource. Valid values are `AWS::EC2::VPC`, `AWS::EC2::Subnet`, `AWS::EC2::AvailabilityZone`, `AWS::EC2::Region`. +* `identifier` - (Required) The identifier of the resource. For VPC resources, this is the VPC ARN. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `monitor_arn` - The Amazon Resource Name (ARN) of the monitor. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `30m`) +* `update` - (Default `30m`) +* `delete` - (Default `30m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Network Flow Monitor Monitor using the monitor name. For example: + +```terraform +import { + to = aws_networkflowmonitor_monitor.example + id = "example-monitor" +} +``` + +Using `terraform import`, import Network Flow Monitor Monitor using the monitor name. For example: + +```console +% terraform import aws_networkflowmonitor_monitor.example example-monitor +``` diff --git a/website/docs/r/networkflowmonitor_scope.html.markdown b/website/docs/r/networkflowmonitor_scope.html.markdown new file mode 100644 index 000000000000..42ee8453edba --- /dev/null +++ b/website/docs/r/networkflowmonitor_scope.html.markdown @@ -0,0 +1,99 @@ +--- +subcategory: "CloudWatch NetworkFlow Monitor" +layout: "aws" +page_title: "AWS: aws_networkflowmonitor_scope" +description: |- + Manages a Network Flow Monitor Scope. +--- + +# Resource: aws_networkflowmonitor_scope + +Manages a Network Flow Monitor Scope. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_caller_identity" "current" {} + +resource "aws_networkflowmonitor_scope" "example" { + target { + region = "us-east-1" + target_identifier { + target_type = "ACCOUNT" + target_id { + account_id = data.aws_caller_identity.current.account_id + } + } + } + + tags = { + Name = "example" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `target` - (Required) The targets to define the scope to be monitored. A target is an array of target resources, which are currently Region-account pairs. + +The following arguments are optional: + +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +### targets + +The `targets` block supports the following: + +* `region` - (Required) The AWS Region for the scope. +* `target_identifier` - (Required) A target identifier is a pair of identifying information for a scope. + +### target_identifier + +The `target_identifier` block supports the following: + +* `target_id` - (Required) The identifier for a target, which is currently always an account ID. +* `target_type` - (Required) The type of a target. A target type is currently always `ACCOUNT`. + +### target_id + +The `target_id` block supports the following: + +* `account_id` - (Required) AWS account ID. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `scope_arn` - The Amazon Resource Name (ARN) of the scope. +* `scope_id` - The identifier for the scope that includes the resources you want to get data results for. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `30m`) +* `update` - (Default `30m`) +* `delete` - (Default `30m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Network Flow Monitor Scope using the scope ID. For example: + +```terraform +import { + to = aws_networkflowmonitor_scope.example + id = "example-scope-id" +} +``` + +Using `terraform import`, import Network Flow Monitor Scope using the scope ID. For example: + +```console +% terraform import aws_networkflowmonitor_scope.example example-scope-id +``` diff --git a/website/docs/r/notifications_channel_association.html.markdown b/website/docs/r/notifications_channel_association.html.markdown index 2bb27bf04206..3fd81310135b 100644 --- a/website/docs/r/notifications_channel_association.html.markdown +++ b/website/docs/r/notifications_channel_association.html.markdown @@ -34,7 +34,7 @@ resource "aws_notifications_channel_association" "example" { The following arguments are required: -* `arn` - (Required) ARN of the channel to associate with the notification configuration. This can be an email contact ARN. +* `arn` - (Required) ARN of the channel to associate with the notification configuration. Must match pattern `^arn:aws:(chatbot|consoleapp|notifications-contacts):[a-zA-Z0-9-]*:[0-9]{12}:[a-zA-Z0-9-_.@]+/[a-zA-Z0-9/_.@:-]+$`. * `notification_configuration_arn` - (Required) ARN of the notification configuration to associate the channel with. ## Attribute Reference diff --git a/website/docs/r/observabilityadmin_centralization_rule_for_organization.html.markdown b/website/docs/r/observabilityadmin_centralization_rule_for_organization.html.markdown new file mode 100644 index 000000000000..9849cba67f0a --- /dev/null +++ b/website/docs/r/observabilityadmin_centralization_rule_for_organization.html.markdown @@ -0,0 +1,208 @@ +--- +subcategory: "CloudWatch Observability Admin" +layout: "aws" +page_title: "AWS: aws_observabilityadmin_centralization_rule_for_organization" +description: |- + Manages an AWS CloudWatch Observability Admin Centralization Rule For Organization. +--- + +# Resource: aws_observabilityadmin_centralization_rule_for_organization + +Manages an AWS CloudWatch Observability Admin Centralization Rule For Organization. + +Centralization rules enable you to centralize log data from multiple AWS accounts and regions within your organization to a single destination account and region. This helps with log management, compliance, and cost optimization by consolidating logs in a central location. + +This requires an AWS account within an organization with at least [delegated administrator permissions](https://docs.aws.amazon.com/organizations/latest/APIReference/API_RegisterDelegatedAdministrator.html). + +## Example Usage + +### Basic Centralization Rule + +```terraform +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "example" { + rule_name = "example-centralization-rule" + + rule { + destination { + region = "eu-west-1" + account = data.aws_caller_identity.current.account_id + } + + source { + regions = ["ap-southeast-1"] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "SKIP" + log_group_selection_criteria = "*" + } + } + } + + tags = { + Name = "example-centralization-rule" + Environment = "production" + } +} +``` + +### Advanced Configuration with Encryption and Backup + +```terraform +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "advanced" { + rule_name = "advanced-centralization-rule" + + rule { + destination { + region = "eu-west-1" + account = data.aws_caller_identity.current.account_id + + destination_logs_configuration { + logs_encryption_configuration { + encryption_strategy = "AWS_OWNED" + } + + backup_configuration { + region = "us-west-1" + } + } + } + + source { + regions = ["ap-southeast-1", "us-east-1"] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "ALLOW" + log_group_selection_criteria = "*" + } + } + } + + tags = { + Name = "advanced-centralization-rule" + Environment = "production" + Team = "observability" + } +} +``` + +### Selective Log Group Filtering + +```terraform +data "aws_caller_identity" "current" {} +data "aws_organizations_organization" "current" {} + +resource "aws_observabilityadmin_centralization_rule_for_organization" "filtered" { + rule_name = "filtered-centralization-rule" + + rule { + destination { + region = "eu-west-1" + account = data.aws_caller_identity.current.account_id + } + + source { + regions = ["ap-southeast-1", "us-east-1"] + scope = "OrganizationId = '${data.aws_organizations_organization.current.id}'" + + source_logs_configuration { + encrypted_log_group_strategy = "ALLOW" + log_group_selection_criteria = "LogGroupName LIKE '/aws/lambda%'" + } + } + } + + tags = { + Name = "filtered-centralization-rule" + Filter = "lambda-logs" + } +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `rule_name` - (Required) Name of the centralization rule. Must be unique within the organization. +* `rule` - (Required) Configuration block for the centralization rule. See [`rule`](#rule) below. + +The following arguments are optional: + +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +### rule + +* `destination` - (Required) Configuration block for the destination where logs will be centralized. See [`destination`](#destination) below. +* `source` - (Required) Configuration block for the source of logs to be centralized. See [`source`](#source) below. + +### destination + +* `account` - (Required) AWS account ID where logs will be centralized. +* `region` - (Required) AWS region where logs will be centralized. +* `destination_logs_configuration` - (Optional) Configuration block for destination logs settings. See [`destination_logs_configuration`](#destination_logs_configuration) below. + +#### destination_logs_configuration + +* `backup_configuration` - (Optional) Configuration block for backup settings. See [`backup_configuration`](#backup_configuration) below. +* `logs_encryption_configuration` - (Optional) Configuration block for logs encryption settings. See [`logs_encryption_configuration`](#logs_encryption_configuration) below. + +##### backup_configuration + +* `region` - (Required) AWS region for backup storage. +* `kms_key_arn` - (Optional) ARN of the KMS key to use for backup encryption. + +##### logs_encryption_configuration + +* `encryption_strategy` - (Required) Encryption strategy for logs. Valid values: `AWS_OWNED`, `CUSTOMER_MANAGED`. +* `encryption_conflict_resolution_strategy` - (Optional) Strategy for resolving encryption conflicts. Valid values: `ALLOW`, `SKIP`. +* `kms_key_arn` - (Optional) ARN of the KMS key to use for encryption when `encryption_strategy` is `CUSTOMER_MANAGED`. + +### source + +* `regions` - (Required) Set of AWS regions from which to centralize logs. Must contain at least one region. +* `scope` - (Required) Scope defining which resources to include. Use organization ID format: `OrganizationId = 'o-example123456'`. +* `source_logs_configuration` - (Optional) Configuration block for source logs settings. See [`source_logs_configuration`](#source_logs_configuration) below. + +#### source_logs_configuration + +* `encrypted_log_group_strategy` - (Required) Strategy for handling encrypted log groups. Valid values: `ALLOW`, `SKIP`. +* `log_group_selection_criteria` - (Required) Criteria for selecting log groups. Use `*` for all log groups or OAM filter syntax like `LogGroupName LIKE '/aws/lambda%'`. Must be between 1 and 2000 characters. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `rule_arn` - ARN of the centralization rule. +* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +- `create` - (Default `5m`) +- `update` - (Default `5m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import CloudWatch Observability Admin Centralization Rule For Organization using the `rule_name`. For example: + +```terraform +import { + to = aws_observabilityadmin_centralization_rule_for_organization.example + id = "example-centralization-rule" +} +``` + +Using `terraform import`, import CloudWatch Observability Admin Centralization Rule For Organization using the `rule_name`. For example: + +```console +% terraform import aws_observabilityadmin_centralization_rule_for_organization.example example-centralization-rule +``` diff --git a/website/docs/r/odb_cloud_vm_cluster.html.markdown b/website/docs/r/odb_cloud_vm_cluster.html.markdown index 388c0313b806..2a127cb7ed75 100644 --- a/website/docs/r/odb_cloud_vm_cluster.html.markdown +++ b/website/docs/r/odb_cloud_vm_cluster.html.markdown @@ -8,7 +8,7 @@ description: |- # Resource: aws_odb_cloud_vm_cluster -Terraform to manage cloud vm cluster resource in AWS for Oracle Database@AWS. +Terraform to manage cloud vm cluster resource in AWS for Oracle Database@AWS. If underlying odb network and cloud exadata infrastructure is shared, ARN must be used while creating VM cluster. You can find out more about Oracle Database@AWS from [User Guide](https://docs.aws.amazon.com/odb/latest/UserGuide/what-is-odb.html). @@ -73,19 +73,21 @@ resource "aws_odb_cloud_vm_cluster" "with_all_parameters" { The following arguments are required: -* `cloud_exadata_infrastructure_id` - (Required) The unique identifier of the Exadata infrastructure for this VM cluster. Changing this will create a new resource. * `cpu_core_count` - (Required) The number of CPU cores to enable on the VM cluster. Changing this will create a new resource. * `db_servers` - (Required) The list of database servers for the VM cluster. Changing this will create a new resource. * `display_name` - (Required) A user-friendly name for the VM cluster. Changing this will create a new resource. * `gi_version` - (Required) A valid software version of Oracle Grid Infrastructure (GI). To get the list of valid values, use the ListGiVersions operation and specify the shape of the Exadata infrastructure. Example: 19.0.0.0 Changing this will create a new resource. * `hostname_prefix` - (Required) The host name prefix for the VM cluster. Constraints: - Can't be "localhost" or "hostname". - Can't contain "-version". - The maximum length of the combined hostname and domain is 63 characters. - The hostname must be unique within the subnet. Changing this will create a new resource. -* `odb_network_id` - (Required) The unique identifier of the ODB network for the VM cluster. Changing this will create a new resource. * `ssh_public_keys` - (Required) The public key portion of one or more key pairs used for SSH access to the VM cluster. Changing this will create a new resource. * `data_collection_options` - (Required) The set of preferences for the various diagnostic collection options for the VM cluster. * `data_storage_size_in_tbs` - (Required) The size of the data disk group, in terabytes (TBs), to allocate for the VM cluster. Changing this will create a new resource. The following arguments are optional: +* `odb_network_id` - (Optional) The unique identifier of the ODB network for the VM cluster. Changing this will create a new resource. Either the combination of cloud_exadata_infrastructure_id and odb_network_id or cloud_exadata_infrastructure_arn and odb_network_arn must be used. +* `cloud_exadata_infrastructure_id` - (Optional) The unique identifier of the Exadata infrastructure for this VM cluster. Changing this will create a new resource. Either the combination of cloud_exadata_infrastructure_id and odb_network_id or cloud_exadata_infrastructure_arn and odb_network_arn must be used. +* `odb_network_arn` - (Optional) The ARN of the ODB network for the VM cluster. Changing this will create a new resource. Either the combination of cloud_exadata_infrastructure_id and odb_network_id or cloud_exadata_infrastructure_arn and odb_network_arn must be used. +* `cloud_exadata_infrastructure_arn` - (Optional) The ARN of the Exadata infrastructure for this VM cluster. Changing this will create a new resource. Either the combination of cloud_exadata_infrastructure_id and odb_network_id or cloud_exadata_infrastructure_arn and odb_network_arn must be used. * `cluster_name` - (Optional) The name of the Grid Infrastructure (GI) cluster. Changing this will create a new resource. * `db_node_storage_size_in_gbs` - (Optional) The amount of local node storage, in gigabytes (GBs), to allocate for the VM cluster. Changing this will create a new resource. * `is_local_backup_enabled` - (Optional) Specifies whether to enable database backups to local Exadata storage for the VM cluster. Changing this will create a new resource. diff --git a/website/docs/r/opensearch_authorize_vpc_endpoint_access.html.markdown b/website/docs/r/opensearch_authorize_vpc_endpoint_access.html.markdown index 0141e58c7006..ab9735f00250 100644 --- a/website/docs/r/opensearch_authorize_vpc_endpoint_access.html.markdown +++ b/website/docs/r/opensearch_authorize_vpc_endpoint_access.html.markdown @@ -44,17 +44,17 @@ This resource exports the following attributes in addition to the arguments abov ## Import -In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import OpenSearch Authorize Vpc Endpoint Access using the `domain_name`. For example: +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import OpenSearch Authorize Vpc Endpoint Access using the `domain_name` and `account` separated by a comma (,). For example: ```terraform import { to = aws_opensearch_authorize_vpc_endpoint_access.example - id = "authorize_vpc_endpoint_access-id-12345678" + id = "authorize_vpc_endpoint_access-id-12345678,123456789012" } ``` -Using `terraform import`, import OpenSearch Authorize Vpc Endpoint Access using the `domain_name`. For example: +Using `terraform import`, import OpenSearch Authorize Vpc Endpoint Access using the `domain_name` and `account` separated by a comma (,). For example: ```console -% terraform import aws_opensearch_authorize_vpc_endpoint_access.example authorize_vpc_endpoint_access-id-12345678 +% terraform import aws_opensearch_authorize_vpc_endpoint_access.example authorize_vpc_endpoint_access-id-12345678,123456789012 ``` diff --git a/website/docs/r/opensearch_domain.html.markdown b/website/docs/r/opensearch_domain.html.markdown index cc2f51789a14..dfa225f73fdb 100644 --- a/website/docs/r/opensearch_domain.html.markdown +++ b/website/docs/r/opensearch_domain.html.markdown @@ -321,6 +321,7 @@ The following arguments are required: The following arguments are optional: * `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `aiml_options` - (Optional) Configuration block for parameters required to enable all machine learning features. Detailed below. * `access_policies` - (Optional) IAM policy document specifying the access policies for the domain. * `advanced_options` - (Optional) Key-value string pairs to specify advanced configuration options. Note that the values for these configuration options must be strings (wrapped in quotes) or they may be wrong and cause a perpetual diff, causing Terraform to want to recreate your OpenSearch domain on every apply. * `advanced_security_options` - (Optional) Configuration block for [fine-grained access control](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/fgac.html). Detailed below. @@ -332,6 +333,7 @@ The following arguments are optional: * `engine_version` - (Optional) Either `Elasticsearch_X.Y` or `OpenSearch_X.Y` to specify the engine version for the Amazon OpenSearch Service domain. For example, `OpenSearch_1.0` or `Elasticsearch_7.9`. See [Creating and managing Amazon OpenSearch Service domains](http://docs.aws.amazon.com/opensearch-service/latest/developerguide/createupdatedomains.html#createdomains). Defaults to the lastest version of OpenSearch. +* `identity_center_options` - (Optional) Configuration block for enabling and managing IAM Identity Center integration within a domain. Detailed below. * `ip_address_type` - (Optional) The IP address type for the endpoint. Valid values are `ipv4` and `dualstack`. * `encrypt_at_rest` - (Optional) Configuration block for encrypt at rest options. Only available for [certain instance types](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/encryption-at-rest.html). Detailed below. * `log_publishing_options` - (Optional) Configuration block for publishing slow and application logs to CloudWatch Logs. This block can be declared multiple times, for each log_type, within the same resource. Detailed below. @@ -355,6 +357,19 @@ The following arguments are optional: * `master_user_name` - (Optional) Main user's username, which is stored in the Amazon OpenSearch Service domain's internal database. Only specify if `internal_user_database_enabled` is set to `true`. * `master_user_password` - (Optional) Main user's password, which is stored in the Amazon OpenSearch Service domain's internal database. Only specify if `internal_user_database_enabled` is set to `true`. +### aiml_options + +* `natural_language_query_generation_options` - (Optional) Configuration block for parameters required for natural language query generation on the specified domain. +* `s3_vectors_engine` - (Optional) Configuration block for parameters required to enable S3 vectors engine features on the specified domain. + +#### natural_language_query_generation_options + +* `desired_state` - (Optional) The desired state of the natural language query generation feature. Valid values are `ENABLED` and `DISABLED`. + +#### s3_vectors_engine + +* `enabled` - (Optional) Enables S3 vectors engine features. + ### auto_tune_options * `desired_state` - (Required) Auto-Tune desired state for the domain. Valid values: `ENABLED` or `DISABLED`. @@ -437,6 +452,13 @@ AWS documentation: [Amazon Cognito Authentication for Dashboard](https://docs.aw * `volume_size` - (Required if `ebs_enabled` is set to `true`.) Size of EBS volumes attached to data nodes (in GiB). * `volume_type` - (Optional) Type of EBS volumes attached to data nodes. +### identity_center_options + +* enabled_api_access - (Optional) Boolean that indicates whether IAM Identity Center is enabled for API access. [Fine-grained access control](#enabling-fine-grained-access-control-on-an-existing-domain) must be enabled to use this feature. To disable it after enabling, set this argument to `false` or remove the `identity_center_options` block entirely. +* identity_center_instance_arn - (Optional) ARN of the IAM Identity Center instance to create an OpenSearch UI application that uses IAM Identity Center for authentication. Required if `enabled_api_access` is set to `true`. +* roles_key - (Optional) Attribute that contains the backend role identifier in IAM Identity Center. Valid values: `GroupName`, `GroupId`. Defaults to `GroupId`. +* subject_key - (Optional) Attribute that contains the subject identifier in IAM Identity Center. Valid values: `UserName`, `UserId`, `Email`. Defaults to `UserId`. + ### encrypt_at_rest ~> **Note:** You can enable `encrypt_at_rest` _in place_ for an existing, unencrypted domain only if you are using OpenSearch or your Elasticsearch version is 6.7 or greater. For other versions, if you enable `encrypt_at_rest`, Terraform with recreate the domain, potentially causing data loss. For any version, if you disable `encrypt_at_rest` for an existing, encrypted domain, Terraform will recreate the domain, potentially causing data loss. If you change the `kms_key_id`, Terraform will also recreate the domain, potentially causing data loss. diff --git a/website/docs/r/organizations_organization.html.markdown b/website/docs/r/organizations_organization.html.markdown index 50e2ac97b1c7..a0b531103fb7 100644 --- a/website/docs/r/organizations_organization.html.markdown +++ b/website/docs/r/organizations_organization.html.markdown @@ -32,7 +32,7 @@ resource "aws_organizations_organization" "org" { This resource supports the following arguments: * `aws_service_access_principals` - (Optional) List of AWS service principal names for which you want to enable integration with your organization. This is typically in the form of a URL, such as service-abbreviation.amazonaws.com. Organization must have `feature_set` set to `ALL`. Some services do not support enablement via this endpoint, see [warning in aws docs](https://docs.aws.amazon.com/organizations/latest/APIReference/API_EnableAWSServiceAccess.html). -* `enabled_policy_types` - (Optional) List of Organizations policy types to enable in the Organization Root. Organization must have `feature_set` set to `ALL`. For additional information about valid policy types (e.g., `AISERVICES_OPT_OUT_POLICY`, `BACKUP_POLICY`, `RESOURCE_CONTROL_POLICY`, `SERVICE_CONTROL_POLICY`, and `TAG_POLICY`), see the [AWS Organizations API Reference](https://docs.aws.amazon.com/organizations/latest/APIReference/API_EnablePolicyType.html). +* `enabled_policy_types` - (Optional) List of Organizations policy types to enable in the Organization Root. Organization must have `feature_set` set to `ALL`. For additional information about valid policy types (e.g., `AISERVICES_OPT_OUT_POLICY`, `BACKUP_POLICY`, `CHATBOT_POLICY`, `DECLARATIVE_POLICY_EC2`, `RESOURCE_CONTROL_POLICY`, `SECURITYHUB_POLICY`, `SERVICE_CONTROL_POLICY`, and `TAG_POLICY`), see the [AWS Organizations API Reference](https://docs.aws.amazon.com/organizations/latest/APIReference/API_EnablePolicyType.html). To enable `SECURITYHUB_POLICY`, `aws_service_access_principals` must include `securityhub.amazonaws.com`. * `feature_set` - (Optional) Specify `ALL` (default) or `CONSOLIDATED_BILLING`. ## Attribute Reference diff --git a/website/docs/r/organizations_policy.html.markdown b/website/docs/r/organizations_policy.html.markdown index 108cf3012949..0fe20674bce4 100644 --- a/website/docs/r/organizations_policy.html.markdown +++ b/website/docs/r/organizations_policy.html.markdown @@ -33,13 +33,17 @@ This resource supports the following arguments: * `content` - (Required) The policy content to add to the new policy. For example, if you create a [service control policy (SCP)](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scp.html), this string must be JSON text that specifies the permissions that admins in attached accounts can delegate to their users, groups, and roles. +For more information about the AI Services opt-out Policy syntax, see the [AI Services opt-out Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_ai-opt-out_syntax.html). +For more information about the Backup Policy syntax, see the [Backup Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_backup_syntax.html). +For more information about the Chatbot Policy syntax, see the [Chatbot Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_chatbot_syntax.html). +For more information about the Declarative Policy syntax, see the [Declarative Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_declarative_syntax.html). For more information about the RCP syntax, see the [Resource Control Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps_syntax.html). For more information about the SCP syntax, see the [Service Control Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_reference_scp-syntax.html). For more information on the Tag Policy syntax, see the [Tag Policy Syntax documentation](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_example-tag-policies.html). * `name` - (Required) The friendly name to assign to the policy. * `description` - (Optional) A description to assign to the policy. * `skip_destroy` - (Optional) If set to `true`, destroy will **not** delete the policy and instead just remove the resource from state. This can be useful in situations where the policies (and the associated attachment) must be preserved to meet the AWS minimum requirement of 1 attached policy. -* `type` - (Optional) The type of policy to create. Valid values are `AISERVICES_OPT_OUT_POLICY`, `BACKUP_POLICY`, `RESOURCE_CONTROL_POLICY` (RCP), `SERVICE_CONTROL_POLICY` (SCP), and `TAG_POLICY`. Defaults to `SERVICE_CONTROL_POLICY`. +* `type` - (Optional) The type of policy to create. Valid values are `AISERVICES_OPT_OUT_POLICY`, `BACKUP_POLICY`, `CHATBOT_POLICY`, `DECLARATIVE_POLICY_EC2`,`RESOURCE_CONTROL_POLICY` (RCP), `SERVICE_CONTROL_POLICY` (SCP), and `TAG_POLICY`. Defaults to `SERVICE_CONTROL_POLICY`. * `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ## Attribute Reference diff --git a/website/docs/r/pinpoint_email_template.markdown b/website/docs/r/pinpoint_email_template.html.markdown similarity index 100% rename from website/docs/r/pinpoint_email_template.markdown rename to website/docs/r/pinpoint_email_template.html.markdown diff --git a/website/docs/r/prometheus_query_logging_configuration.html.markdown b/website/docs/r/prometheus_query_logging_configuration.html.markdown index 4a82224e15a5..52eb40c6055f 100644 --- a/website/docs/r/prometheus_query_logging_configuration.html.markdown +++ b/website/docs/r/prometheus_query_logging_configuration.html.markdown @@ -54,7 +54,7 @@ The following arguments are optional: #### `cloudwatch_logs` -* `log_group_arn` - (Required) The ARN of the CloudWatch log group to which query logs will be sent. +* `log_group_arn` - (Required) The ARN of the CloudWatch log group to which query logs will be sent. The ARN must end with `:*` #### `filters` diff --git a/website/docs/r/prometheus_workspace.html.markdown b/website/docs/r/prometheus_workspace.html.markdown index 50ad28cde43c..1b37b486cf6b 100644 --- a/website/docs/r/prometheus_workspace.html.markdown +++ b/website/docs/r/prometheus_workspace.html.markdown @@ -64,7 +64,7 @@ This resource supports the following arguments: The `logging_configuration` block supports the following arguments: -* `log_group_arn` - (Required) The ARN of the CloudWatch log group to which the vended log data will be published. This log group must exist. +* `log_group_arn` - (Required) The ARN of the CloudWatch log group to which the vended log data will be published. This log group must exist. The ARN must end with `:*` ## Attribute Reference diff --git a/website/docs/r/quicksight_account_settings.html.markdown b/website/docs/r/quicksight_account_settings.html.markdown index 0fd7fcdea3f0..96de0fc9000b 100644 --- a/website/docs/r/quicksight_account_settings.html.markdown +++ b/website/docs/r/quicksight_account_settings.html.markdown @@ -35,6 +35,7 @@ This resource supports the following arguments: * `aws_account_id` - (Optional, Forces new resource) AWS account ID. Defaults to automatically determined account ID of the Terraform AWS provider. * `default_namespace` - (Optional) The default namespace for this Amazon Web Services account. Currently, the default is `default`. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `termination_protection_enabled` - (Optional) A boolean value that determines whether or not an Amazon QuickSight account can be deleted. If `true`, it does not allow the account to be deleted and results in an error message if a user tries to make a DeleteAccountSubscription request. If `false`, it will allow the account to be deleted. ## Attribute Reference diff --git a/website/docs/r/rds_custom_db_engine_version.markdown b/website/docs/r/rds_custom_db_engine_version.html.markdown similarity index 100% rename from website/docs/r/rds_custom_db_engine_version.markdown rename to website/docs/r/rds_custom_db_engine_version.html.markdown diff --git a/website/docs/r/s3_bucket_server_side_encryption_configuration.html.markdown b/website/docs/r/s3_bucket_server_side_encryption_configuration.html.markdown index d64617fd4943..d2503a682dd1 100644 --- a/website/docs/r/s3_bucket_server_side_encryption_configuration.html.markdown +++ b/website/docs/r/s3_bucket_server_side_encryption_configuration.html.markdown @@ -36,6 +36,32 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "example" { } ``` +### Blocking SSE-C Uploads + +```terraform +resource "aws_kms_key" "mykey" { + description = "This key is used to encrypt bucket objects" + deletion_window_in_days = 10 +} + +resource "aws_s3_bucket" "mybucket" { + bucket = "mybucket" +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "example" { + bucket = aws_s3_bucket.mybucket.id + + rule { + apply_server_side_encryption_by_default { + kms_master_key_id = aws_kms_key.mykey.arn + sse_algorithm = "aws:kms" + } + bucket_key_enabled = true + blocked_encryption_types = ["SSE-C"] + } +} +``` + ## Argument Reference This resource supports the following arguments: @@ -50,6 +76,7 @@ This resource supports the following arguments: The `rule` configuration block supports the following arguments: * `apply_server_side_encryption_by_default` - (Optional) Single object for setting server-side encryption by default. [See below](#apply_server_side_encryption_by_default). +* `blocked_encryption_types` - (Optional) List of server-side encryption types to block for object uploads. Valid values are `SSE-C` (blocks uploads using server-side encryption with customer-provided keys) and `NONE` (unblocks all encryption types). Starting in March 2026, Amazon S3 will automatically block SSE-C uploads for all new buckets. * `bucket_key_enabled` - (Optional) Whether or not to use [Amazon S3 Bucket Keys](https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html) for SSE-KMS. ### apply_server_side_encryption_by_default diff --git a/website/docs/r/s3tables_table.html.markdown b/website/docs/r/s3tables_table.html.markdown index 805a9b0f824c..93e86e1c899a 100644 --- a/website/docs/r/s3tables_table.html.markdown +++ b/website/docs/r/s3tables_table.html.markdown @@ -96,13 +96,14 @@ The following arguments are required: The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `encryption_configuration` - (Optional) A single table bucket encryption configuration object. [See `encryption_configuration` below](#encryption_configuration). * `maintenance_configuration` - (Optional) A single table bucket maintenance configuration object. [See `maintenance_configuration` below](#maintenance_configuration). * `metadata` - (Optional) Contains details about the table metadata. This configuration specifies the metadata format and schema for the table. Currently only supports Iceberg format. [See `metadata` below](#metadata). +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### `encryption_configuration` @@ -194,6 +195,7 @@ This resource exports the following attributes in addition to the arguments abov * `modified_at` - Date and time when the namespace was last modified. * `modified_by` - Account ID of the account that last modified the namespace. * `owner_account_id` - Account ID of the account that owns the namespace. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). * `type` - Type of the table. One of `customer` or `aws`. * `version_token` - Identifier for the current version of table data. diff --git a/website/docs/r/s3tables_table_bucket.html.markdown b/website/docs/r/s3tables_table_bucket.html.markdown index e58a2b6aa233..c315a1097858 100644 --- a/website/docs/r/s3tables_table_bucket.html.markdown +++ b/website/docs/r/s3tables_table_bucket.html.markdown @@ -37,6 +37,7 @@ The following arguments are optional: * `maintenance_configuration` - (Optional) A single table bucket maintenance configuration object. [See `maintenance_configuration` below](#maintenance_configuration). * `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `tags` - (Optional) Key-value map of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### `encryption_configuration` @@ -77,6 +78,7 @@ This resource exports the following attributes in addition to the arguments abov * `arn` - ARN of the table bucket. * `created_at` - Date and time when the bucket was created. * `owner_account_id` - Account ID of the account that owns the table bucket. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Import diff --git a/website/docs/r/sagemaker_endpoint_configuration.html.markdown b/website/docs/r/sagemaker_endpoint_configuration.html.markdown index 973c75cd65bc..bcbef4105180 100644 --- a/website/docs/r/sagemaker_endpoint_configuration.html.markdown +++ b/website/docs/r/sagemaker_endpoint_configuration.html.markdown @@ -35,105 +35,103 @@ resource "aws_sagemaker_endpoint_configuration" "ec" { This resource supports the following arguments: +* `async_inference_config` - (Optional) How an endpoint performs asynchronous inference. +* `data_capture_config` - (Optional) Parameters to capture input/output of SageMaker AI models endpoints. Fields are documented below. +* `execution_role_arn` - (Optional) ARN of an IAM role that SageMaker AI can assume to perform actions on your behalf. Required when `model_name` is not specified in `production_variants` to support Inference Components. +* `kms_key_arn` - (Optional) ARN of a AWS KMS key that SageMaker AI uses to encrypt data on the storage volume attached to the ML compute instance that hosts the endpoint. +* `name_prefix` - (Optional) Unique endpoint configuration name beginning with the specified prefix. Conflicts with `name`. +* `name` - (Optional) Name of the endpoint configuration. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. +* `production_variants` - (Required) List each model that you want to host at this endpoint. [See below](#production_variants). * `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). -* `production_variants` - (Required) An list of ProductionVariant objects, one for each model that you want to host at this endpoint. Fields are documented below. -* `kms_key_arn` - (Optional) Amazon Resource Name (ARN) of a AWS Key Management Service key that Amazon SageMaker AI uses to encrypt data on the storage volume attached to the ML compute instance that hosts the endpoint. -* `name` - (Optional) The name of the endpoint configuration. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. -* `name_prefix` - (Optional) Creates a unique endpoint configuration name beginning with the specified prefix. Conflicts with `name`. -* `tags` - (Optional) A mapping of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. -* `data_capture_config` - (Optional) Specifies the parameters to capture input/output of SageMaker AI models endpoints. Fields are documented below. -* `async_inference_config` - (Optional) Specifies configuration for how an endpoint performs asynchronous inference. -* `shadow_production_variants` - (Optional) Array of ProductionVariant objects. There is one for each model that you want to host at this endpoint in shadow mode with production traffic replicated from the model specified on ProductionVariants. If you use this field, you can only specify one variant for ProductionVariants and one variant for ShadowProductionVariants. Fields are documented below. +* `shadow_production_variants` - (Optional) Models that you want to host at this endpoint in shadow mode with production traffic replicated from the model specified on `oroduction_variants`. If you use this field, you can only specify one variant for `production_variants` and one variant for `shadow_production_variants`. [See below](#production_variants) (same arguments as `production_variants`). +* `tags` - (Optional) Mapping of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### production_variants -* `accelerator_type` - (Optional) The size of the Elastic Inference (EI) instance to use for the production variant. -* `container_startup_health_check_timeout_in_seconds` - (Optional) The timeout value, in seconds, for your inference container to pass health check by SageMaker AI Hosting. For more information about health check, see [How Your Container Should Respond to Health Check (Ping) Requests](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms-inference-code.html#your-algorithms-inference-algo-ping-requests). Valid values between `60` and `3600`. -* `core_dump_config` - (Optional) Specifies configuration for a core dump from the model container when the process crashes. Fields are documented below. -* `enable_ssm_access` - (Optional) You can use this parameter to turn on native Amazon Web Services Systems Manager (SSM) access for a production variant behind an endpoint. By default, SSM access is disabled for all production variants behind an endpoints. -* `inference_ami_version` - (Optional) Specifies an option from a collection of preconfigured Amazon Machine Image (AMI) images. Each image is configured by Amazon Web Services with a set of software and driver versions. Amazon Web Services optimizes these configurations for different machine learning workloads. +* `accelerator_type` - (Optional) Size of the Elastic Inference (EI) instance to use for the production variant. +* `container_startup_health_check_timeout_in_seconds` - (Optional) Timeout value, in seconds, for your inference container to pass health check by SageMaker AI Hosting. For more information about health check, see [How Your Container Should Respond to Health Check (Ping) Requests](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms-inference-code.html#your-algorithms-inference-algo-ping-requests). Valid values between `60` and `3600`. +* `core_dump_config` - (Optional) Core dump configuration from the model container when the process crashes. Fields are documented below. +* `enable_ssm_access` - (Optional) Whether to turn on native AWS SSM access for a production variant behind an endpoint. By default, SSM access is disabled for all production variants behind endpoints. Ignored if `model_name` is not set (Inference Components endpoint). +* `inference_ami_version` - (Optional) Option from a collection of preconfigured AMI images. Each image is configured by AWS with a set of software and driver versions. AWS optimizes these configurations for different machine learning workloads. * `initial_instance_count` - (Optional) Initial number of instances used for auto-scaling. -* `instance_type` - (Optional) The type of instance to start. -* `initial_variant_weight` - (Optional) Determines initial traffic distribution among all of the models that you specify in the endpoint configuration. If unspecified, it defaults to `1.0`. -* `model_data_download_timeout_in_seconds` - (Optional) The timeout value, in seconds, to download and extract the model that you want to host from Amazon S3 to the individual inference instance associated with this production variant. Valid values between `60` and `3600`. -* `model_name` - (Required) The name of the model to use. -* `routing_config` - (Optional) Sets how the endpoint routes incoming traffic. See [routing_config](#routing_config) below. -* `serverless_config` - (Optional) Specifies configuration for how an endpoint performs asynchronous inference. -* `managed_instance_scaling` - (Optional) Settings that control the range in the number of instances that the endpoint provisions as it scales up or down to accommodate traffic. -* `variant_name` - (Optional) The name of the variant. If omitted, Terraform will assign a random, unique name. -* `volume_size_in_gb` - (Optional) The size, in GB, of the ML storage volume attached to individual inference instance associated with the production variant. Valid values between `1` and `512`. +* `initial_variant_weight` - (Optional) Initial traffic distribution among all of the models that you specify in the endpoint configuration. If unspecified, defaults to `1.0`. Ignored if `model_name` is not set (Inference Components endpoint). +* `instance_type` - (Optional) Type of instance to start. +* `managed_instance_scaling` - (Optional) Control the range in the number of instances that the endpoint provisions as it scales up or down to accommodate traffic. +* `model_data_download_timeout_in_seconds` - (Optional) Timeout value, in seconds, to download and extract the model that you want to host from S3 to the individual inference instance associated with this production variant. Valid values between `60` and `3600`. +* `model_name` - (Optional) Name of the model to use. Required unless using Inference Components (in which case `execution_role_arn` must be specified at the endpoint configuration level). +* `routing_config` - (Optional) How the endpoint routes incoming traffic. See [routing_config](#routing_config) below. +* `serverless_config` - (Optional) How an endpoint performs asynchronous inference. +* `variant_name` - (Optional) Name of the variant. If omitted, Terraform will assign a random, unique name. +* `volume_size_in_gb` - (Optional) Size, in GB, of the ML storage volume attached to individual inference instance associated with the production variant. Valid values between `1` and `512`. #### core_dump_config -* `destination_s3_uri` - (Required) The Amazon S3 bucket to send the core dump to. -* `kms_key_id` - (Required) The Amazon Web Services Key Management Service (Amazon Web Services KMS) key that SageMaker AI uses to encrypt the core dump data at rest using Amazon S3 server-side encryption. +* `destination_s3_uri` - (Required) S3 bucket to send the core dump to. +* `kms_key_id` - (Required) KMS key that SageMaker AI uses to encrypt the core dump data at rest using S3 server-side encryption. #### routing_config -* `routing_strategy` - (Required) Sets how the endpoint routes incoming traffic. Valid values are `LEAST_OUTSTANDING_REQUESTS` and `RANDOM`. `LEAST_OUTSTANDING_REQUESTS` routes requests to the specific instances that have more capacity to process them. `RANDOM` routes each request to a randomly chosen instance. +* `routing_strategy` - (Required) How the endpoint routes incoming traffic. Valid values are `LEAST_OUTSTANDING_REQUESTS` and `RANDOM`. `LEAST_OUTSTANDING_REQUESTS` routes requests to the specific instances that have more capacity to process them. `RANDOM` routes each request to a randomly chosen instance. #### serverless_config -* `max_concurrency` - (Required) The maximum number of concurrent invocations your serverless endpoint can process. Valid values are between `1` and `200`. -* `memory_size_in_mb` - (Required) The memory size of your serverless endpoint. Valid values are in 1 GB increments: `1024` MB, `2048` MB, `3072` MB, `4096` MB, `5120` MB, or `6144` MB. -* `provisioned_concurrency` - The amount of provisioned concurrency to allocate for the serverless endpoint. Should be less than or equal to `max_concurrency`. Valid values are between `1` and `200`. +* `max_concurrency` - (Required) Maximum number of concurrent invocations your serverless endpoint can process. Valid values are between `1` and `200`. +* `memory_size_in_mb` - (Required) Memory size of your serverless endpoint. Valid values are in 1 GB increments: `1024` MB, `2048` MB, `3072` MB, `4096` MB, `5120` MB, or `6144` MB. +* `provisioned_concurrency` - Amount of provisioned concurrency to allocate for the serverless endpoint. Should be less than or equal to `max_concurrency`. Valid values are between `1` and `200`. #### managed_instance_scaling -* `status` - (Optional) Indicates whether managed instance scaling is enabled. Valid values are `ENABLED` and `DISABLED`. -* `min_instance_count` - (Optional) The minimum number of instances that the endpoint must retain when it scales down to accommodate a decrease in traffic. -* `max_instance_count` - (Optional) The maximum number of instances that the endpoint can provision when it scales up to accommodate an increase in traffic. +* `max_instance_count` - (Optional) Maximum number of instances that the endpoint can provision when it scales up to accommodate an increase in traffic. +* `min_instance_count` - (Optional) Minimum number of instances that the endpoint must retain when it scales down to accommodate a decrease in traffic. +* `status` - (Optional) Whether managed instance scaling is enabled. Valid values are `ENABLED` and `DISABLED`. ### data_capture_config -* `initial_sampling_percentage` - (Required) Portion of data to capture. Should be between 0 and 100. -* `destination_s3_uri` - (Required) The URL for S3 location where the captured data is stored. -* `capture_options` - (Required) Specifies what data to capture. Fields are documented below. -* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of a AWS Key Management Service key that Amazon SageMaker AI uses to encrypt the captured data on Amazon S3. +* `capture_content_type_header` - (Optional) Content type headers to capture. See [`capture_content_type_header`](#capture_content_type_header) below. +* `capture_options` - (Required) What data to capture. Fields are documented below. +* `destination_s3_uri` - (Required) URL for S3 location where the captured data is stored. * `enable_capture` - (Optional) Flag to enable data capture. Defaults to `false`. -* `capture_content_type_header` - (Optional) The content type headers to capture. - See [`capture_content_type_header`](#capture_content_type_header) below. +* `initial_sampling_percentage` - (Required) Portion of data to capture. Should be between 0 and 100. +* `kms_key_id` - (Optional) ARN of a KMS key that SageMaker AI uses to encrypt the captured data on S3. #### capture_options -* `capture_mode` - (Required) Specifies the data to be captured. Should be one of `Input`, `Output` or `InputAndOutput`. +* `capture_mode` - (Required) Data to be captured. Should be one of `Input`, `Output` or `InputAndOutput`. #### capture_content_type_header -* `csv_content_types` - (Optional) The CSV content type headers to capture. - One of `csv_content_types` or `json_content_types` is required. -* `json_content_types` - (Optional) The JSON content type headers to capture. - One of `json_content_types` or `csv_content_types` is required. +* `csv_content_types` - (Optional) CSV content type headers to capture. One of `csv_content_types` or `json_content_types` is required. +* `json_content_types` - (Optional) The JSON content type headers to capture. One of `json_content_types` or `csv_content_types` is required. ### async_inference_config -* `output_config` - (Required) Specifies the configuration for asynchronous inference invocation outputs. -* `client_config` - (Optional) Configures the behavior of the client used by Amazon SageMaker AI to interact with the model container during asynchronous inference. +* `client_config` - (Optional) Configures the behavior of the client used by SageMaker AI to interact with the model container during asynchronous inference. +* `output_config` - (Required) Configuration for asynchronous inference invocation outputs. #### client_config -* `max_concurrent_invocations_per_instance` - (Optional) The maximum number of concurrent requests sent by the SageMaker AI client to the model container. If no value is provided, Amazon SageMaker AI will choose an optimal value for you. +* `max_concurrent_invocations_per_instance` - (Optional) Maximum number of concurrent requests sent by the SageMaker AI client to the model container. If no value is provided, SageMaker AI will choose an optimal value for you. #### output_config -* `s3_output_path` - (Required) The Amazon S3 location to upload inference responses to. -* `s3_failure_path` - (Optional) The Amazon S3 location to upload failure inference responses to. -* `kms_key_id` - (Optional) The Amazon Web Services Key Management Service (Amazon Web Services KMS) key that Amazon SageMaker AI uses to encrypt the asynchronous inference output in Amazon S3. -* `notification_config` - (Optional) Specifies the configuration for notifications of inference results for asynchronous inference. +* `s3_output_path` - (Required) S3 location to upload inference responses to. +* `s3_failure_path` - (Optional) S3 location to upload failure inference responses to. +* `kms_key_id` - (Optional) KMS key that SageMaker AI uses to encrypt the asynchronous inference output in S3. +* `notification_config` - (Optional) Configuration for notifications of inference results for asynchronous inference. ##### notification_config -* `include_inference_response_in` - (Optional) The Amazon SNS topics where you want the inference response to be included. Valid values are `SUCCESS_NOTIFICATION_TOPIC` and `ERROR_NOTIFICATION_TOPIC`. -* `error_topic` - (Optional) Amazon SNS topic to post a notification to when inference fails. If no topic is provided, no notification is sent on failure. -* `success_topic` - (Optional) Amazon SNS topic to post a notification to when inference completes successfully. If no topic is provided, no notification is sent on success. +* `error_topic` - (Optional) SNS topic to post a notification to when inference fails. If no topic is provided, no notification is sent on failure. +* `include_inference_response_in` - (Optional) SNS topics where you want the inference response to be included. Valid values are `SUCCESS_NOTIFICATION_TOPIC` and `ERROR_NOTIFICATION_TOPIC`. +* `success_topic` - (Optional) SNS topic to post a notification to when inference completes successfully. If no topic is provided, no notification is sent on success. ## Attribute Reference This resource exports the following attributes in addition to the arguments above: -* `arn` - The Amazon Resource Name (ARN) assigned by AWS to this endpoint configuration. -* `name` - The name of the endpoint configuration. -* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). +* `arn` - ARN assigned by AWS to this endpoint configuration. +* `name` - Name of the endpoint configuration. +* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Import diff --git a/website/docs/r/sagemaker_model.html.markdown b/website/docs/r/sagemaker_model.html.markdown index 02c3b9fb8063..63c346b320df 100644 --- a/website/docs/r/sagemaker_model.html.markdown +++ b/website/docs/r/sagemaker_model.html.markdown @@ -3,16 +3,16 @@ subcategory: "SageMaker AI" layout: "aws" page_title: "AWS: aws_sagemaker_model" description: |- - Provides a SageMaker AI model resource. + Manages an Amazon SageMaker AI Model. --- # Resource: aws_sagemaker_model -Provides a SageMaker AI model resource. +Manages an Amazon SageMaker AI Model. ## Example Usage -Basic usage: +### Basic Usage ```terraform resource "aws_sagemaker_model" "example" { @@ -48,28 +48,29 @@ data "aws_sagemaker_prebuilt_ecr_image" "test" { This resource supports the following arguments: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). -* `name` - (Optional) The name of the model (must be unique). If omitted, Terraform will assign a random, unique name. -* `primary_container` - (Optional) The primary docker image containing inference code that is used when the model is deployed for predictions. If not specified, the `container` argument is required. Fields are documented below. -* `execution_role_arn` - (Required) A role that SageMaker AI can assume to access model artifacts and docker images for deployment. -* `inference_execution_config` - (Optional) Specifies details of how containers in a multi-container endpoint are called. See [Inference Execution Config](#inference-execution-config). * `container` (Optional) - Specifies containers in the inference pipeline. If not specified, the `primary_container` argument is required. Fields are documented below. * `enable_network_isolation` (Optional) - Isolates the model container. No inbound or outbound network calls can be made to or from the model container. -* `vpc_config` (Optional) - Specifies the VPC that you want your model to connect to. This configuration is used in hosting services and in batch transform. See [VPC Config](#vpc-config). +* `execution_role_arn` - (Required) A role that SageMaker AI can assume to access model artifacts and docker images for deployment. +* `inference_execution_config` - (Optional) Specifies details of how containers in a multi-container endpoint are called. See [Inference Execution Config](#inference-execution-config). +* `name` - (Optional) Name of the model (must be unique). If omitted, Terraform will assign a random, unique name. +* `primary_container` - (Optional) Primary docker image containing inference code that is used when the model is deployed for predictions. If not specified, the `container` argument is required. Fields are documented below. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `vpc_config` (Optional) - Specifies the VPC that you want your model to connect to. This configuration is used in hosting services and in batch transform. See [VPC Config](#vpc-config). The `primary_container` and `container` block both support: -* `image` - (Optional) The registry path where the inference code image is stored in Amazon ECR. -* `mode` - (Optional) The container hosts value `SingleModel/MultiModel`. The default value is `SingleModel`. -* `model_data_url` - (Optional) The URL for the S3 location where model artifacts are stored. -* `model_package_name` - (Optional) The Amazon Resource Name (ARN) of the model package to use to create the model. -* `model_data_source` - (Optional) The location of model data to deploy. Use this for uncompressed model deployment. For information about how to deploy an uncompressed model, see [Deploying uncompressed models](https://docs.aws.amazon.com/sagemaker/latest/dg/large-model-inference-uncompressed.html) in the _AWS SageMaker AI Developer Guide_. -* `container_hostname` - (Optional) The DNS host name for the container. +* `additional_model_data_source` - (Optional) Additional data sources that are available to the model in addition to those specified in `model_data_source`. See [Additional Model Data Source](#additional-model-data-source). +* `container_hostname` - (Optional) DNS host name for the container. * `environment` - (Optional) Environment variables for the Docker container. - A list of key value pairs. +* `image` - (Optional) Registry path where the inference code image is stored in Amazon ECR. * `image_config` - (Optional) Specifies whether the model container is in Amazon ECR or a private Docker registry accessible from your Amazon Virtual Private Cloud (VPC). For more information see [Using a Private Docker Registry for Real-Time Inference Containers](https://docs.aws.amazon.com/sagemaker/latest/dg/your-algorithms-containers-inference-private.html). see [Image Config](#image-config). -* `inference_specification_name` - (Optional) The inference specification name in the model package version. +* `inference_specification_name` - (Optional) Inference specification name in the model package version. +* `mode` - (Optional) Container hosts value. Allowed values are: `SingleModel` and `MultiModel`. The default value is `SingleModel`. +* `model_data_source` - (Optional) Location of model data to deploy. Use this for uncompressed model deployment. For information about how to deploy an uncompressed model, see [Deploying uncompressed models](https://docs.aws.amazon.com/sagemaker/latest/dg/large-model-inference-uncompressed.html) in the _AWS SageMaker AI Developer Guide_. +* `model_data_url` - (Optional) URL for the S3 location where model artifacts are stored. +* `model_package_name` - (Optional) Amazon Resource Name (ARN) of the model package to use to create the model. + A list of key value pairs. * `multi_model_config` - (Optional) Specifies additional configuration for multi-model endpoints. see [Multi Model Config](#multi-model-config). ### Image Config @@ -79,30 +80,35 @@ The `primary_container` and `container` block both support: #### Repository Auth Config -* `repository_credentials_provider_arn` - (Required) The Amazon Resource Name (ARN) of an AWS Lambda function that provides credentials to authenticate to the private Docker registry where your model image is hosted. For information about how to create an AWS Lambda function, see [Create a Lambda function with the console](https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html) in the _AWS Lambda Developer Guide_. +* `repository_credentials_provider_arn` - (Required) Amazon Resource Name (ARN) of an AWS Lambda function that provides credentials to authenticate to the private Docker registry where your model image is hosted. For information about how to create an AWS Lambda function, see [Create a Lambda function with the console](https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html) in the _AWS Lambda Developer Guide_. ### Model Data Source -* `s3_data_source` - (Required) The S3 location of model data to deploy. +* `s3_data_source` - (Required) S3 location of model data to deploy. See [S3 Data Source](#s3-data-source). + +### Additional Model Data Source + +* `channel_name` - (required) Custom name for the additional model data source object. It will be stored in `/opt/ml/additional-model-data-sources//`. +* `s3_data_source` - (Required) S3 location of model data to deploy. See [S3 Data Source](#s3-data-source). #### S3 Data Source * `compression_type` - (Required) How the model data is prepared. Allowed values are: `None` and `Gzip`. -* `s3_data_type` - (Required) The type of model data to deploy. Allowed values are: `S3Object` and `S3Prefix`. +* `model_access_config` - (Optional) Specifies the access configuration file for the ML model. You can explicitly accept the model end-user license agreement (EULA) within the [`model_access_config` configuration block]. See [Model Access Config](#model-access-config). +* `s3_data_type` - (Required) Type of model data to deploy. Allowed values are: `S3Object` and `S3Prefix`. * `s3_uri` - (Required) The S3 path of model data to deploy. -* `model_access_config` - (Optional) Specifies the access configuration file for the ML model. You can explicitly accept the model end-user license agreement (EULA) within the [`model_access_config` configuration block]. see [Model Access Config](#model-access-config). ##### Model Access Config -* `accept_eula` - (Required) Specifies agreement to the model end-user license agreement (EULA). The AcceptEula value must be explicitly defined as `true` in order to accept the EULA that this model requires. You are responsible for reviewing and complying with any applicable license terms and making sure they are acceptable for your use case before downloading or using a model. +* `accept_eula` - (Required) Specifies agreement to the model end-user license agreement (EULA). The value must be set to `true` in order to accept the EULA that this model requires. You are responsible for reviewing and complying with any applicable license terms and making sure they are acceptable for your use case before downloading or using a model. ### Multi Model Config * `model_cache_setting` - (Optional) Whether to cache models for a multi-model endpoint. By default, multi-model endpoints cache models so that a model does not have to be loaded into memory each time it is invoked. Some use cases do not benefit from model caching. For example, if an endpoint hosts a large number of models that are each invoked infrequently, the endpoint might perform better if you disable model caching. To disable model caching, set the value of this parameter to `Disabled`. Allowed values are: `Enabled` and `Disabled`. -## Inference Execution Config +### Inference Execution Config -* `mode` - (Required) How containers in a multi-container are run. The following values are valid `Serial` and `Direct`. +* `mode` - (Required) How containers in a multi-container are run. Allowed values are: `Serial` and `Direct`. ### VPC Config @@ -113,8 +119,8 @@ The `primary_container` and `container` block both support: This resource exports the following attributes in addition to the arguments above: -* `name` - The name of the model. -* `arn` - The Amazon Resource Name (ARN) assigned by AWS to this model. +* `arn` - Amazon Resource Name (ARN) assigned by AWS to this model. +* `name` - Name of the model. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Import @@ -123,7 +129,7 @@ In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashico ```terraform import { - to = aws_sagemaker_model.test_model + to = aws_sagemaker_model.example id = "model-foo" } ``` @@ -131,5 +137,5 @@ import { Using `terraform import`, import models using the `name`. For example: ```console -% terraform import aws_sagemaker_model.test_model model-foo +% terraform import aws_sagemaker_model.example model-foo ``` diff --git a/website/docs/r/securityhub_configuration_policy_association.markdown b/website/docs/r/securityhub_configuration_policy_association.html.markdown similarity index 100% rename from website/docs/r/securityhub_configuration_policy_association.markdown rename to website/docs/r/securityhub_configuration_policy_association.html.markdown diff --git a/website/docs/r/ssoadmin_account_assignment.html.markdown b/website/docs/r/ssoadmin_account_assignment.html.markdown index bc3963baf5ce..f09856ac71cb 100644 --- a/website/docs/r/ssoadmin_account_assignment.html.markdown +++ b/website/docs/r/ssoadmin_account_assignment.html.markdown @@ -63,7 +63,7 @@ resource "aws_identitystore_group" "example" { description = "Admin Group" } -resource "aws_ssoadmin_account_assignment" "account_assignment" { +resource "aws_ssoadmin_account_assignment" "example" { instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0] permission_set_arn = aws_ssoadmin_permission_set.example.arn @@ -96,7 +96,7 @@ This resource supports the following arguments: * `principal_id` - (Required, Forces new resource) An identifier for an object in SSO, such as a user or group. PrincipalIds are GUIDs (For example, `f81d4fae-7dec-11d0-a765-00a0c91e6bf6`). * `principal_type` - (Required, Forces new resource) The entity type for which the assignment will be created. Valid values: `USER`, `GROUP`. * `target_id` - (Required, Forces new resource) An AWS account identifier, typically a 10-12 digit string. -* `target_type` - (Optional, Forces new resource) The entity type for which the assignment will be created. Valid values: `AWS_ACCOUNT`. +* `target_type` - (Required, Forces new resource) The entity type for which the assignment will be created. Valid values: `AWS_ACCOUNT`. ## Attribute Reference diff --git a/website/docs/r/timestreaminfluxdb_db_cluster.html.markdown b/website/docs/r/timestreaminfluxdb_db_cluster.html.markdown index e7bdb8e8678a..fd1d692f820c 100644 --- a/website/docs/r/timestreaminfluxdb_db_cluster.html.markdown +++ b/website/docs/r/timestreaminfluxdb_db_cluster.html.markdown @@ -188,32 +188,72 @@ resource "aws_timestreaminfluxdb_db_cluster" "example" { } ``` +### Usage with InfluxDB V3 + +For InfluxDB V3 clusters, you can create a cluster without providing `allocated_storage`, `bucket`, `organization`, `username`, `password`, or `deployment_type` by specifying a `db_parameter_group_identifier` such as `"InfluxDBV3Core"`. The following example shows how to create an InfluxDB V3 cluster: + +```terraform +resource "aws_timestreaminfluxdb_db_cluster" "example" { + name = "example-v3-cluster" + db_instance_type = "db.influx.large" + db_parameter_group_identifier = "InfluxDBV3Core" + vpc_subnet_ids = [aws_subnet.example_1.id, aws_subnet.example_2.id] + vpc_security_group_ids = [aws_security_group.example.id] +} +``` + +## Cluster Type Requirements + +### InfluxDB V2 Clusters (default) + +The following arguments are **required** for InfluxDB V2 clusters: + +* `allocated_storage` +* `bucket` +* `deployment_type` +* `organization` +* `password` +* `username` + +The `deployment_type` argument defaults to `"MULTI_NODE_READ_REPLICAS"` for InfluxDB V2 clusters when not specified. + +### InfluxDB V3 Clusters (when using V3 parameter groups) + +The following arguments are **forbidden** for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group): + +* `allocated_storage` +* `bucket` +* `deployment_type` +* `organization` +* `password` +* `username` + ## Argument Reference The following arguments are required: -* `allocated_storage` - (Required) Amount of storage in GiB (gibibytes). The minimum value is `20`, the maximum value is `16384`. The argument `db_storage_type` places restrictions on this argument's minimum value. The following is a list of `db_storage_type` values and the corresponding minimum value for `allocated_storage`: `"InfluxIOIncludedT1": `20`, `"InfluxIOIncludedT2" and `"InfluxIOIncludedT3": `400`. -* `bucket` - (Required) Name of the initial InfluxDB bucket. All InfluxDB data is stored in a bucket. A bucket combines the concept of a database and a retention period (the duration of time that each data point persists). A bucket belongs to an organization. Along with `organization`, `username`, and `password`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. * `db_instance_type` - (Required) Timestream for InfluxDB DB instance type to run InfluxDB on. Valid options are: `"db.influx.medium"`, `"db.influx.large"`, `"db.influx.xlarge"`, `"db.influx.2xlarge"`, `"db.influx.4xlarge"`, `"db.influx.8xlarge"`, `"db.influx.12xlarge"`, and `"db.influx.16xlarge"`. This argument is updatable. * `name` - (Required) Name that uniquely identifies the DB cluster when interacting with the Amazon Timestream for InfluxDB API and CLI commands. This name will also be a prefix included in the endpoint. Cluster names must be unique per customer and per region. The argument must start with a letter, cannot contain consecutive hyphens (`-`) and cannot end with a hyphen. -* `password` - (Required) Password of the initial admin user created in InfluxDB. This password will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. Along with `bucket`, `username`, and `organization`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. -* `organization` - (Required) Name of the initial organization for the initial admin user in InfluxDB. An InfluxDB organization is a workspace for a group of users. Along with `bucket`, `username`, and `password`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. -* `username` - (Required) Username of the initial admin user created in InfluxDB. Must start with a letter and can't end with a hyphen or contain two consecutive hyphens. This username will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. Along with `bucket`, `organization`, and `password`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. * `vpc_security_group_ids` - (Required) List of VPC security group IDs to associate with the cluster. * `vpc_subnet_ids` - (Required) List of VPC subnet IDs to associate with the cluster. Provide at least two VPC subnet IDs in different availability zones when deploying with a Multi-AZ standby. The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `allocated_storage` - (Optional) Amount of storage in GiB (gibibytes). The minimum value is `20`, the maximum value is `16384`. The argument `db_storage_type` places restrictions on this argument's minimum value. The following is a list of `db_storage_type` values and the corresponding minimum value for `allocated_storage`: `"InfluxIOIncludedT1": `20`, `"InfluxIOIncludedT2" and `"InfluxIOIncludedT3": `400`. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group). +* `bucket` - (Optional) Name of the initial InfluxDB bucket. All InfluxDB data is stored in a bucket. A bucket combines the concept of a database and a retention period (the duration of time that each data point persists). A bucket belongs to an organization. Along with `organization`, `username`, and `password`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group). * `db_parameter_group_identifier` - (Optional) ID of the DB parameter group assigned to your cluster. This argument is updatable. If added to an existing Timestream for InfluxDB cluster or given a new value, will cause an in-place update to the cluster. However, if a cluster already has a value for `db_parameter_group_identifier`, removing `db_parameter_group_identifier` will cause the cluster to be destroyed and recreated. * `db_storage_type` - (Default `"InfluxIOIncludedT1"`) Timestream for InfluxDB DB storage type to read and write InfluxDB data. You can choose between 3 different types of provisioned Influx IOPS included storage according to your workloads requirements: Influx IO Included 3000 IOPS, Influx IO Included 12000 IOPS, Influx IO Included 16000 IOPS. Valid options are: `"InfluxIOIncludedT1"`, `"InfluxIOIncludedT2"`, and `"InfluxIOIncludedT3"`. If you use `"InfluxIOIncludedT2" or "InfluxIOIncludedT3", the minimum value for `allocated_storage` is 400. -* `deployment_type` - (Default `"MULTI_NODE_READ_REPLICAS"`) Specifies the type of cluster to create. Valid options are: `"MULTI_NODE_READ_REPLICAS"`. +* `deployment_type` - (Default `"MULTI_NODE_READ_REPLICAS"` for InfluxDB V2 clusters) Specifies the type of cluster to create. Valid options are: `"MULTI_NODE_READ_REPLICAS"`. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group). * `failover_mode` - (Default `"AUTOMATIC"`) Specifies the behavior of failure recovery when the primary node of the cluster fails. Valid options are: `"AUTOMATIC"` and `"NO_FAILOVER"`. * `log_delivery_configuration` - (Optional) Configuration for sending InfluxDB engine logs to a specified S3 bucket. This argument is updatable. * `network_type` - (Optional) Specifies whether the network type of the Timestream for InfluxDB cluster is IPV4, which can communicate over IPv4 protocol only, or DUAL, which can communicate over both IPv4 and IPv6 protocols. +* `organization` - (Optional) Name of the initial organization for the initial admin user in InfluxDB. An InfluxDB organization is a workspace for a group of users. Along with `bucket`, `username`, and `password`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group). +* `password` - (Optional) Password of the initial admin user created in InfluxDB. This password will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. Along with `bucket`, `username`, and `organization`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group) as the AWS API rejects it. * `port` - (Default `8086`) The port on which the cluster accepts connections. Valid values: `1024`-`65535`. Cannot be `2375`-`2376`, `7788`-`7799`, `8090`, or `51678`-`51680`. This argument is updatable. * `publicly_accessible` - (Default `false`) Configures the DB cluster with a public IP to facilitate access. Other resources, such as a VPC, a subnet, an internet gateway, and a route table with routes, are also required to enabled public access, in addition to this argument. See "[Usage with Public Internet Access Enabled](#usage-with-public-internet-access-enabled)" for an example configuration with all required resources for public internet access. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `tags` - (Optional) Map of tags assigned to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `username` - (Optional) Username of the initial admin user created in InfluxDB. Must start with a letter and can't end with a hyphen or contain two consecutive hyphens. This username will allow you to access the InfluxDB UI to perform various administrative tasks and also use the InfluxDB CLI to create an operator token. Along with `bucket`, `organization`, and `password`, this argument will be stored in the secret referred to by the `influx_auth_parameters_secret_arn` attribute. This field is forbidden for InfluxDB V3 clusters (when using an InfluxDB V3 db parameter group). ### Nested Fields @@ -233,9 +273,10 @@ The following arguments are optional: This resource exports the following attributes in addition to the arguments above: * `arn` - ARN of the Timestream for InfluxDB cluster. +* `engine_type` - Database engine type of the DB cluster. * `endpoint` - Endpoint used to connect to InfluxDB. The default InfluxDB port is 8086. * `id` - ID of the Timestream for InfluxDB cluster. -* `influx_auth_parameters_secret_arn` - ARN of the AWS Secrets Manager secret containing the initial InfluxDB authorization parameters. The secret value is a JSON formatted key-value pair holding InfluxDB authorization values: organization, bucket, username, and password. +* `influx_auth_parameters_secret_arn` - ARN of the AWS Secrets Manager secret containing the initial InfluxDB authorization parameters. For InfluxDB V2 clusters, the secret value is a JSON formatted key-value pair holding InfluxDB authorization values: organization, bucket, username, and password. For InfluxDB V3 clusters, the secret contains the InfluxDB admin token. * `reader_endpoint` - The endpoint used to connect to the Timestream for InfluxDB cluster for read-only operations. * `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). diff --git a/website/docs/r/vpclattice_domain_verification.html.markdown b/website/docs/r/vpclattice_domain_verification.html.markdown new file mode 100644 index 000000000000..7d7fc373f868 --- /dev/null +++ b/website/docs/r/vpclattice_domain_verification.html.markdown @@ -0,0 +1,86 @@ +--- +subcategory: "VPC Lattice" +layout: "aws" +page_title: "AWS: aws_vpclattice_domain_verification" +description: |- + Terraform resource for managing an AWS VPC Lattice Domain Verification. +--- + +# Resource: aws_vpclattice_domain_verification + +Terraform resource for managing an AWS VPC Lattice Domain Verification. + +Starts the domain verification process for a custom domain name. Use this resource to verify ownership of a domain before associating it with VPC Lattice resources. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_vpclattice_domain_verification" "example" { + domain_name = "example.com" +} + +# Create DNS TXT record for domain verification +resource "aws_route53_record" "example" { + zone_id = aws_route53_zone.example.zone_id + name = aws_vpclattice_domain_verification.example.txt_record_name + type = "TXT" + ttl = 300 + records = [aws_vpclattice_domain_verification.example.txt_record_value] +} +``` + +### With Tags + +```terraform +resource "aws_vpclattice_domain_verification" "example" { + domain_name = "example.com" + + tags = { + Environment = "production" + Purpose = "domain-verification" + } +} +``` + +## Argument Reference + +The following arguments are required: + +* `domain_name` - (Required) The domain name to verify ownership for. + +The following arguments are optional: + +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `tags` - (Optional) Key-value mapping of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `arn` - The Amazon Resource Name (ARN) of the domain verification. +* `created_at` - The date and time that the domain verification was created, in ISO-8601 format. +* `id` - The ID of the domain verification. +* `last_verified_time` - The date and time that the domain was last successfully verified, in ISO-8601 format. +* `status` - The current status of the domain verification process. Valid values: `VERIFIED`, `PENDING`, `VERIFICATION_TIMED_OUT`. +* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). +* `txt_record_name` - The name of the TXT record that must be created for domain verification. +* `txt_record_value` - The value that must be added to the TXT record for domain verification. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import VPC Lattice Domain Verification using the `id`. For example: + +```terraform +import { + to = aws_vpclattice_domain_verification.example + id = "dv-0a1b2c3d4e5f" +} +``` + +Using `terraform import`, import VPC Lattice Domain Verification using the `id`. For example: + +```console +% terraform import aws_vpclattice_domain_verification.example dv-0a1b2c3d4e5f +``` diff --git a/website/docs/r/vpclattice_resource_configuration.html.markdown b/website/docs/r/vpclattice_resource_configuration.html.markdown index b200b72446a7..0769c7052f43 100644 --- a/website/docs/r/vpclattice_resource_configuration.html.markdown +++ b/website/docs/r/vpclattice_resource_configuration.html.markdown @@ -58,6 +58,36 @@ resource "aws_vpclattice_resource_configuration" "example" { } ``` +### With custom domain + +```terraform +resource "aws_vpclattice_domain_verification" "example" { + domain_name = "example.com" +} + +resource "aws_vpclattice_resource_configuration" "example" { + name = "Example" + + resource_gateway_identifier = aws_vpclattice_resource_gateway.example.id + custom_domain_name = "custom.example.com" + domain_verification_id = aws_vpclattice_domain_verification.example.id + + port_ranges = ["443"] + protocol = "TCP" + + resource_configuration_definition { + dns_resource { + domain_name = "test.example.com" + ip_address_type = "IPV4" + } + } + + tags = { + Environment = "Example" + } +} +``` + ### ARN Example ```terraform @@ -88,6 +118,8 @@ The following arguments are optional: * `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `allow_association_to_shareable_service_network` (Optional) Allow or Deny the association of this resource to a shareable service network. +* `custom_domain_name` - (Optional) Custom domain name for your resource configuration. Additionally, provide a `domain_verification_id` to prove your ownership of a domain. +* `domain_verification_id` - (Optional) The domain verification ID of your verified custom domain name. If you don't provide an ID, you must configure the DNS settings yourself. * `protocol` - (Optional) Protocol for the Resource `TCP` is currently the only supported value. MUST be specified if `resource_configuration_group_id` is not. * `resource_configuration_group_id` (Optional) ID of Resource Configuration where `type` is `CHILD`. * `resource_gateway_identifier` - (Optional) ID of the Resource Gateway used to access the resource. MUST be specified if `resource_configuration_group_id` is not. @@ -129,6 +161,8 @@ The following arguments are required: This resource exports the following attributes in addition to the arguments above: * `arn` - ARN of the resource gateway. +* `domain_verification_arn` - ARN of the domain verification. +* `domain_verification_status` - Domain verification status. * `id` - ID of the resource gateway. * `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). diff --git a/website/docs/r/vpn_connection.html.markdown b/website/docs/r/vpn_connection.html.markdown index 0421cca674af..71a85c3e6d37 100644 --- a/website/docs/r/vpn_connection.html.markdown +++ b/website/docs/r/vpn_connection.html.markdown @@ -138,6 +138,7 @@ This resource supports the following arguments: * `remote_ipv4_network_cidr` - (Optional, Default `0.0.0.0/0`) The IPv4 CIDR on the AWS side of the VPN connection. * `remote_ipv6_network_cidr` - (Optional, Default `::/0`) The IPv6 CIDR on the AWS side of the VPN connection. * `transport_transit_gateway_attachment_id` - (Required when outside_ip_address_type is set to `PrivateIpv4`). The attachment ID of the Transit Gateway attachment to Direct Connect Gateway. The ID is obtained through a data source only. +* `tunnel_bandwidth` - (Optional, Default `standard`) Desired bandwidth specification for the VPN tunnel. Valid values are `standard | large`. `standard` supports up to 1.25 Gbps per tunnel, while `large` supports up to 5 Gbps per tunnel. Not supported when `vpn_gateway_id` is specified, or `enable_acceleration` is `true`. * `tunnel_inside_ip_version` - (Optional, Default `ipv4`) Indicate whether the VPN tunnels process IPv4 or IPv6 traffic. Valid values are `ipv4 | ipv6`. `ipv6` Supports only EC2 Transit Gateway. * `tunnel1_inside_cidr` - (Optional) The CIDR block of the inside IP addresses for the first VPN tunnel. Valid value is a size /30 CIDR block from the 169.254.0.0/16 range. * `tunnel2_inside_cidr` - (Optional) The CIDR block of the inside IP addresses for the second VPN tunnel. Valid value is a size /30 CIDR block from the 169.254.0.0/16 range. diff --git a/website/ignore-enhanced-region-check-resources.txt b/website/ignore-enhanced-region-check-resources.txt index b008f3248b72..5901c21de429 100644 --- a/website/ignore-enhanced-region-check-resources.txt +++ b/website/ignore-enhanced-region-check-resources.txt @@ -5,7 +5,6 @@ aws_cloudtrail_organization_delegated_admin_account aws_config_aggregate_authorization aws_dx_gateway aws_dx_hosted_connection -aws_ec2_image_block_public_access aws_vpc_ipam_organization_admin_account aws_fms_admin_account aws_ram_sharing_with_organization @@ -16,7 +15,6 @@ aws_ssmincidents_replication_set aws_default_subnet aws_default_vpc aws_default_vpc_dhcp_options -aws_quicksight_account_settings aws_lb_target_group aws_spot_fleet_request -aws_transfer_server \ No newline at end of file +aws_transfer_server