From 1a856ff661a61e4782e1f8816b135807533e786b Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Thu, 18 Aug 2022 14:16:10 -0400 Subject: [PATCH 01/28] drs rep config --- .../drs_replication_configuration_template.go | 299 ++++++++++++++++++ internal/service/drs/find.go | 38 +++ 2 files changed, 337 insertions(+) create mode 100644 internal/service/drs/drs_replication_configuration_template.go create mode 100644 internal/service/drs/find.go diff --git a/internal/service/drs/drs_replication_configuration_template.go b/internal/service/drs/drs_replication_configuration_template.go new file mode 100644 index 000000000000..3b9dd780580a --- /dev/null +++ b/internal/service/drs/drs_replication_configuration_template.go @@ -0,0 +1,299 @@ +package drs + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go/service/drs" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "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" +) + +func ResourceReplicationConfigurationTemplate() *schema.Resource { + return &schema.Resource{ + Create: resourceReplicationConfigurationTemplateCreate, + Read: resourceReplicationConfigurationTemplateRead, + Update: resourceReplicationConfigurationTemplateUpdate, + Delete: resourceReplicationConfigurationTemplateDelete, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "associate_default_security_group": { + Type: schema.TypeBool, + Required: true, + }, + "bandwidth_throttling": { + Type: schema.TypeInt, + Required: true, + }, + "create_public_ip": { + Type: schema.TypeBool, + Required: true, + }, + "data_plane_routing": { + Type: schema.TypeString, + Required: true, + }, + "default_large_staging_disk_type": { + Type: schema.TypeString, + Required: true, + }, + "ebs_encryption": { + Type: schema.TypeString, + Required: true, + }, + "ebs_encryption_key_arn": { + Type: schema.TypeString, + Required: true, + }, + "pit_policy": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: schema.TypeBool, + Optional: true, + }, + "interval": { + Type: schema.TypeInt, + Optional: true, + }, + "retention_duration": { + Type: schema.TypeInt, + Required: true, + }, + "rule_id": { + Type: schema.TypeInt, + Optional: true, + }, + "units": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "replication_server_instance_type": { + Type: schema.TypeString, + Required: true, + }, + "replication_servers_security_groups_ids": { + Type: schema.TypeList, + Required: true, + }, + "staging_area_subnet_id": { + Type: schema.TypeString, + Required: true, + }, + "staging_area_tags": tftags.TagsSchema(), + "tags": tftags.TagsSchema(), + "use_dedicated_replication_server": { + Type: schema.TypeBool, + Required: true, + }, + }, + } +} + +func resourceReplicationConfigurationTemplateCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSConn + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + staging_tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("staging_area_tags").(map[string]interface{}))) + tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) + + input := &drs.CreateReplicationConfigurationTemplateInput{ + AssociateDefaultSecurityGroup: aws.Bool(d.Get("associate_default_security_group").(bool)), + BandwidthThrottling: aws.Int64(d.Get("bandwidth_throttling").(int64)), + CreatePublicIP: aws.Bool(d.Get("create_public_ip").(bool)), + DataPlaneRouting: aws.String(d.Get("data_plane_routing").(string)), + DefaultLargeStagingDiskType: aws.String(d.Get("default_large_staging_disk_type").(string)), + EbsEncryption: aws.String(d.Get("ebs_encryption").(string)), + EbsEncryptionKeyArn: aws.String(d.Get("ebs_encryption_key_arn").(string)), + PitPolicy: expandPitPolicy(d.Get("pit_policy").(*schema.Set).List()), + ReplicationServerInstanceType: aws.String(d.Get("replication_server_instance_type").(string)), + ReplicationServersSecurityGroupsIDs: flex.ExpandStringList(d.Get("replication_servers_security_groups_ids").([]interface{})), + StagingAreaSubnetId: aws.String(d.Get("staging_area_subnet_id").(string)), + StagingAreaTags: Tags(tags.IgnoreAWS()), + Tags: Tags(staging_tags.IgnoreAWS()), + UseDedicatedReplicationServer: aws.Bool(d.Get("use_dedicated_replication_server").(bool)), + } + + log.Printf("[DEBUG] Creating DRS Replication Configuration Template: %s", input) + output, err := conn.CreateReplicationConfigurationTemplate(input) + + if err != nil { + return fmt.Errorf("error creating DRS Replication Configuration Template: %w", err) + } + + d.SetId(aws.ToString(output.ReplicationConfigurationTemplateID)) + + return resourceReplicationConfigurationTemplateRead(d, meta) +} + +func resourceReplicationConfigurationTemplateRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSConn + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + replicationConfigurationTemplate, err := FindReplicationConfigurationTemplateByID(conn, d.Id()) + + if tfresource.NotFound(err) && !d.IsNewResource() { + log.Printf("[WARN] Replication Configuration Template (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading Replication Configuration Template (%s): %w", d.Id(), err) + } + + d.Set("arn", replicationConfigurationTemplate.Arn) + d.Set("associate_default_security_group", replicationConfigurationTemplate.AssociateDefaultSecurityGroup) + d.Set("bandwidth_throttling", replicationConfigurationTemplate.BandwidthThrottling) + d.Set("create_public_ip", replicationConfigurationTemplate.CreatePublicIP) + d.Set("data_plane_routing", replicationConfigurationTemplate.DataPlaneRouting) + d.Set("default_large_staging_disk_type", replicationConfigurationTemplate.DefaultLargeStagingDiskType) + d.Set("ebs_encryption", replicationConfigurationTemplate.EbsEncryption) + d.Set("ebs_encryption_key_arn", replicationConfigurationTemplate.EbsEncryptionKeyArn) + d.Set("pit_policy", replicationConfigurationTemplate.PitPolicy) + d.Set("replication_server_instance_type", replicationConfigurationTemplate.ReplicationServerInstanceType) + d.Set("replication_servers_security_groups_ids", replicationConfigurationTemplate.ReplicationServersSecurityGroupsIDs) + d.Set("staging_area_subnet_id", replicationConfigurationTemplate.StagingAreaSubnetId) + d.Set("use_dedicated_replication_server", replicationConfigurationTemplate.UseDedicatedReplicationServer) + + tags := KeyValueTags(replicationConfigurationTemplate.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + if err := d.Set("staging_area_tags", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + + return nil +} + +func resourceReplicationConfigurationTemplateUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSConn + + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + staging_tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("staging_area_tags").(map[string]interface{}))) + + input := &drs.UpdateReplicationConfigurationTemplateInput{ + ReplicationConfigurationTemplateID: aws.String(d.Id()), + } + + if d.HasChange("associate_default_security_group") { + input.AssociateDefaultSecurityGroup = aws.Bool(d.Get("associate_default_security_group").(bool)) + } + + if d.HasChange("bandwidth_throttling") { + input.BandwidthThrottling = aws.Int64(d.Get("bandwidth_throttling").(int64)) + } + + if d.HasChange("create_public_ip") { + input.CreatePublicIP = aws.Bool(d.Get("create_public_ip").(bool)) + } + + if d.HasChange("data_plane_routing") { + input.DataPlaneRouting = aws.String(d.Get("data_plane_routing").(string)) + } + + if d.HasChange("default_large_staging_disk_type") { + input.DefaultLargeStagingDiskType = aws.String(d.Get("default_large_staging_disk_type").(string)) + } + + if d.HasChange("ebs_encryption") { + input.EbsEncryption = aws.String(d.Get("ebs_encryption").(string)) + } + + if d.HasChange("ebs_encryption_key_arn") { + input.EbsEncryptionKeyArn = aws.String(d.Get("ebs_encryption_key_arn").(string)) + } + + if d.HasChange("pit_policy") { + input.PitPolicy = expandPitPolicy(d.Get("pit_policy").(*schema.Set).List()) + } + + if d.HasChange("replication_server_instance_type") { + input.ReplicationServerInstanceType = aws.String(d.Get("replication_server_instance_type").(string)) + } + + if d.HasChange("replication_servers_security_groups_ids") { + input.ReplicationServersSecurityGroupsIDs = flex.ExpandStringList(d.Get("replication_servers_security_groups_ids").([]interface{})) + } + + if d.HasChange("staging_area_subnet_id") { + input.StagingAreaSubnetId = aws.String(d.Get("staging_area_subnet_id").(string)) + } + + if d.HasChange("staging_area_tags") { + input.StagingAreaTags = Tags(staging_tags.IgnoreAWS()) + } + + if d.HasChange("use_dedicated_replication_server") { + input.UseDedicatedReplicationServer = aws.Bool(d.Get("use_dedicated_replication_server").(bool)) + } + + _, err := conn.UpdateReplicationConfigurationTemplate(input) + + if err != nil { + return fmt.Errorf("error updating replication configuration template (%s): : %w", d.Id(), err) + } + + return resourceReplicationConfigurationTemplateRead(d, meta) + +} + +func resourceReplicationConfigurationTemplateDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSConn + + log.Printf("[DEBUG] Deleting Replication Configuration Template: %s", d.Id()) + _, err := conn.DeleteReplicationConfigurationTemplate(&drs.DeleteReplicationConfigurationTemplateInput{ + ReplicationConfigurationTemplateID: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, drs.ErrCodeResourceNotFoundException) { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting Replication Configuration Tempalte (%s): %w", d.Id(), err) + } + + return nil +} + +func expandPitPolicy(p []interface{}) []*drs.PITPolicyRule { + pitPolicyRules := make([]*drs.PITPolicyRule, len(p)) + for i, pitPolicy := range p { + pitPol := pitPolicy.(map[string]interface{}) + pitPolicyRules[i] = &drs.PITPolicyRule{ + Enabled: aws.Bool(pitPol["enabled"].(bool)), + Interval: aws.Int64(pitPol["interval"].(int64)), + RetentionDuration: aws.Int64(pitPol["retention_duration"].(int64)), + RuleID: aws.Int64(pitPol["rule_id"].(int64)), + Units: aws.String(pitPol["units"].(string)), + } + } + return pitPolicyRules +} + +func Tags(tags tftags.KeyValueTags) map[string]*string { + return aws.StringMap(tags.Map()) +} + +func KeyValueTags(tags map[string]*string) tftags.KeyValueTags { + return tftags.New(tags) +} diff --git a/internal/service/drs/find.go b/internal/service/drs/find.go new file mode 100644 index 000000000000..1f0eceb0b300 --- /dev/null +++ b/internal/service/drs/find.go @@ -0,0 +1,38 @@ +package drs + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/drs" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +func FindReplicationConfigurationTemplateByID(conn *drs.Drs, id string) (*drs.ReplicationConfigurationTemplate, error) { + //make string list from id + templateIdList := []*string{} + templateIdList = append(templateIdList, aws.String(id)) + + input := &drs.DescribeReplicationConfigurationTemplatesInput{ + ReplicationConfigurationTemplateIDs: templateIdList, + } + + output, err := conn.DescribeReplicationConfigurationTemplates(input) + + if tfawserr.ErrCodeEquals(err, drs.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Items == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.Items[0], nil +} From 93ac38f9e49ce08fb32081283ff9dc248a4bab1a Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Fri, 19 Aug 2022 12:40:30 -0400 Subject: [PATCH 02/28] adding doc --- ...ation_configuration_template.html.markdown | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 website/docs/r/drs_replication_configuration_template.html.markdown diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown new file mode 100644 index 000000000000..e9e2cf501c25 --- /dev/null +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -0,0 +1,84 @@ +--- +subcategory: "Elastic Disaster Recovery" +layout: "aws" +page_title: "AWS: drs_replication_configuration_template" +description: |- + Provides an Elastic Disaster Recovery replication configuration template resource. +--- + +# Resource: aws_drs_replication_configuration_template + +Provides an Elastic Disaster Recovery replication configuration template resource. + +## Example Usage + +### Basic configuration + +```terraform +resource "aws_drs_replication_configuration_template" "example" { + associate_default_security_group = True|False + bandwidth_throttling = 123 + create_public_ip = True|False + data_plane_routing = 'PRIVATE_IP'|'PUBLIC_IP' + default_large_staging_disk_type = 'GP2'|'GP3|'ST1|'AUTO + ebs_ecryption = 'DEFAULT'|'CUSTOM' + ebs_encryption_key_arn = 'string' + pit_policy = [{'enabled': True|False, 'interval':123}] + replication_server_instance_type = 'string' + replication_servers_security_groups_ids = ['string'] + staging_area_subnet_id = 'string + staging_area_tags = {'string': 'string'} + tags = {'string': 'string'} + use_dedicated_replication_server = True|False +} +``` + +## Argument Reference + +The following arguments are required: + +* `associate_default_security_group` - (Required)(boolean) Whether to associate the default Elastic Disaster Recovery Security group with the Replication Configuration Template. +* `bandwidth_throttling` - (Required)(integer) Configure bandwidth throttling for the outbound data transfer rate of the Source Server in Mbps. +* `create_public_ip` (Required)(boolean) Whether to create a Public IP for the Recovery Instance by default. +* `data_plane_routing` (Required)(string) The data plane routing mechanism that will be used for replication. +* `default_large_staging_disk_type` (Required)(string) The Staging Disk EBS volume type to be used during replication. +* `ebs_encryption` (Required)(string) The type of EBS encryption to be used during replication. +* `ebs_encryption_key_arn` (Required)(string) The ARN of the EBS encryption key to be used during replication. +* `pit_policy`(Required)(list) The Point in time (PIT) policy to manage snapshots taken during replication. + (dict) -- + A rule in the Point in Time (PIT) policy representing when to take snapshots and how long to retain them for. + + enabled (boolean) -- + + Whether this rule is enabled or not. + interval (integer) -- [REQUIRED] + + How often, in the chosen units, a snapshot should be taken. + retentionDuration (integer) -- [REQUIRED] + + The duration to retain a snapshot for, in the chosen units. + ruleID (integer) -- + + The ID of the rule. + units (string) -- [REQUIRED] + + The units used to measure the interval and retentionDuration. +* `replication_server_instance_type` (Required)(string) The instance type to be used for the replication server. +* `replication_servers_security_groups_ids` (Required)(list) The security group IDs that will be used by the replication server. +* `staging_area_subnet_id` (Required)(string) The subnet to be used by the replication staging area. +* `staging_area_tags` (Required)(dict) A set of tags to be associated with all resources created in the replication staging area: EC2 replication server, EBS volumes, EBS snapshots, etc. +* `use_dedicated_replication_server` (Required)(boolean) Whether to use a dedicated Replication Server in the replication staging area. + +The following arguments are optional: + +* `tags` (Optional)(dict) A set of tags to be associated with the Replication Configuration Template resource. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Replication Configuration Template ARN. +* `replication_configuration_template_id` - The Replication Configuration Template ID. + + + From 0c6816cc93b13018c8fbce95719e9403dfe095a5 Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 14:51:46 -0400 Subject: [PATCH 03/28] adding schema elem --- .../service/drs/drs_replication_configuration_template.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/service/drs/drs_replication_configuration_template.go b/internal/service/drs/drs_replication_configuration_template.go index 3b9dd780580a..4c7233cd58d9 100644 --- a/internal/service/drs/drs_replication_configuration_template.go +++ b/internal/service/drs/drs_replication_configuration_template.go @@ -8,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/service/drs" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "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/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" @@ -89,6 +90,10 @@ func ResourceReplicationConfigurationTemplate() *schema.Resource { "replication_servers_security_groups_ids": { Type: schema.TypeList, Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(drs.ValidationExceptionReason_Values(), false), + }, }, "staging_area_subnet_id": { Type: schema.TypeString, From 828542ef5f3220b9a5c660c514fee30e0562a9c3 Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 15:00:32 -0400 Subject: [PATCH 04/28] markdown edits --- ...eplication_configuration_template.html.markdown | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index e9e2cf501c25..dcd49adfd317 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -16,20 +16,20 @@ Provides an Elastic Disaster Recovery replication configuration template resourc ```terraform resource "aws_drs_replication_configuration_template" "example" { - associate_default_security_group = True|False + associate_default_security_group = True or False bandwidth_throttling = 123 - create_public_ip = True|False - data_plane_routing = 'PRIVATE_IP'|'PUBLIC_IP' - default_large_staging_disk_type = 'GP2'|'GP3|'ST1|'AUTO - ebs_ecryption = 'DEFAULT'|'CUSTOM' + create_public_ip = True or False + data_plane_routing = 'PRIVATE_IP' or 'PUBLIC_IP' + default_large_staging_disk_type = 'GP2'or 'GP3 or 'ST1 or 'AUTO + ebs_ecryption = 'DEFAULT' or 'CUSTOM' ebs_encryption_key_arn = 'string' - pit_policy = [{'enabled': True|False, 'interval':123}] + pit_policy = [{'enabled': True or False, 'interval':123}] replication_server_instance_type = 'string' replication_servers_security_groups_ids = ['string'] staging_area_subnet_id = 'string staging_area_tags = {'string': 'string'} tags = {'string': 'string'} - use_dedicated_replication_server = True|False + use_dedicated_replication_server = True or False } ``` From 0a8686fc912b46fdf413460e93de3e4a90288a16 Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 15:05:33 -0400 Subject: [PATCH 05/28] removing markdown indent --- ...cation_configuration_template.html.markdown | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index dcd49adfd317..df6c9dab862e 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -45,24 +45,6 @@ The following arguments are required: * `ebs_encryption` (Required)(string) The type of EBS encryption to be used during replication. * `ebs_encryption_key_arn` (Required)(string) The ARN of the EBS encryption key to be used during replication. * `pit_policy`(Required)(list) The Point in time (PIT) policy to manage snapshots taken during replication. - (dict) -- - A rule in the Point in Time (PIT) policy representing when to take snapshots and how long to retain them for. - - enabled (boolean) -- - - Whether this rule is enabled or not. - interval (integer) -- [REQUIRED] - - How often, in the chosen units, a snapshot should be taken. - retentionDuration (integer) -- [REQUIRED] - - The duration to retain a snapshot for, in the chosen units. - ruleID (integer) -- - - The ID of the rule. - units (string) -- [REQUIRED] - - The units used to measure the interval and retentionDuration. * `replication_server_instance_type` (Required)(string) The instance type to be used for the replication server. * `replication_servers_security_groups_ids` (Required)(list) The security group IDs that will be used by the replication server. * `staging_area_subnet_id` (Required)(string) The subnet to be used by the replication staging area. From 48843ccc6df167a65019e6e857faa969f205ae3c Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 15:10:19 -0400 Subject: [PATCH 06/28] adding double quotes to markdown --- ...ation_configuration_template.html.markdown | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index df6c9dab862e..7f7ad24b3bca 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -19,16 +19,16 @@ resource "aws_drs_replication_configuration_template" "example" { associate_default_security_group = True or False bandwidth_throttling = 123 create_public_ip = True or False - data_plane_routing = 'PRIVATE_IP' or 'PUBLIC_IP' - default_large_staging_disk_type = 'GP2'or 'GP3 or 'ST1 or 'AUTO - ebs_ecryption = 'DEFAULT' or 'CUSTOM' - ebs_encryption_key_arn = 'string' - pit_policy = [{'enabled': True or False, 'interval':123}] - replication_server_instance_type = 'string' - replication_servers_security_groups_ids = ['string'] - staging_area_subnet_id = 'string - staging_area_tags = {'string': 'string'} - tags = {'string': 'string'} + data_plane_routing = "PRIVATE_IP" or "PUBLIC_IP" + default_large_staging_disk_type = "GP2"or "GP3 or "ST1 or "AUTO + ebs_ecryption = "DEFAULT" or "CUSTOM" + ebs_encryption_key_arn = "string" + pit_policy = [{"enabled": True or False, "interval":123}] + replication_server_instance_type = "string" + replication_servers_security_groups_ids = ["string"] + staging_area_subnet_id = "string + staging_area_tags = {"string": "string"} + tags = {"string": "string"} use_dedicated_replication_server = True or False } ``` From e6163baa0e7f9e0340eef047974bf771e8b4277c Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 15:21:00 -0400 Subject: [PATCH 07/28] fixing quotes --- .../docs/r/drs_replication_configuration_template.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index 7f7ad24b3bca..04b5d579ef31 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -26,7 +26,7 @@ resource "aws_drs_replication_configuration_template" "example" { pit_policy = [{"enabled": True or False, "interval":123}] replication_server_instance_type = "string" replication_servers_security_groups_ids = ["string"] - staging_area_subnet_id = "string + staging_area_subnet_id = "string" staging_area_tags = {"string": "string"} tags = {"string": "string"} use_dedicated_replication_server = True or False From d34c193f0bafdf46dc305e1fcd6e71b72fea443a Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 15:30:25 -0400 Subject: [PATCH 08/28] removing newlines --- .../docs/r/drs_replication_configuration_template.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index 04b5d579ef31..aed8364d050b 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -20,7 +20,7 @@ resource "aws_drs_replication_configuration_template" "example" { bandwidth_throttling = 123 create_public_ip = True or False data_plane_routing = "PRIVATE_IP" or "PUBLIC_IP" - default_large_staging_disk_type = "GP2"or "GP3 or "ST1 or "AUTO + default_large_staging_disk_type = "GP2" or "GP3" or "ST1" or "AUTO" ebs_ecryption = "DEFAULT" or "CUSTOM" ebs_encryption_key_arn = "string" pit_policy = [{"enabled": True or False, "interval":123}] From e8d00970c42099c3f16155d3c2ab1462785681c7 Mon Sep 17 00:00:00 2001 From: Kevin Lewin Date: Mon, 22 Aug 2022 15:50:21 -0400 Subject: [PATCH 09/28] fixing subcategory --- .../docs/r/drs_replication_configuration_template.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index aed8364d050b..8b245fd4278b 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -1,5 +1,5 @@ --- -subcategory: "Elastic Disaster Recovery" +subcategory: "DRS (Elastic Disaster Recovery)" layout: "aws" page_title: "AWS: drs_replication_configuration_template" description: |- From 47c7e1232ccfb87354ec1fa7bc5af2af6a658278 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 15:13:42 -0400 Subject: [PATCH 10/28] drs_replication_configuration_template: Part way thru migration --- .../drs_replication_configuration_template.go | 232 ++++++++++-------- 1 file changed, 132 insertions(+), 100 deletions(-) diff --git a/internal/service/drs/drs_replication_configuration_template.go b/internal/service/drs/drs_replication_configuration_template.go index 4c7233cd58d9..ea4bb3fd1113 100644 --- a/internal/service/drs/drs_replication_configuration_template.go +++ b/internal/service/drs/drs_replication_configuration_template.go @@ -1,137 +1,144 @@ package drs import ( + "context" "fmt" "log" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/service/drs" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/aws/aws-sdk-go-v2/service/drs" + awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "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/conns" - "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "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" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" ) -func ResourceReplicationConfigurationTemplate() *schema.Resource { - return &schema.Resource{ - Create: resourceReplicationConfigurationTemplateCreate, - Read: resourceReplicationConfigurationTemplateRead, - Update: resourceReplicationConfigurationTemplateUpdate, - Delete: resourceReplicationConfigurationTemplateDelete, +// @FrameworkResource(name="Replication Configuration Template") +func newResourceReplicationConfigurationTemplate(_ context.Context) (resource.ResourceWithConfigure, error) { + return &resourceReplicationConfigurationTemplate{}, nil +} + +const ( + ResNameReplicationConfigurationTemplate = "ReplicationConfigurationTemplate" +) + +type resourceReplicationConfigurationTemplate struct { + framework.ResourceWithConfigure + framework.WithImportByID + framework.WithTimeouts +} - Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, +func (r *resourceReplicationConfigurationTemplate) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_drs_replication_configuration_template" +} + +func (r *resourceReplicationConfigurationTemplate) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "arn": schema.StringAttribute{ Computed: true, }, - "associate_default_security_group": { - Type: schema.TypeBool, + "associate_default_security_group": schema.BoolAttribute{ Required: true, }, - "bandwidth_throttling": { - Type: schema.TypeInt, + "bandwidth_throttling": schema.Int64Attribute{ Required: true, }, - "create_public_ip": { - Type: schema.TypeBool, + "create_public_ip": schema.BoolAttribute{ Required: true, }, - "data_plane_routing": { - Type: schema.TypeString, - Required: true, + "data_plane_routing": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationDataPlaneRouting](), + }, + "default_large_staging_disk_type": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationDefaultLargeStagingDiskType](), }, - "default_large_staging_disk_type": { - Type: schema.TypeString, + "ebs_encryption": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationEbsEncryption](), + }, + "ebs_encryption_key_arn": schema.StringAttribute{ Required: true, }, - "ebs_encryption": { - Type: schema.TypeString, + "replication_server_instance_type": schema.StringAttribute{ Required: true, }, - "ebs_encryption_key_arn": { - Type: schema.TypeString, + "replication_servers_security_groups_ids": schema.ListAttribute{ + Required: true, + ElementType: types.StringType, + }, + "staging_area_subnet_id": schema.StringAttribute{ Required: true, }, - "pit_policy": { - Type: schema.TypeList, + + "staging_area_tags": tftags.TagsAttribute(), + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + + "use_dedicated_replication_server": schema.BoolAttribute{ Required: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, + }, + }, + Blocks: map[string]schema.Block{ + "pit_policy": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[pitPolicy](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ Optional: true, }, - "interval": { - Type: schema.TypeInt, + "interval": schema.Int64Attribute{ Optional: true, }, - "retention_duration": { - Type: schema.TypeInt, + "retention_duration": schema.Int64Attribute{ Required: true, }, - "rule_id": { - Type: schema.TypeInt, + "rule_id": schema.Int64Attribute{ Optional: true, }, - "units": { - Type: schema.TypeString, + "units": schema.StringAttribute{ Required: true, }, }, }, - }, - "replication_server_instance_type": { - Type: schema.TypeString, - Required: true, - }, - "replication_servers_security_groups_ids": { - Type: schema.TypeList, - Required: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice(drs.ValidationExceptionReason_Values(), false), + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), }, }, - "staging_area_subnet_id": { - Type: schema.TypeString, - Required: true, - }, - "staging_area_tags": tftags.TagsSchema(), - "tags": tftags.TagsSchema(), - "use_dedicated_replication_server": { - Type: schema.TypeBool, - Required: true, - }, }, } } -func resourceReplicationConfigurationTemplateCreate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSConn - defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig - staging_tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("staging_area_tags").(map[string]interface{}))) - tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) - - input := &drs.CreateReplicationConfigurationTemplateInput{ - AssociateDefaultSecurityGroup: aws.Bool(d.Get("associate_default_security_group").(bool)), - BandwidthThrottling: aws.Int64(d.Get("bandwidth_throttling").(int64)), - CreatePublicIP: aws.Bool(d.Get("create_public_ip").(bool)), - DataPlaneRouting: aws.String(d.Get("data_plane_routing").(string)), - DefaultLargeStagingDiskType: aws.String(d.Get("default_large_staging_disk_type").(string)), - EbsEncryption: aws.String(d.Get("ebs_encryption").(string)), - EbsEncryptionKeyArn: aws.String(d.Get("ebs_encryption_key_arn").(string)), - PitPolicy: expandPitPolicy(d.Get("pit_policy").(*schema.Set).List()), - ReplicationServerInstanceType: aws.String(d.Get("replication_server_instance_type").(string)), - ReplicationServersSecurityGroupsIDs: flex.ExpandStringList(d.Get("replication_servers_security_groups_ids").([]interface{})), - StagingAreaSubnetId: aws.String(d.Get("staging_area_subnet_id").(string)), - StagingAreaTags: Tags(tags.IgnoreAWS()), - Tags: Tags(staging_tags.IgnoreAWS()), - UseDedicatedReplicationServer: aws.Bool(d.Get("use_dedicated_replication_server").(bool)), +func (r *resourceReplicationConfigurationTemplate) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data resourceReplicationConfigurationTemplateData + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return } + conn := r.Meta().DRSClient(ctx) + + input := &drs.CreateReplicationConfigurationTemplateInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + if response.Diagnostics.HasError() { + return + } + + input.Tags = getTags(ctx) + log.Printf("[DEBUG] Creating DRS Replication Configuration Template: %s", input) output, err := conn.CreateReplicationConfigurationTemplate(input) @@ -141,11 +148,11 @@ func resourceReplicationConfigurationTemplateCreate(d *schema.ResourceData, meta d.SetId(aws.ToString(output.ReplicationConfigurationTemplateID)) - return resourceReplicationConfigurationTemplateRead(d, meta) + return append(diags, resourceReplicationConfigurationTemplateRead(d, meta)...) } -func resourceReplicationConfigurationTemplateRead(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSConn +func resourceReplicationConfigurationTemplateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSClient(ctx) defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig @@ -189,8 +196,8 @@ func resourceReplicationConfigurationTemplateRead(d *schema.ResourceData, meta i return nil } -func resourceReplicationConfigurationTemplateUpdate(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSConn +func resourceReplicationConfigurationTemplateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSClient(ctx) defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig staging_tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("staging_area_tags").(map[string]interface{}))) @@ -261,15 +268,15 @@ func resourceReplicationConfigurationTemplateUpdate(d *schema.ResourceData, meta } -func resourceReplicationConfigurationTemplateDelete(d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSConn +func resourceReplicationConfigurationTemplateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).DRSClient(ctx) log.Printf("[DEBUG] Deleting Replication Configuration Template: %s", d.Id()) _, err := conn.DeleteReplicationConfigurationTemplate(&drs.DeleteReplicationConfigurationTemplateInput{ ReplicationConfigurationTemplateID: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, drs.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil } @@ -280,16 +287,16 @@ func resourceReplicationConfigurationTemplateDelete(d *schema.ResourceData, meta return nil } -func expandPitPolicy(p []interface{}) []*drs.PITPolicyRule { - pitPolicyRules := make([]*drs.PITPolicyRule, len(p)) +func expandPitPolicy(p []interface{}) []*awstypes.PITPolicyRule { + pitPolicyRules := make([]*awstypes.PITPolicyRule, len(p)) for i, pitPolicy := range p { pitPol := pitPolicy.(map[string]interface{}) - pitPolicyRules[i] = &drs.PITPolicyRule{ + pitPolicyRules[i] = &awstypes.PITPolicyRule{ Enabled: aws.Bool(pitPol["enabled"].(bool)), - Interval: aws.Int64(pitPol["interval"].(int64)), - RetentionDuration: aws.Int64(pitPol["retention_duration"].(int64)), - RuleID: aws.Int64(pitPol["rule_id"].(int64)), - Units: aws.String(pitPol["units"].(string)), + Interval: aws.Int32(pitPol["interval"].(int32)), + RetentionDuration: aws.Int32(pitPol["retention_duration"].(int32)), + RuleID: pitPol["rule_id"].(int64), + Units: pitPol["units"].(string), } } return pitPolicyRules @@ -302,3 +309,28 @@ func Tags(tags tftags.KeyValueTags) map[string]*string { func KeyValueTags(tags map[string]*string) tftags.KeyValueTags { return tftags.New(tags) } + +type resourceReplicationConfigurationTemplateData struct { + AssociateDefaultSecurityGroup types.Bool `tfsdk:"associate_default_security_group"` + BandwidthThrottling types.Int `tfsdk:"bandwidth_throttling"` + CreatePublicIP types.Bool `tfsdk:"create_public_ip"` + DataPlaneRouting fwtypes.StringEnum[awstypes.ReplicationConfigurationDataPlaneRouting] `tfsdk:"data_plane_routing"` + DefaultLargeStagingDiskType fwtypes.StringEnum[awstypes.ReplicationConfigurationDefaultLargeStagingDiskType] `tfsdk:"default_large_staging_disk_type"` + EbsEncryption fwtypes.StringEnum[awstypes.ReplicationConfigurationEbsEncryption] `tfsdk:"ebs_encryption"` + EbsEncryptionKeyARN types.String `tfsdk:"ebs_encryption_key_arn"` + PitPolicy fwtypes.ListNestedObjectValueOf[pitPolicy] `tfsdk:"pit_policy"` + ReplicationServerInstanceType types.String `tfsdk:"replication_server_instance_type"` + ReplicationServersSecurityGroupsIDs types.List `tfsdk:"replication_servers_security_groups_ids"` + StagingAreaSubnetID types.String `tfsdk:"staging_area_subnet_id"` + UseDedicatedReplicationServer types.Bool `tfsdk:"use_dedicated_replication_server"` + StagingAreaTags tftags.KeyValueTags `tfsdk:"staging_area_tags"` + Tags tftags.KeyValueTags `tfsdk:"tags"` +} + +type pitPolicy struct { + Enabled types.Bool `tfsdk:"enabled"` + Interval types.Int `tfsdk:"interval"` + RetentionDuration types.Int `tfsdk:"retention_duration"` + RuleID types.Int `tfsdk:"rule_id"` + Units types.String `tfsdk:"units"` +} From 204bae1db5ac678cf3b2c5046a7b71223a42ce6f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 15:14:06 -0400 Subject: [PATCH 11/28] drs/find: Migration step --- internal/service/drs/find.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/service/drs/find.go b/internal/service/drs/find.go index 1f0eceb0b300..30970fa6f1ae 100644 --- a/internal/service/drs/find.go +++ b/internal/service/drs/find.go @@ -1,25 +1,27 @@ package drs import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/drs" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "context" + + "github.com/aws/aws-sdk-go-v2/service/drs" + awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -func FindReplicationConfigurationTemplateByID(conn *drs.Drs, id string) (*drs.ReplicationConfigurationTemplate, error) { +func FindReplicationConfigurationTemplateByID(ctx context.Context, conn *drs.Client, id string) (*awstypes.ReplicationConfigurationTemplate, error) { //make string list from id - templateIdList := []*string{} - templateIdList = append(templateIdList, aws.String(id)) + templateIdList := []string{} + templateIdList = append(templateIdList, id) - input := &drs.DescribeReplicationConfigurationTemplatesInput{ + input := &awstypes.DescribeReplicationConfigurationTemplatesInput{ ReplicationConfigurationTemplateIDs: templateIdList, } output, err := conn.DescribeReplicationConfigurationTemplates(input) - if tfawserr.ErrCodeEquals(err, drs.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &resource.NotFoundError{ LastError: err, LastRequest: input, From 58682c66a5d0e38447601ae750e86660d0539dd0 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 15:14:27 -0400 Subject: [PATCH 12/28] drs: Generators --- internal/service/drs/generate.go | 1 + internal/service/drs/service_package_gen.go | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/service/drs/generate.go b/internal/service/drs/generate.go index 590623b58dcb..be899e13e3a8 100644 --- a/internal/service/drs/generate.go +++ b/internal/service/drs/generate.go @@ -3,6 +3,7 @@ //go:generate go run ../../generate/servicepackage/main.go //go:generate go run ../../generate/tagstests/main.go +//go:generate go run ../../generate/tags/main.go -AWSSDKVersion=2 -ListTagsForResource -ListTagsInIDElem=ResourceArn -ServiceTagsMap -TagOp=TagResource -TagInIDElem=ResourceId -UntagOp=UntagResource -ListTags -UpdateTags // ONLY generate directives and package declaration! Do not add anything else to this file. package drs diff --git a/internal/service/drs/service_package_gen.go b/internal/service/drs/service_package_gen.go index 93ba7aec234c..13f3a1940964 100644 --- a/internal/service/drs/service_package_gen.go +++ b/internal/service/drs/service_package_gen.go @@ -20,7 +20,12 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv } func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { - return []*types.ServicePackageFrameworkResource{} + return []*types.ServicePackageFrameworkResource{ + { + Factory: newResourceReplicationConfigurationTemplate, + Name: "Replication Configuration Template", + }, + } } func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePackageSDKDataSource { From 7d791f506573c83244db14eebf75e228e3c48648 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:13:07 -0400 Subject: [PATCH 13/28] drs: Add test exports --- internal/service/drs/exports_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 internal/service/drs/exports_test.go diff --git a/internal/service/drs/exports_test.go b/internal/service/drs/exports_test.go new file mode 100644 index 000000000000..432b2c2a6c2a --- /dev/null +++ b/internal/service/drs/exports_test.go @@ -0,0 +1,9 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package drs + +// Exports for use in tests only. +var ( + FindReplicationConfigurationTemplateByID = findReplicationConfigurationTemplateByID +) From 2ff6b87fc2f6d51a077749859e0bbfa16926df2e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:13:23 -0400 Subject: [PATCH 14/28] drs: Gen tags --- internal/service/drs/tags_gen.go | 137 +++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 internal/service/drs/tags_gen.go diff --git a/internal/service/drs/tags_gen.go b/internal/service/drs/tags_gen.go new file mode 100644 index 000000000000..cf6f91a7d0fe --- /dev/null +++ b/internal/service/drs/tags_gen.go @@ -0,0 +1,137 @@ +// Code generated by internal/generate/tags/main.go; DO NOT EDIT. +package drs + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/drs" + "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 drs 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 *drs.Client, identifier string, optFns ...func(*drs.Options)) (tftags.KeyValueTags, error) { + input := &drs.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(ctx, input, optFns...) + + if err != nil { + return tftags.New(ctx, nil), err + } + + return KeyValueTags(ctx, output.Tags), nil +} + +// ListTags lists drs 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).DRSClient(ctx), identifier) + + if err != nil { + return err + } + + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(tags) + } + + return nil +} + +// map[string]string handling + +// Tags returns drs service tags. +func Tags(tags tftags.KeyValueTags) map[string]string { + return tags.Map() +} + +// KeyValueTags creates tftags.KeyValueTags from drs service tags. +func KeyValueTags(ctx context.Context, tags map[string]string) tftags.KeyValueTags { + return tftags.New(ctx, tags) +} + +// getTagsIn returns drs 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 := Tags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { + return tags + } + } + + return nil +} + +// setTagsOut sets drs 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)) + } +} + +// createTags creates drs service tags for new resources. +func createTags(ctx context.Context, conn *drs.Client, identifier string, tags map[string]string) error { + if len(tags) == 0 { + return nil + } + + return updateTags(ctx, conn, identifier, nil, tags) +} + +// updateTags updates drs 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 *drs.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*drs.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.DRS) + if len(removedTags) > 0 { + input := &drs.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: removedTags.Keys(), + } + + _, err := conn.UntagResource(ctx, input, optFns...) + + if err != nil { + return fmt.Errorf("untagging resource (%s): %w", identifier, err) + } + } + + updatedTags := oldTags.Updated(newTags) + updatedTags = updatedTags.IgnoreSystem(names.DRS) + if len(updatedTags) > 0 { + input := &drs.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: Tags(updatedTags), + } + + _, err := conn.TagResource(ctx, input, optFns...) + + if err != nil { + return fmt.Errorf("tagging resource (%s): %w", identifier, err) + } + } + + return nil +} + +// UpdateTags updates drs 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).DRSClient(ctx), identifier, oldTags, newTags) +} From c53504b3c9ca0f2bf7af7b3c57a09004db3c8bc8 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:14:02 -0400 Subject: [PATCH 15/28] drs: Fix generate --- internal/service/drs/generate.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/service/drs/generate.go b/internal/service/drs/generate.go index be899e13e3a8..04beee97cc05 100644 --- a/internal/service/drs/generate.go +++ b/internal/service/drs/generate.go @@ -1,9 +1,8 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 +//go:generate go run ../../generate/tags/main.go -AWSSDKVersion=2 -ListTags -ListTagsInIDElem=ResourceArn -ServiceTagsMap -SkipTypesImp -KVTValues -TagOp=TagResource -TagInIDElem=ResourceArn -UntagOp=UntagResource -CreateTags -ListTags -UpdateTags //go:generate go run ../../generate/servicepackage/main.go -//go:generate go run ../../generate/tagstests/main.go -//go:generate go run ../../generate/tags/main.go -AWSSDKVersion=2 -ListTagsForResource -ListTagsInIDElem=ResourceArn -ServiceTagsMap -TagOp=TagResource -TagInIDElem=ResourceId -UntagOp=UntagResource -ListTags -UpdateTags // ONLY generate directives and package declaration! Do not add anything else to this file. package drs From 72f9e081dff46a3d76dc5b26330624f5c415dc46 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:14:26 -0400 Subject: [PATCH 16/28] drs: Update service package --- internal/service/drs/service_package_gen.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/service/drs/service_package_gen.go b/internal/service/drs/service_package_gen.go index 13f3a1940964..60cf41df0564 100644 --- a/internal/service/drs/service_package_gen.go +++ b/internal/service/drs/service_package_gen.go @@ -22,8 +22,11 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { return []*types.ServicePackageFrameworkResource{ { - Factory: newResourceReplicationConfigurationTemplate, + Factory: newReplicationConfigurationTemplateResource, Name: "Replication Configuration Template", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }, }, } } From 09afa57b8e3ea3aa659b73b3f07c41710ae23d7c Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:14:57 -0400 Subject: [PATCH 17/28] drs/replication_configuration_template: Convert to framework, add tests --- .../drs_replication_configuration_template.go | 336 ------------- internal/service/drs/find.go | 40 -- .../drs/replication_configuration_template.go | 450 ++++++++++++++++++ ...replication_configuration_template_test.go | 133 ++++++ 4 files changed, 583 insertions(+), 376 deletions(-) delete mode 100644 internal/service/drs/drs_replication_configuration_template.go delete mode 100644 internal/service/drs/find.go create mode 100644 internal/service/drs/replication_configuration_template.go create mode 100644 internal/service/drs/replication_configuration_template_test.go diff --git a/internal/service/drs/drs_replication_configuration_template.go b/internal/service/drs/drs_replication_configuration_template.go deleted file mode 100644 index ea4bb3fd1113..000000000000 --- a/internal/service/drs/drs_replication_configuration_template.go +++ /dev/null @@ -1,336 +0,0 @@ -package drs - -import ( - "context" - "fmt" - "log" - - "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/drs" - awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" - "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" - "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/conns" - "github.com/hashicorp/terraform-provider-aws/internal/errs" - "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" - 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(name="Replication Configuration Template") -func newResourceReplicationConfigurationTemplate(_ context.Context) (resource.ResourceWithConfigure, error) { - return &resourceReplicationConfigurationTemplate{}, nil -} - -const ( - ResNameReplicationConfigurationTemplate = "ReplicationConfigurationTemplate" -) - -type resourceReplicationConfigurationTemplate struct { - framework.ResourceWithConfigure - framework.WithImportByID - framework.WithTimeouts -} - -func (r *resourceReplicationConfigurationTemplate) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { - response.TypeName = "aws_drs_replication_configuration_template" -} - -func (r *resourceReplicationConfigurationTemplate) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - Attributes: map[string]schema.Attribute{ - "arn": schema.StringAttribute{ - Computed: true, - }, - "associate_default_security_group": schema.BoolAttribute{ - Required: true, - }, - "bandwidth_throttling": schema.Int64Attribute{ - Required: true, - }, - "create_public_ip": schema.BoolAttribute{ - Required: true, - }, - "data_plane_routing": schema.StringAttribute{ - Required: true, - CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationDataPlaneRouting](), - }, - "default_large_staging_disk_type": schema.StringAttribute{ - Required: true, - CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationDefaultLargeStagingDiskType](), - }, - "ebs_encryption": schema.StringAttribute{ - Required: true, - CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationEbsEncryption](), - }, - "ebs_encryption_key_arn": schema.StringAttribute{ - Required: true, - }, - "replication_server_instance_type": schema.StringAttribute{ - Required: true, - }, - "replication_servers_security_groups_ids": schema.ListAttribute{ - Required: true, - ElementType: types.StringType, - }, - "staging_area_subnet_id": schema.StringAttribute{ - Required: true, - }, - - "staging_area_tags": tftags.TagsAttribute(), - names.AttrTags: tftags.TagsAttribute(), - names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), - - "use_dedicated_replication_server": schema.BoolAttribute{ - Required: true, - }, - }, - Blocks: map[string]schema.Block{ - "pit_policy": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[pitPolicy](ctx), - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "enabled": schema.BoolAttribute{ - Optional: true, - }, - "interval": schema.Int64Attribute{ - Optional: true, - }, - "retention_duration": schema.Int64Attribute{ - Required: true, - }, - "rule_id": schema.Int64Attribute{ - Optional: true, - }, - "units": schema.StringAttribute{ - Required: true, - }, - }, - }, - Validators: []validator.List{ - listvalidator.SizeAtLeast(1), - }, - }, - }, - } -} - -func (r *resourceReplicationConfigurationTemplate) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { - var data resourceReplicationConfigurationTemplateData - response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) - if response.Diagnostics.HasError() { - return - } - - conn := r.Meta().DRSClient(ctx) - - input := &drs.CreateReplicationConfigurationTemplateInput{} - response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) - if response.Diagnostics.HasError() { - return - } - - input.Tags = getTags(ctx) - - log.Printf("[DEBUG] Creating DRS Replication Configuration Template: %s", input) - output, err := conn.CreateReplicationConfigurationTemplate(input) - - if err != nil { - return fmt.Errorf("error creating DRS Replication Configuration Template: %w", err) - } - - d.SetId(aws.ToString(output.ReplicationConfigurationTemplateID)) - - return append(diags, resourceReplicationConfigurationTemplateRead(d, meta)...) -} - -func resourceReplicationConfigurationTemplateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSClient(ctx) - defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig - ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - - replicationConfigurationTemplate, err := FindReplicationConfigurationTemplateByID(conn, d.Id()) - - if tfresource.NotFound(err) && !d.IsNewResource() { - log.Printf("[WARN] Replication Configuration Template (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - - if err != nil { - return fmt.Errorf("error reading Replication Configuration Template (%s): %w", d.Id(), err) - } - - d.Set("arn", replicationConfigurationTemplate.Arn) - d.Set("associate_default_security_group", replicationConfigurationTemplate.AssociateDefaultSecurityGroup) - d.Set("bandwidth_throttling", replicationConfigurationTemplate.BandwidthThrottling) - d.Set("create_public_ip", replicationConfigurationTemplate.CreatePublicIP) - d.Set("data_plane_routing", replicationConfigurationTemplate.DataPlaneRouting) - d.Set("default_large_staging_disk_type", replicationConfigurationTemplate.DefaultLargeStagingDiskType) - d.Set("ebs_encryption", replicationConfigurationTemplate.EbsEncryption) - d.Set("ebs_encryption_key_arn", replicationConfigurationTemplate.EbsEncryptionKeyArn) - d.Set("pit_policy", replicationConfigurationTemplate.PitPolicy) - d.Set("replication_server_instance_type", replicationConfigurationTemplate.ReplicationServerInstanceType) - d.Set("replication_servers_security_groups_ids", replicationConfigurationTemplate.ReplicationServersSecurityGroupsIDs) - d.Set("staging_area_subnet_id", replicationConfigurationTemplate.StagingAreaSubnetId) - d.Set("use_dedicated_replication_server", replicationConfigurationTemplate.UseDedicatedReplicationServer) - - tags := KeyValueTags(replicationConfigurationTemplate.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) - - //lintignore:AWSR002 - if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { - return fmt.Errorf("error setting tags: %w", err) - } - - if err := d.Set("staging_area_tags", tags.Map()); err != nil { - return fmt.Errorf("error setting tags_all: %w", err) - } - - return nil -} - -func resourceReplicationConfigurationTemplateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSClient(ctx) - - defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig - staging_tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("staging_area_tags").(map[string]interface{}))) - - input := &drs.UpdateReplicationConfigurationTemplateInput{ - ReplicationConfigurationTemplateID: aws.String(d.Id()), - } - - if d.HasChange("associate_default_security_group") { - input.AssociateDefaultSecurityGroup = aws.Bool(d.Get("associate_default_security_group").(bool)) - } - - if d.HasChange("bandwidth_throttling") { - input.BandwidthThrottling = aws.Int64(d.Get("bandwidth_throttling").(int64)) - } - - if d.HasChange("create_public_ip") { - input.CreatePublicIP = aws.Bool(d.Get("create_public_ip").(bool)) - } - - if d.HasChange("data_plane_routing") { - input.DataPlaneRouting = aws.String(d.Get("data_plane_routing").(string)) - } - - if d.HasChange("default_large_staging_disk_type") { - input.DefaultLargeStagingDiskType = aws.String(d.Get("default_large_staging_disk_type").(string)) - } - - if d.HasChange("ebs_encryption") { - input.EbsEncryption = aws.String(d.Get("ebs_encryption").(string)) - } - - if d.HasChange("ebs_encryption_key_arn") { - input.EbsEncryptionKeyArn = aws.String(d.Get("ebs_encryption_key_arn").(string)) - } - - if d.HasChange("pit_policy") { - input.PitPolicy = expandPitPolicy(d.Get("pit_policy").(*schema.Set).List()) - } - - if d.HasChange("replication_server_instance_type") { - input.ReplicationServerInstanceType = aws.String(d.Get("replication_server_instance_type").(string)) - } - - if d.HasChange("replication_servers_security_groups_ids") { - input.ReplicationServersSecurityGroupsIDs = flex.ExpandStringList(d.Get("replication_servers_security_groups_ids").([]interface{})) - } - - if d.HasChange("staging_area_subnet_id") { - input.StagingAreaSubnetId = aws.String(d.Get("staging_area_subnet_id").(string)) - } - - if d.HasChange("staging_area_tags") { - input.StagingAreaTags = Tags(staging_tags.IgnoreAWS()) - } - - if d.HasChange("use_dedicated_replication_server") { - input.UseDedicatedReplicationServer = aws.Bool(d.Get("use_dedicated_replication_server").(bool)) - } - - _, err := conn.UpdateReplicationConfigurationTemplate(input) - - if err != nil { - return fmt.Errorf("error updating replication configuration template (%s): : %w", d.Id(), err) - } - - return resourceReplicationConfigurationTemplateRead(d, meta) - -} - -func resourceReplicationConfigurationTemplateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) error { - conn := meta.(*conns.AWSClient).DRSClient(ctx) - - log.Printf("[DEBUG] Deleting Replication Configuration Template: %s", d.Id()) - _, err := conn.DeleteReplicationConfigurationTemplate(&drs.DeleteReplicationConfigurationTemplateInput{ - ReplicationConfigurationTemplateID: aws.String(d.Id()), - }) - - if errs.IsA[*awstypes.ResourceNotFoundException](err) { - return nil - } - - if err != nil { - return fmt.Errorf("error deleting Replication Configuration Tempalte (%s): %w", d.Id(), err) - } - - return nil -} - -func expandPitPolicy(p []interface{}) []*awstypes.PITPolicyRule { - pitPolicyRules := make([]*awstypes.PITPolicyRule, len(p)) - for i, pitPolicy := range p { - pitPol := pitPolicy.(map[string]interface{}) - pitPolicyRules[i] = &awstypes.PITPolicyRule{ - Enabled: aws.Bool(pitPol["enabled"].(bool)), - Interval: aws.Int32(pitPol["interval"].(int32)), - RetentionDuration: aws.Int32(pitPol["retention_duration"].(int32)), - RuleID: pitPol["rule_id"].(int64), - Units: pitPol["units"].(string), - } - } - return pitPolicyRules -} - -func Tags(tags tftags.KeyValueTags) map[string]*string { - return aws.StringMap(tags.Map()) -} - -func KeyValueTags(tags map[string]*string) tftags.KeyValueTags { - return tftags.New(tags) -} - -type resourceReplicationConfigurationTemplateData struct { - AssociateDefaultSecurityGroup types.Bool `tfsdk:"associate_default_security_group"` - BandwidthThrottling types.Int `tfsdk:"bandwidth_throttling"` - CreatePublicIP types.Bool `tfsdk:"create_public_ip"` - DataPlaneRouting fwtypes.StringEnum[awstypes.ReplicationConfigurationDataPlaneRouting] `tfsdk:"data_plane_routing"` - DefaultLargeStagingDiskType fwtypes.StringEnum[awstypes.ReplicationConfigurationDefaultLargeStagingDiskType] `tfsdk:"default_large_staging_disk_type"` - EbsEncryption fwtypes.StringEnum[awstypes.ReplicationConfigurationEbsEncryption] `tfsdk:"ebs_encryption"` - EbsEncryptionKeyARN types.String `tfsdk:"ebs_encryption_key_arn"` - PitPolicy fwtypes.ListNestedObjectValueOf[pitPolicy] `tfsdk:"pit_policy"` - ReplicationServerInstanceType types.String `tfsdk:"replication_server_instance_type"` - ReplicationServersSecurityGroupsIDs types.List `tfsdk:"replication_servers_security_groups_ids"` - StagingAreaSubnetID types.String `tfsdk:"staging_area_subnet_id"` - UseDedicatedReplicationServer types.Bool `tfsdk:"use_dedicated_replication_server"` - StagingAreaTags tftags.KeyValueTags `tfsdk:"staging_area_tags"` - Tags tftags.KeyValueTags `tfsdk:"tags"` -} - -type pitPolicy struct { - Enabled types.Bool `tfsdk:"enabled"` - Interval types.Int `tfsdk:"interval"` - RetentionDuration types.Int `tfsdk:"retention_duration"` - RuleID types.Int `tfsdk:"rule_id"` - Units types.String `tfsdk:"units"` -} diff --git a/internal/service/drs/find.go b/internal/service/drs/find.go deleted file mode 100644 index 30970fa6f1ae..000000000000 --- a/internal/service/drs/find.go +++ /dev/null @@ -1,40 +0,0 @@ -package drs - -import ( - "context" - - "github.com/aws/aws-sdk-go-v2/service/drs" - awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-provider-aws/internal/errs" - "github.com/hashicorp/terraform-provider-aws/internal/tfresource" -) - -func FindReplicationConfigurationTemplateByID(ctx context.Context, conn *drs.Client, id string) (*awstypes.ReplicationConfigurationTemplate, error) { - //make string list from id - templateIdList := []string{} - templateIdList = append(templateIdList, id) - - input := &awstypes.DescribeReplicationConfigurationTemplatesInput{ - ReplicationConfigurationTemplateIDs: templateIdList, - } - - output, err := conn.DescribeReplicationConfigurationTemplates(input) - - if errs.IsA[*awstypes.ResourceNotFoundException](err) { - return nil, &resource.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil || output.Items == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output.Items[0], nil -} diff --git a/internal/service/drs/replication_configuration_template.go b/internal/service/drs/replication_configuration_template.go new file mode 100644 index 000000000000..c2a332b34d6e --- /dev/null +++ b/internal/service/drs/replication_configuration_template.go @@ -0,0 +1,450 @@ +package drs + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/drs" + awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "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-log/tflog" + "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(name="Replication Configuration Template") +// @Tags(identifierAttribute="arn") +func newReplicationConfigurationTemplateResource(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &replicationConfigurationTemplateResource{} + + r.SetDefaultCreateTimeout(20 * time.Minute) + r.SetDefaultUpdateTimeout(20 * time.Minute) + r.SetDefaultDeleteTimeout(20 * time.Minute) + + return r, nil +} + +type replicationConfigurationTemplateResource struct { + framework.ResourceWithConfigure + framework.WithImportByID + framework.WithTimeouts +} + +func (r *replicationConfigurationTemplateResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_drs_replication_configuration_template" +} + +func (r *replicationConfigurationTemplateResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "arn": schema.StringAttribute{ + Computed: true, + }, + "associate_default_security_group": schema.BoolAttribute{ + Required: true, + }, + "auto_replicate_new_disks": schema.BoolAttribute{ + Optional: true, + }, + "bandwidth_throttling": schema.Int64Attribute{ + Required: true, + }, + "create_public_ip": schema.BoolAttribute{ + Required: true, + }, + "data_plane_routing": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationDataPlaneRouting](), + }, + "default_large_staging_disk_type": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationDefaultLargeStagingDiskType](), + }, + "ebs_encryption": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.ReplicationConfigurationEbsEncryption](), + }, + "ebs_encryption_key_arn": schema.StringAttribute{ + Optional: true, + }, + "id": schema.StringAttribute{ + Computed: true, + }, + "replication_server_instance_type": schema.StringAttribute{ + Required: true, + }, + "replication_servers_security_groups_ids": schema.ListAttribute{ + Required: true, + ElementType: types.StringType, + }, + "staging_area_subnet_id": schema.StringAttribute{ + Required: true, + }, + + "staging_area_tags": tftags.TagsAttribute(), + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + + "use_dedicated_replication_server": schema.BoolAttribute{ + Required: true, + }, + }, + Blocks: map[string]schema.Block{ + "pit_policy": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[pitPolicy](ctx), + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ + Optional: true, + }, + "interval": schema.Int64Attribute{ + Required: true, + }, + "retention_duration": schema.Int64Attribute{ + Required: true, + }, + "rule_id": schema.Int64Attribute{ + Optional: true, + }, + "units": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.StringEnumType[awstypes.PITPolicyRuleUnits](), + }, + }, + }, + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + }, + }, + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), + }, + } +} + +func (r *replicationConfigurationTemplateResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data replicationConfigurationTemplateResourceModel + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().DRSClient(ctx) + + input := &drs.CreateReplicationConfigurationTemplateInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + if response.Diagnostics.HasError() { + return + } + + input.Tags = getTagsIn(ctx) + + _, err := conn.CreateReplicationConfigurationTemplate(ctx, input) + if err != nil { + response.Diagnostics.AddError("creating DRS Replication Configuration Template", err.Error()) + + return + } + + output, err := waitReplicationConfigurationTemplateAvailable(ctx, conn, data.ID.ValueString(), r.CreateTimeout(ctx, data.Timeouts)) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for DRS Replication Configuration Template (%s) create", data.ID.ValueString()), err.Error()) + + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *replicationConfigurationTemplateResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data replicationConfigurationTemplateResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().DRSClient(ctx) + + output, err := findReplicationConfigurationTemplateByID(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 Replication Configuration Template (%s)", data.ID.ValueString()), err.Error()) + + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *replicationConfigurationTemplateResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var old, new replicationConfigurationTemplateResourceModel + 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().DRSClient(ctx) + + if replicationConfigurationTemplateHasChanges(ctx, new, old) { + input := &drs.UpdateReplicationConfigurationTemplateInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, new, input)...) + if response.Diagnostics.HasError() { + return + } + + _, err := conn.UpdateReplicationConfigurationTemplate(ctx, input) + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("updating DRS Replication Configuration Template (%s)", new.ID.ValueString()), err.Error()) + + return + } + + if _, err := waitReplicationConfigurationTemplateAvailable(ctx, conn, old.ID.ValueString(), r.UpdateTimeout(ctx, new.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for DRS Replication Configuration Template (%s) update", new.ID.ValueString()), err.Error()) + + return + } + } + + output, err := findReplicationConfigurationTemplateByID(ctx, conn, old.ID.ValueString()) + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading DRS Replication Configuration Template (%s)", old.ID.ValueString()), err.Error()) + + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &new)...) + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &new)...) +} + +func (r *replicationConfigurationTemplateResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data replicationConfigurationTemplateResourceModel + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + conn := r.Meta().DRSClient(ctx) + + tflog.Debug(ctx, "deleting DRS Replication Configuration Template", map[string]interface{}{ + names.AttrID: data.ID.ValueString(), + }) + + input := &drs.DeleteReplicationConfigurationTemplateInput{ + ReplicationConfigurationTemplateID: aws.String(data.ID.ValueString()), + } + + _, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, 5*time.Minute, func() (interface{}, error) { + return conn.DeleteReplicationConfigurationTemplate(ctx, input) + }, "DependencyViolation") + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting DRS Replication Configuration Template (%s)", data.ID.ValueString()), err.Error()) + + return + } + + if _, err := waitReplicationConfigurationTemplateDeleted(ctx, conn, data.ID.ValueString(), r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for DRS Replication Configuration Template (%s) delete", data.ID.ValueString()), err.Error()) + + return + } +} + +func (r *replicationConfigurationTemplateResource) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, request, response) +} + +func findReplicationConfigurationTemplate(ctx context.Context, conn *drs.Client, input *drs.DescribeReplicationConfigurationTemplatesInput) (*awstypes.ReplicationConfigurationTemplate, error) { + output, err := findReplicationConfigurationTemplates(ctx, conn, input) + + if err != nil { + return nil, err + } + + return tfresource.AssertSingleValueResult(output) +} + +func findReplicationConfigurationTemplates(ctx context.Context, conn *drs.Client, input *drs.DescribeReplicationConfigurationTemplatesInput) ([]awstypes.ReplicationConfigurationTemplate, error) { + var output []awstypes.ReplicationConfigurationTemplate + + pages := drs.NewDescribeReplicationConfigurationTemplatesPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + output = append(output, page.Items...) + } + + return output, nil +} + +func findReplicationConfigurationTemplateByID(ctx context.Context, conn *drs.Client, id string) (*awstypes.ReplicationConfigurationTemplate, error) { + input := &drs.DescribeReplicationConfigurationTemplatesInput{ + ReplicationConfigurationTemplateIDs: []string{id}, + } + + return findReplicationConfigurationTemplate(ctx, conn, input) +} + +const ( + replicationConfigurationTemplateAvailable = "AVAILABLE" +) + +func statusReplicationConfigurationTemplate(ctx context.Context, conn *drs.Client, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findReplicationConfigurationTemplateByID(ctx, conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + if err != nil { + return nil, "", err + } + + return output, replicationConfigurationTemplateAvailable, nil + } +} + +func waitReplicationConfigurationTemplateAvailable(ctx context.Context, conn *drs.Client, id string, timeout time.Duration) (*awstypes.ReplicationConfigurationTemplate, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{}, + Target: []string{replicationConfigurationTemplateAvailable}, + Refresh: statusReplicationConfigurationTemplate(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.ReplicationConfigurationTemplate); ok { + return output, err + } + + return nil, err +} + +func waitReplicationConfigurationTemplateDeleted(ctx context.Context, conn *drs.Client, id string, timeout time.Duration) (*awstypes.ReplicationConfigurationTemplate, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{replicationConfigurationTemplateAvailable}, + Target: []string{}, + Refresh: statusReplicationConfigurationTemplate(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.ReplicationConfigurationTemplate); ok { + return output, err + } + + return nil, err +} + +type replicationConfigurationTemplateResourceModel struct { + ARN types.String `tfsdk:"arn"` + AssociateDefaultSecurityGroup types.Bool `tfsdk:"associate_default_security_group"` + AutoReplicateNewDisks types.Bool `tfsdk:"auto_replicate_new_disks"` + BandwidthThrottling types.Int64 `tfsdk:"bandwidth_throttling"` + CreatePublicIP types.Bool `tfsdk:"create_public_ip"` + DataPlaneRouting fwtypes.StringEnum[awstypes.ReplicationConfigurationDataPlaneRouting] `tfsdk:"data_plane_routing"` + DefaultLargeStagingDiskType fwtypes.StringEnum[awstypes.ReplicationConfigurationDefaultLargeStagingDiskType] `tfsdk:"default_large_staging_disk_type"` + EBSEncryption fwtypes.StringEnum[awstypes.ReplicationConfigurationEbsEncryption] `tfsdk:"ebs_encryption"` + EBSEncryptionKeyARN types.String `tfsdk:"ebs_encryption_key_arn"` + ID types.String `tfsdk:"id"` + PitPolicy fwtypes.ListNestedObjectValueOf[pitPolicy] `tfsdk:"pit_policy"` + ReplicationServerInstanceType types.String `tfsdk:"replication_server_instance_type"` + ReplicationServersSecurityGroupsIDs types.List `tfsdk:"replication_servers_security_groups_ids"` + StagingAreaSubnetID types.String `tfsdk:"staging_area_subnet_id"` + UseDedicatedReplicationServer types.Bool `tfsdk:"use_dedicated_replication_server"` + StagingAreaTags types.Map `tfsdk:"staging_area_tags"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +type pitPolicy struct { + Enabled types.Bool `tfsdk:"enabled"` + Interval types.Int64 `tfsdk:"interval"` + RetentionDuration types.Int64 `tfsdk:"retention_duration"` + RuleID types.Int64 `tfsdk:"rule_id"` + Units fwtypes.StringEnum[awstypes.PITPolicyRuleUnits] `tfsdk:"units"` +} + +func replicationConfigurationTemplateHasChanges(_ context.Context, plan, state replicationConfigurationTemplateResourceModel) bool { + return !plan.AssociateDefaultSecurityGroup.Equal(state.AssociateDefaultSecurityGroup) || + !plan.AutoReplicateNewDisks.Equal(state.AutoReplicateNewDisks) || + !plan.BandwidthThrottling.Equal(state.BandwidthThrottling) || + !plan.CreatePublicIP.Equal(state.CreatePublicIP) || + !plan.DataPlaneRouting.Equal(state.DataPlaneRouting) || + !plan.DefaultLargeStagingDiskType.Equal(state.DefaultLargeStagingDiskType) || + !plan.EBSEncryption.Equal(state.EBSEncryption) || + !plan.EBSEncryptionKeyARN.Equal(state.EBSEncryptionKeyARN) || + !plan.ID.Equal(state.ID) || + !plan.PitPolicy.Equal(state.PitPolicy) || + !plan.ReplicationServerInstanceType.Equal(state.ReplicationServerInstanceType) || + !plan.ReplicationServersSecurityGroupsIDs.Equal(state.ReplicationServersSecurityGroupsIDs) || + !plan.StagingAreaSubnetID.Equal(state.StagingAreaSubnetID) || + !plan.UseDedicatedReplicationServer.Equal(state.UseDedicatedReplicationServer) +} diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go new file mode 100644 index 000000000000..747943034bd0 --- /dev/null +++ b/internal/service/drs/replication_configuration_template_test.go @@ -0,0 +1,133 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package drs_test + +import ( + "context" + "fmt" + "testing" + + awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" + "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" + tfdrs "github.com/hashicorp/terraform-provider-aws/internal/service/drs" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { + ctx := acctest.Context(t) + //if testing.Short() { + // t.Skip("skipping long-running test in short mode") + //} + + resourceName := "aws_drs_replication_configuration_template.test" + var rct awstypes.ReplicationConfigurationTemplate + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.DRSServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: resource.ComposeAggregateTestCheckFunc( + testAccCheckReplicationConfigurationTemplateDestroy(ctx), + ), + Steps: []resource.TestStep{ + { + Config: testAccReplicationConfigurationTemplateConfig_basic(), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckReplicationConfigurationTemplateExists(ctx, resourceName, &rct), + resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), + resource.TestCheckResourceAttrSet(resourceName, "cache_usage_limits.#"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrCreateTime), + resource.TestCheckResourceAttrSet(resourceName, "endpoint.#"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), + resource.TestCheckResourceAttrSet(resourceName, "full_engine_version"), + resource.TestCheckResourceAttrSet(resourceName, "reader_endpoint.#"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), + resource.TestCheckResourceAttrSet(resourceName, "subnet_ids.#"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckReplicationConfigurationTemplateExists(ctx context.Context, n string, v *awstypes.ReplicationConfigurationTemplate) 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).DRSClient(ctx) + + output, err := tfdrs.FindReplicationConfigurationTemplateByID(ctx, conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccCheckReplicationConfigurationTemplateDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).DRSClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_drs_replication_configuration_template" { + continue + } + + _, err := tfdrs.FindReplicationConfigurationTemplateByID(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + if err != nil { + return err + } + + return fmt.Errorf("DRS Replication Configuration Template (%s) still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccReplicationConfigurationTemplateConfig_basic() string { + return ` +resource "aws_drs_replication_configuration_template" "test" { + associate_default_security_group = false + bandwidth_throttling = 1 + create_public_ip = false + data_plane_routing = "PRIVATE_IP" + default_large_staging_disk_type = "GP2" + ebs_encryption = "NONE" + use_dedicated_replication_server = false + replication_server_instance_type = "t2.micro" + replication_servers_security_groups_ids = [] + staging_area_subnet_id = "" + + pit_policy { + interval = 1 + retention_duration = 1 + units = "DAY" + } + + staging_area_tags = { + Name = "staging-area" + } +} +` +} From cd63842582f3635b32f2d0ef26db51b475bd91c6 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:18:44 -0400 Subject: [PATCH 18/28] drs: Add header --- internal/service/drs/replication_configuration_template.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/drs/replication_configuration_template.go b/internal/service/drs/replication_configuration_template.go index c2a332b34d6e..486867c2244f 100644 --- a/internal/service/drs/replication_configuration_template.go +++ b/internal/service/drs/replication_configuration_template.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package drs import ( From 92e635687e03be0d28821e6cd54ad1bf8daf43b5 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 4 Jun 2024 19:39:14 -0400 Subject: [PATCH 19/28] docs/drs: Begin update of docs --- ...ation_configuration_template.html.markdown | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index 8b245fd4278b..0f8c1bdfe877 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -27,9 +27,7 @@ resource "aws_drs_replication_configuration_template" "example" { replication_server_instance_type = "string" replication_servers_security_groups_ids = ["string"] staging_area_subnet_id = "string" - staging_area_tags = {"string": "string"} - tags = {"string": "string"} - use_dedicated_replication_server = True or False + use_dedicated_replication_server = false } ``` @@ -37,30 +35,61 @@ resource "aws_drs_replication_configuration_template" "example" { The following arguments are required: -* `associate_default_security_group` - (Required)(boolean) Whether to associate the default Elastic Disaster Recovery Security group with the Replication Configuration Template. -* `bandwidth_throttling` - (Required)(integer) Configure bandwidth throttling for the outbound data transfer rate of the Source Server in Mbps. -* `create_public_ip` (Required)(boolean) Whether to create a Public IP for the Recovery Instance by default. -* `data_plane_routing` (Required)(string) The data plane routing mechanism that will be used for replication. -* `default_large_staging_disk_type` (Required)(string) The Staging Disk EBS volume type to be used during replication. -* `ebs_encryption` (Required)(string) The type of EBS encryption to be used during replication. -* `ebs_encryption_key_arn` (Required)(string) The ARN of the EBS encryption key to be used during replication. -* `pit_policy`(Required)(list) The Point in time (PIT) policy to manage snapshots taken during replication. -* `replication_server_instance_type` (Required)(string) The instance type to be used for the replication server. -* `replication_servers_security_groups_ids` (Required)(list) The security group IDs that will be used by the replication server. -* `staging_area_subnet_id` (Required)(string) The subnet to be used by the replication staging area. -* `staging_area_tags` (Required)(dict) A set of tags to be associated with all resources created in the replication staging area: EC2 replication server, EBS volumes, EBS snapshots, etc. -* `use_dedicated_replication_server` (Required)(boolean) Whether to use a dedicated Replication Server in the replication staging area. +* `associate_default_security_group` - (Required) Whether to associate the default Elastic Disaster Recovery Security group with the Replication Configuration Template. +* `bandwidth_throttling` - (Required) Configure bandwidth throttling for the outbound data transfer rate of the Source Server in Mbps. +* `create_public_ip` - (Required) Whether to create a Public IP for the Recovery Instance by default. +* `data_plane_routing` - (Required) Data plane routing mechanism that will be used for replication. +* `default_large_staging_disk_type` - (Required) Staging Disk EBS volume type to be used during replication. +* `ebs_encryption` - (Required) Type of EBS encryption to be used during replication. +* `ebs_encryption_key_arn` - (Required) ARN of the EBS encryption key to be used during replication. +* `pit_policy` - (Required) Configuration block for Point in time (PIT) policy to manage snapshots taken during replication. [See below](#pit_policy). +* `replication_server_instance_type` - (Required) Instance type to be used for the replication server. +* `replication_servers_security_groups_ids` - (Required) Security group IDs that will be used by the replication server. +* `staging_area_subnet_id` - (Required) Subnet to be used by the replication staging area. +* `staging_area_tags` - (Required) Set of tags to be associated with all resources created in the replication staging area: EC2 replication server, EBS volumes, EBS snapshots, etc. +* `use_dedicated_replication_server` - (Required) Whether to use a dedicated Replication Server in the replication staging area. The following arguments are optional: -* `tags` (Optional)(dict) A set of tags to be associated with the Replication Configuration Template resource. +* `auto_replicate_new_disks` - (Optional) Whether to allow the AWS replication agent to automatically replicate newly added disks. +* `tags` - (Optional) A set of tags to be associated with the Replication Configuration Template resource. + +### `pit_policy` + +* `enabled` - (Optional) Whether this rule is enabled or not. +* `interval` - (Required) How often, in the chosen units, a snapshot should be taken. +* `retention_duration` - (Required) Duration to retain a snapshot for, in the chosen `units`. +* `rule_id` - (Optional) ID of the rule. Valid values are integers. +* `units` - (Required) Units used to measure the `interval` and `retention_duration`. Valid values are `MINUTE`, `HOUR`, and `DAY`. ## Attributes Reference -In addition to all arguments above, the following attributes are exported: +This resource exports the following attributes in addition to the arguments above: + +* `arn` - Replication configuration template ARN. +* `id` - Replication configuration template ID. -* `arn` - The Replication Configuration Template ARN. -* `replication_configuration_template_id` - The Replication Configuration Template ID. +## Timeouts +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): +- `create` - (Default `20m`) +- `update` - (Default `20m`) +- `delete` - (Default `20m`) +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import DRS Replication Configuration Template using the `id`. For example: + +```terraform +import { + to = aws_drs_replication_configuration_template.example + id = "templateid" +} +``` + +Using `terraform import`, import DRS Replication Configuration Template using the `id`. For example: + +```console +% terraform import aws_drs_replication_configuration_template.example templateid +``` From 038d9678aa863a478615009654f2b886ccbe53fe Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Mon, 17 Jun 2024 13:40:01 -0400 Subject: [PATCH 20/28] drs: Updates to docs, logic --- ...replication_configuration_template_test.go | 43 +++++++++++++------ ...ation_configuration_template.html.markdown | 34 +++++++++------ 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go index 747943034bd0..b62415a4041b 100644 --- a/internal/service/drs/replication_configuration_template_test.go +++ b/internal/service/drs/replication_configuration_template_test.go @@ -9,6 +9,7 @@ import ( "testing" awstypes "github.com/aws/aws-sdk-go-v2/service/drs/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" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -23,7 +24,7 @@ func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { //if testing.Short() { // t.Skip("skipping long-running test in short mode") //} - + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_drs_replication_configuration_template.test" var rct awstypes.ReplicationConfigurationTemplate @@ -36,7 +37,7 @@ func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { ), Steps: []resource.TestStep{ { - Config: testAccReplicationConfigurationTemplateConfig_basic(), + Config: testAccReplicationConfigurationTemplateConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckReplicationConfigurationTemplateExists(ctx, resourceName, &rct), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), @@ -105,29 +106,45 @@ func testAccCheckReplicationConfigurationTemplateDestroy(ctx context.Context) re } } -func testAccReplicationConfigurationTemplateConfig_basic() string { - return ` +func testAccReplicationConfigurationTemplateConfig_basic(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigVPCWithSubnets(rName, 1), + fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q + description = %[1]q + vpc_id = aws_vpc.test.id + + ingress { + from_port = -1 + to_port = -1 + protocol = "icmp" + cidr_blocks = ["0.0.0.0/0"] + } +} + resource "aws_drs_replication_configuration_template" "test" { associate_default_security_group = false - bandwidth_throttling = 1 + bandwidth_throttling = 12 create_public_ip = false data_plane_routing = "PRIVATE_IP" default_large_staging_disk_type = "GP2" ebs_encryption = "NONE" use_dedicated_replication_server = false - replication_server_instance_type = "t2.micro" - replication_servers_security_groups_ids = [] - staging_area_subnet_id = "" + replication_server_instance_type = "t3.small" + replication_servers_security_groups_ids = [aws_security_group.test.id] + staging_area_subnet_id = aws_subnet.test[0].id pit_policy { - interval = 1 - retention_duration = 1 - units = "DAY" + enabled = true + interval = 60 + retention_duration = 120 + units = "MINUTE" } staging_area_tags = { - Name = "staging-area" + Name = %[1]q } } -` +`, rName)) } diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index 0f8c1bdfe877..1300e273baac 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -16,18 +16,24 @@ Provides an Elastic Disaster Recovery replication configuration template resourc ```terraform resource "aws_drs_replication_configuration_template" "example" { - associate_default_security_group = True or False - bandwidth_throttling = 123 - create_public_ip = True or False - data_plane_routing = "PRIVATE_IP" or "PUBLIC_IP" - default_large_staging_disk_type = "GP2" or "GP3" or "ST1" or "AUTO" - ebs_ecryption = "DEFAULT" or "CUSTOM" - ebs_encryption_key_arn = "string" - pit_policy = [{"enabled": True or False, "interval":123}] - replication_server_instance_type = "string" - replication_servers_security_groups_ids = ["string"] - staging_area_subnet_id = "string" + associate_default_security_group = false + bandwidth_throttling = 12 + create_public_ip = false + data_plane_routing = "PRIVATE_IP" + default_large_staging_disk_type = "GP2" + ebs_ecryption = "DEFAULT" + ebs_encryption_key_arn = "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab" + replication_server_instance_type = "t3.small" + replication_servers_security_groups_ids = aws_security_group.example[*].id + staging_area_subnet_id = aws_subnet.example.id use_dedicated_replication_server = false + + pit_policy { + enabled = true + interval = 1 + retention_duration = 1 + units = "DAY" + } } ``` @@ -38,9 +44,9 @@ The following arguments are required: * `associate_default_security_group` - (Required) Whether to associate the default Elastic Disaster Recovery Security group with the Replication Configuration Template. * `bandwidth_throttling` - (Required) Configure bandwidth throttling for the outbound data transfer rate of the Source Server in Mbps. * `create_public_ip` - (Required) Whether to create a Public IP for the Recovery Instance by default. -* `data_plane_routing` - (Required) Data plane routing mechanism that will be used for replication. -* `default_large_staging_disk_type` - (Required) Staging Disk EBS volume type to be used during replication. -* `ebs_encryption` - (Required) Type of EBS encryption to be used during replication. +* `data_plane_routing` - (Required) Data plane routing mechanism that will be used for replication. Valid values are `PUBLIC_IP` and `PRIVATE_IP`. +* `default_large_staging_disk_type` - (Required) Staging Disk EBS volume type to be used during replication. Valid values are `GP2`, `GP3`, `ST1`, or `AUTO`. +* `ebs_encryption` - (Required) Type of EBS encryption to be used during replication. Valid values are `DEFAULT` and `CUSTOM`. * `ebs_encryption_key_arn` - (Required) ARN of the EBS encryption key to be used during replication. * `pit_policy` - (Required) Configuration block for Point in time (PIT) policy to manage snapshots taken during replication. [See below](#pit_policy). * `replication_server_instance_type` - (Required) Instance type to be used for the replication server. From df1acae83e6eb5fb68e60f0afcc4940ff4db2545 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 15:41:04 -0400 Subject: [PATCH 21/28] drs/replication_configuration_template: Fix test --- .../drs/replication_configuration_template_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go index b62415a4041b..a449dd1e438a 100644 --- a/internal/service/drs/replication_configuration_template_test.go +++ b/internal/service/drs/replication_configuration_template_test.go @@ -136,10 +136,11 @@ resource "aws_drs_replication_configuration_template" "test" { staging_area_subnet_id = aws_subnet.test[0].id pit_policy { - enabled = true - interval = 60 - retention_duration = 120 - units = "MINUTE" + enabled = false + interval = 14 + retention_duration = 21 + units = "DAY" + rule_id = 1 } staging_area_tags = { From 8105a990eafbcaa2a89b6d29ba8d8052af2e6b8d Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 16:28:51 -0400 Subject: [PATCH 22/28] Add changelog --- .changelog/26399.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/26399.txt diff --git a/.changelog/26399.txt b/.changelog/26399.txt new file mode 100644 index 000000000000..19345acf8fd7 --- /dev/null +++ b/.changelog/26399.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_drs_replication_configuration_template +``` \ No newline at end of file From b741a36a5fc7ddcf7f25c752a99403fa586edb5f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 16:39:48 -0400 Subject: [PATCH 23/28] docs/drs: Add warning note about status --- .../r/drs_replication_configuration_template.html.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index 1300e273baac..5a216acf24f2 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -10,6 +10,8 @@ description: |- Provides an Elastic Disaster Recovery replication configuration template resource. +~> **NOTE:** This resource is provided on a best-effort basis and may not function as intended. Due to challenges with DRS permissions, it has not been fully tested. We are collaborating with AWS to enhance its functionality and [welcome your feedback](https://github.com/hashicorp/terraform-provider-aws/issues/new/choose). + ## Example Usage ### Basic configuration @@ -58,7 +60,7 @@ The following arguments are required: The following arguments are optional: * `auto_replicate_new_disks` - (Optional) Whether to allow the AWS replication agent to automatically replicate newly added disks. -* `tags` - (Optional) A set of tags to be associated with the Replication Configuration Template resource. +* `tags` - (Optional) Set of tags to be associated with the Replication Configuration Template resource. ### `pit_policy` @@ -74,6 +76,7 @@ This resource exports the following attributes in addition to the arguments abov * `arn` - Replication configuration template ARN. * `id` - Replication configuration template ID. +* `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). ## Timeouts From ccdbc98271a5da54d0ee011b279a0e6801e20545 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 16:53:29 -0400 Subject: [PATCH 24/28] drs/rep_conf_temp: Update test with correct args --- ...replication_configuration_template_test.go | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go index a449dd1e438a..4a7d99db2f4b 100644 --- a/internal/service/drs/replication_configuration_template_test.go +++ b/internal/service/drs/replication_configuration_template_test.go @@ -9,6 +9,7 @@ import ( "testing" awstypes "github.com/aws/aws-sdk-go-v2/service/drs/types" + "github.com/aws/aws-sdk-go/aws" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -21,9 +22,6 @@ import ( func TestAccDRSReplicationConfigurationTemplate_basic(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_drs_replication_configuration_template.test" var rct awstypes.ReplicationConfigurationTemplate @@ -41,14 +39,26 @@ func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckReplicationConfigurationTemplateExists(ctx, resourceName, &rct), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttrSet(resourceName, "cache_usage_limits.#"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrCreateTime), - resource.TestCheckResourceAttrSet(resourceName, "endpoint.#"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrEngine), - resource.TestCheckResourceAttrSet(resourceName, "full_engine_version"), - resource.TestCheckResourceAttrSet(resourceName, "reader_endpoint.#"), - resource.TestCheckResourceAttrSet(resourceName, names.AttrStatus), - resource.TestCheckResourceAttrSet(resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttr(resourceName, "associate_default_security_group", "false"), + resource.TestCheckResourceAttr(resourceName, "bandwidth_throttling", "12"), + resource.TestCheckResourceAttr(resourceName, "create_public_ip", "false"), + resource.TestCheckResourceAttr(resourceName, "data_plane_routing", "PRIVATE_IP"), + resource.TestCheckResourceAttr(resourceName, "default_large_staging_disk_type", "GP2"), + resource.TestCheckResourceAttr(resourceName, "ebs_encryption", "NONE"), + resource.TestCheckResourceAttr(resourceName, "use_dedicated_replication_server", "false"), + resource.TestCheckResourceAttr(resourceName, "replication_server_instance_type", "t3.small"), + resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.0", aws.StringValue(&rct.ReplicationServersSecurityGroupsIDs[0])), + resource.TestCheckResourceAttr(resourceName, "staging_area_subnet_id", aws.StringValue(rct.StagingAreaSubnetId)), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "pit_policy", map[string]string{ + "enabled": "false", + "interval": "14", + "retention_duration": "21", + "units": "DAY", + "rule_id": "1", + }), + resource.TestCheckResourceAttr(resourceName, "staging_area_tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "staging_area_tags.Name", rName), ), }, { @@ -140,7 +150,7 @@ resource "aws_drs_replication_configuration_template" "test" { interval = 14 retention_duration = 21 units = "DAY" - rule_id = 1 + rule_id = 1 } staging_area_tags = { From 524c9af5478ec429fffb8174cf71ded825b1f61f Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 16:55:01 -0400 Subject: [PATCH 25/28] docs/drs: Fixup header --- .../docs/r/drs_replication_configuration_template.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/drs_replication_configuration_template.html.markdown b/website/docs/r/drs_replication_configuration_template.html.markdown index 5a216acf24f2..e3b91516c6c1 100644 --- a/website/docs/r/drs_replication_configuration_template.html.markdown +++ b/website/docs/r/drs_replication_configuration_template.html.markdown @@ -70,7 +70,7 @@ The following arguments are optional: * `rule_id` - (Optional) ID of the rule. Valid values are integers. * `units` - (Required) Units used to measure the `interval` and `retention_duration`. Valid values are `MINUTE`, `HOUR`, and `DAY`. -## Attributes Reference +## Attribute Reference This resource exports the following attributes in addition to the arguments above: From 371b7dfc02d78208874a6d61e530aa16ec0faf08 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 17:23:14 -0400 Subject: [PATCH 26/28] drs: fix constants --- .../drs/replication_configuration_template.go | 8 ++++---- .../replication_configuration_template_test.go | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/internal/service/drs/replication_configuration_template.go b/internal/service/drs/replication_configuration_template.go index 486867c2244f..500e1a1947d7 100644 --- a/internal/service/drs/replication_configuration_template.go +++ b/internal/service/drs/replication_configuration_template.go @@ -54,7 +54,7 @@ func (r *replicationConfigurationTemplateResource) Metadata(_ context.Context, r func (r *replicationConfigurationTemplateResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "arn": schema.StringAttribute{ + names.AttrARN: schema.StringAttribute{ Computed: true, }, "associate_default_security_group": schema.BoolAttribute{ @@ -84,7 +84,7 @@ func (r *replicationConfigurationTemplateResource) Schema(ctx context.Context, r "ebs_encryption_key_arn": schema.StringAttribute{ Optional: true, }, - "id": schema.StringAttribute{ + names.AttrID: schema.StringAttribute{ Computed: true, }, "replication_server_instance_type": schema.StringAttribute{ @@ -111,10 +111,10 @@ func (r *replicationConfigurationTemplateResource) Schema(ctx context.Context, r CustomType: fwtypes.NewListNestedObjectTypeOf[pitPolicy](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "enabled": schema.BoolAttribute{ + names.AttrEnabled: schema.BoolAttribute{ Optional: true, }, - "interval": schema.Int64Attribute{ + names.AttrInterval: schema.Int64Attribute{ Required: true, }, "retention_duration": schema.Int64Attribute{ diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go index 4a7d99db2f4b..372a8701dca5 100644 --- a/internal/service/drs/replication_configuration_template_test.go +++ b/internal/service/drs/replication_configuration_template_test.go @@ -39,25 +39,25 @@ func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( testAccCheckReplicationConfigurationTemplateExists(ctx, resourceName, &rct), resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "associate_default_security_group", "false"), + resource.TestCheckResourceAttr(resourceName, "associate_default_security_group", acctest.CtFalse), resource.TestCheckResourceAttr(resourceName, "bandwidth_throttling", "12"), - resource.TestCheckResourceAttr(resourceName, "create_public_ip", "false"), + resource.TestCheckResourceAttr(resourceName, "create_public_ip", acctest.CtFalse), resource.TestCheckResourceAttr(resourceName, "data_plane_routing", "PRIVATE_IP"), resource.TestCheckResourceAttr(resourceName, "default_large_staging_disk_type", "GP2"), resource.TestCheckResourceAttr(resourceName, "ebs_encryption", "NONE"), - resource.TestCheckResourceAttr(resourceName, "use_dedicated_replication_server", "false"), + resource.TestCheckResourceAttr(resourceName, "use_dedicated_replication_server", acctest.CtFalse), resource.TestCheckResourceAttr(resourceName, "replication_server_instance_type", "t3.small"), - resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.0", aws.StringValue(&rct.ReplicationServersSecurityGroupsIDs[0])), resource.TestCheckResourceAttr(resourceName, "staging_area_subnet_id", aws.StringValue(rct.StagingAreaSubnetId)), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "pit_policy", map[string]string{ - "enabled": "false", - "interval": "14", + names.AttrEnabled: acctest.CtFalse, + names.AttrInterval: "14", "retention_duration": "21", "units": "DAY", - "rule_id": "1", + "rule_id": acctest.Ct1, }), - resource.TestCheckResourceAttr(resourceName, "staging_area_tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "staging_area_tags.%", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "staging_area_tags.Name", rName), ), }, From fd5f7ae93df523a0ed259e632b8c30193278172e Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 17:30:00 -0400 Subject: [PATCH 27/28] drs: gofmt --- .../service/drs/replication_configuration_template_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go index 372a8701dca5..45160b5920b2 100644 --- a/internal/service/drs/replication_configuration_template_test.go +++ b/internal/service/drs/replication_configuration_template_test.go @@ -51,8 +51,8 @@ func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.0", aws.StringValue(&rct.ReplicationServersSecurityGroupsIDs[0])), resource.TestCheckResourceAttr(resourceName, "staging_area_subnet_id", aws.StringValue(rct.StagingAreaSubnetId)), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "pit_policy", map[string]string{ - names.AttrEnabled: acctest.CtFalse, - names.AttrInterval: "14", + names.AttrEnabled: acctest.CtFalse, + names.AttrInterval: "14", "retention_duration": "21", "units": "DAY", "rule_id": acctest.Ct1, From b9bd770533ef7c4e2c93e23878bd0e923e0aaae1 Mon Sep 17 00:00:00 2001 From: Dirk Avery Date: Tue, 18 Jun 2024 19:02:12 -0400 Subject: [PATCH 28/28] drs: Fix panic --- internal/service/drs/replication_configuration_template_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/drs/replication_configuration_template_test.go b/internal/service/drs/replication_configuration_template_test.go index 45160b5920b2..28a213c75de3 100644 --- a/internal/service/drs/replication_configuration_template_test.go +++ b/internal/service/drs/replication_configuration_template_test.go @@ -48,7 +48,6 @@ func TestAccDRSReplicationConfigurationTemplate_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "use_dedicated_replication_server", acctest.CtFalse), resource.TestCheckResourceAttr(resourceName, "replication_server_instance_type", "t3.small"), resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.#", acctest.Ct1), - resource.TestCheckResourceAttr(resourceName, "replication_servers_security_groups_ids.0", aws.StringValue(&rct.ReplicationServersSecurityGroupsIDs[0])), resource.TestCheckResourceAttr(resourceName, "staging_area_subnet_id", aws.StringValue(rct.StagingAreaSubnetId)), resource.TestCheckTypeSetElemNestedAttrs(resourceName, "pit_policy", map[string]string{ names.AttrEnabled: acctest.CtFalse,