mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-20 11:48:24 -06:00
* Add aws dms vendoring * Add aws dms endpoint resource * Add aws dms replication instance resource * Add aws dms replication subnet group resource * Add aws dms replication task resource * Fix aws dms resource go vet errors * Review fixes: Add id validators for all resources. Add validator for endpoint engine_name. * Add aws dms resources to importability list * Review fixes: Add aws dms iam role dependencies to test cases * Review fixes: Adjustments for handling input values * Add aws dms replication subnet group tagging * Fix aws dms subnet group doesn't use standard error for resource not found * Missed update of aws dms vendored version * Add aws dms certificate resource * Update aws dms resources to force new for immutable attributes * Fix tests failing on subnet deletion by adding explicit dependencies. Combine import tests with basic tests to cut down runtime.
423 lines
12 KiB
Go
423 lines
12 KiB
Go
package aws
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
"github.com/aws/aws-sdk-go/private/waiter"
|
|
dms "github.com/aws/aws-sdk-go/service/databasemigrationservice"
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
)
|
|
|
|
func resourceAwsDmsReplicationInstance() *schema.Resource {
|
|
return &schema.Resource{
|
|
Create: resourceAwsDmsReplicationInstanceCreate,
|
|
Read: resourceAwsDmsReplicationInstanceRead,
|
|
Update: resourceAwsDmsReplicationInstanceUpdate,
|
|
Delete: resourceAwsDmsReplicationInstanceDelete,
|
|
|
|
Importer: &schema.ResourceImporter{
|
|
State: schema.ImportStatePassthrough,
|
|
},
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"allocated_storage": {
|
|
Type: schema.TypeInt,
|
|
Computed: true,
|
|
Optional: true,
|
|
ValidateFunc: validateIntegerInRange(5, 6144),
|
|
},
|
|
"apply_immediately": {
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
},
|
|
"auto_minor_version_upgrade": {
|
|
Type: schema.TypeBool,
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
"availability_zone": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"engine_version": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
"kms_key_arn": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
ValidateFunc: validateArn,
|
|
},
|
|
"multi_az": {
|
|
Type: schema.TypeBool,
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
"preferred_maintenance_window": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
Optional: true,
|
|
ValidateFunc: validateOnceAWeekWindowFormat,
|
|
},
|
|
"publicly_accessible": {
|
|
Type: schema.TypeBool,
|
|
Computed: true,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"replication_instance_arn": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
},
|
|
"replication_instance_class": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
// Valid Values: dms.t2.micro | dms.t2.small | dms.t2.medium | dms.t2.large | dms.c4.large |
|
|
// dms.c4.xlarge | dms.c4.2xlarge | dms.c4.4xlarge
|
|
},
|
|
"replication_instance_id": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
ValidateFunc: validateDmsReplicationInstanceId,
|
|
},
|
|
"replication_instance_private_ips": {
|
|
Type: schema.TypeList,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Computed: true,
|
|
},
|
|
"replication_instance_public_ips": {
|
|
Type: schema.TypeList,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Computed: true,
|
|
},
|
|
"replication_subnet_group_id": {
|
|
Type: schema.TypeString,
|
|
Computed: true,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"tags": {
|
|
Type: schema.TypeMap,
|
|
Optional: true,
|
|
},
|
|
"vpc_security_group_ids": {
|
|
Type: schema.TypeSet,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
Set: schema.HashString,
|
|
Computed: true,
|
|
Optional: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func resourceAwsDmsReplicationInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|
conn := meta.(*AWSClient).dmsconn
|
|
|
|
request := &dms.CreateReplicationInstanceInput{
|
|
AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
|
|
PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)),
|
|
ReplicationInstanceClass: aws.String(d.Get("replication_instance_class").(string)),
|
|
ReplicationInstanceIdentifier: aws.String(d.Get("replication_instance_id").(string)),
|
|
Tags: dmsTagsFromMap(d.Get("tags").(map[string]interface{})),
|
|
}
|
|
|
|
// WARNING: GetOk returns the zero value for the type if the key is omitted in config. This means for optional
|
|
// keys that the zero value is valid we cannot know if the zero value was in the config and cannot allow the API
|
|
// to set the default value. See GitHub Issue #5694 https://github.com/hashicorp/terraform/issues/5694
|
|
|
|
if v, ok := d.GetOk("allocated_storage"); ok {
|
|
request.AllocatedStorage = aws.Int64(int64(v.(int)))
|
|
}
|
|
if v, ok := d.GetOk("engine_version"); ok {
|
|
request.EngineVersion = aws.String(v.(string))
|
|
}
|
|
if v, ok := d.GetOk("kms_key_arn"); ok {
|
|
request.KmsKeyId = aws.String(v.(string))
|
|
}
|
|
if v, ok := d.GetOk("preferred_maintenance_window"); ok {
|
|
request.PreferredMaintenanceWindow = aws.String(v.(string))
|
|
}
|
|
if v, ok := d.GetOk("replication_subnet_group_id"); ok {
|
|
request.ReplicationSubnetGroupIdentifier = aws.String(v.(string))
|
|
}
|
|
if v, ok := d.GetOk("vpc_security_group_ids"); ok {
|
|
request.VpcSecurityGroupIds = expandStringList(v.(*schema.Set).List())
|
|
}
|
|
|
|
az, azSet := d.GetOk("availability_zone")
|
|
if azSet {
|
|
request.AvailabilityZone = aws.String(az.(string))
|
|
}
|
|
|
|
if multiAz, ok := d.GetOk("multi_az"); ok {
|
|
request.MultiAZ = aws.Bool(multiAz.(bool))
|
|
|
|
if multiAz.(bool) && azSet {
|
|
return fmt.Errorf("Cannot set availability_zone if multi_az is set to true")
|
|
}
|
|
}
|
|
|
|
log.Println("[DEBUG] DMS create replication instance:", request)
|
|
|
|
_, err := conn.CreateReplicationInstance(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = waitForInstanceCreated(conn, d.Get("replication_instance_id").(string), 30, 20)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
d.SetId(d.Get("replication_instance_id").(string))
|
|
return resourceAwsDmsReplicationInstanceRead(d, meta)
|
|
}
|
|
|
|
func resourceAwsDmsReplicationInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
|
conn := meta.(*AWSClient).dmsconn
|
|
|
|
response, err := conn.DescribeReplicationInstances(&dms.DescribeReplicationInstancesInput{
|
|
Filters: []*dms.Filter{
|
|
{
|
|
Name: aws.String("replication-instance-id"),
|
|
Values: []*string{aws.String(d.Id())}, // Must use d.Id() to work with import.
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
if dmserr, ok := err.(awserr.Error); ok && dmserr.Code() == "ResourceNotFoundFault" {
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
|
|
err = resourceAwsDmsReplicationInstanceSetState(d, response.ReplicationInstances[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tagsResp, err := conn.ListTagsForResource(&dms.ListTagsForResourceInput{
|
|
ResourceArn: aws.String(d.Get("replication_instance_arn").(string)),
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.Set("tags", dmsTagsToMap(tagsResp.TagList))
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceAwsDmsReplicationInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
|
|
request := &dms.ModifyReplicationInstanceInput{
|
|
ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)),
|
|
ReplicationInstanceArn: aws.String(d.Get("replication_instance_arn").(string)),
|
|
}
|
|
hasChanges := false
|
|
|
|
if d.HasChange("auto_minor_version_upgrade") {
|
|
request.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool))
|
|
hasChanges = true
|
|
}
|
|
|
|
if d.HasChange("allocated_storage") {
|
|
if v, ok := d.GetOk("allocated_storage"); ok {
|
|
request.AllocatedStorage = aws.Int64(int64(v.(int)))
|
|
hasChanges = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("engine_version") {
|
|
if v, ok := d.GetOk("engine_version"); ok {
|
|
request.ReplicationInstanceClass = aws.String(v.(string))
|
|
hasChanges = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("multi_az") {
|
|
if v, ok := d.GetOk("multi_az"); ok {
|
|
request.MultiAZ = aws.Bool(v.(bool))
|
|
hasChanges = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("preferred_maintenance_window") {
|
|
if v, ok := d.GetOk("preferred_maintenance_window"); ok {
|
|
request.PreferredMaintenanceWindow = aws.String(v.(string))
|
|
hasChanges = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("replication_instance_class") {
|
|
if v, ok := d.GetOk("replication_instance_class"); ok {
|
|
request.ReplicationInstanceClass = aws.String(v.(string))
|
|
hasChanges = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("vpc_security_group_ids") {
|
|
if v, ok := d.GetOk("vpc_security_group_ids"); ok {
|
|
request.VpcSecurityGroupIds = expandStringList(v.(*schema.Set).List())
|
|
hasChanges = true
|
|
}
|
|
}
|
|
|
|
if d.HasChange("tags") {
|
|
err := dmsSetTags(d.Get("replication_instance_arn").(string), d, meta)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if hasChanges {
|
|
conn := meta.(*AWSClient).dmsconn
|
|
|
|
_, err := conn.ModifyReplicationInstance(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return resourceAwsDmsReplicationInstanceRead(d, meta)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceAwsDmsReplicationInstanceDelete(d *schema.ResourceData, meta interface{}) error {
|
|
conn := meta.(*AWSClient).dmsconn
|
|
|
|
request := &dms.DeleteReplicationInstanceInput{
|
|
ReplicationInstanceArn: aws.String(d.Get("replication_instance_arn").(string)),
|
|
}
|
|
|
|
log.Printf("[DEBUG] DMS delete replication instance: %#v", request)
|
|
|
|
_, err := conn.DeleteReplicationInstance(request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
waitErr := waitForInstanceDeleted(conn, d.Get("replication_instance_id").(string), 30, 20)
|
|
if waitErr != nil {
|
|
return waitErr
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceAwsDmsReplicationInstanceSetState(d *schema.ResourceData, instance *dms.ReplicationInstance) error {
|
|
d.SetId(*instance.ReplicationInstanceIdentifier)
|
|
|
|
d.Set("replication_instance_id", instance.ReplicationInstanceIdentifier)
|
|
d.Set("allocated_storage", instance.AllocatedStorage)
|
|
d.Set("auto_minor_version_upgrade", instance.AutoMinorVersionUpgrade)
|
|
d.Set("availability_zone", instance.AvailabilityZone)
|
|
d.Set("engine_version", instance.EngineVersion)
|
|
d.Set("kms_key_arn", instance.KmsKeyId)
|
|
d.Set("multi_az", instance.MultiAZ)
|
|
d.Set("preferred_maintenance_window", instance.PreferredMaintenanceWindow)
|
|
d.Set("publicly_accessible", instance.PubliclyAccessible)
|
|
d.Set("replication_instance_arn", instance.ReplicationInstanceArn)
|
|
d.Set("replication_instance_class", instance.ReplicationInstanceClass)
|
|
d.Set("replication_subnet_group_id", instance.ReplicationSubnetGroup.ReplicationSubnetGroupIdentifier)
|
|
|
|
vpc_security_group_ids := []string{}
|
|
for _, sg := range instance.VpcSecurityGroups {
|
|
vpc_security_group_ids = append(vpc_security_group_ids, aws.StringValue(sg.VpcSecurityGroupId))
|
|
}
|
|
|
|
d.Set("vpc_security_group_ids", vpc_security_group_ids)
|
|
|
|
private_ip_addresses := []string{}
|
|
for _, ip := range instance.ReplicationInstancePrivateIpAddresses {
|
|
private_ip_addresses = append(private_ip_addresses, aws.StringValue(ip))
|
|
}
|
|
|
|
d.Set("replication_instance_private_ips", private_ip_addresses)
|
|
|
|
public_ip_addresses := []string{}
|
|
for _, ip := range instance.ReplicationInstancePublicIpAddresses {
|
|
public_ip_addresses = append(public_ip_addresses, aws.StringValue(ip))
|
|
}
|
|
|
|
d.Set("replication_instance_public_ips", public_ip_addresses)
|
|
|
|
return nil
|
|
}
|
|
|
|
func waitForInstanceCreated(client *dms.DatabaseMigrationService, id string, delay int, maxAttempts int) error {
|
|
input := &dms.DescribeReplicationInstancesInput{
|
|
Filters: []*dms.Filter{
|
|
{
|
|
Name: aws.String("replication-instance-id"),
|
|
Values: []*string{aws.String(id)},
|
|
},
|
|
},
|
|
}
|
|
|
|
config := waiter.Config{
|
|
Operation: "DescribeReplicationInstances",
|
|
Delay: delay,
|
|
MaxAttempts: maxAttempts,
|
|
Acceptors: []waiter.WaitAcceptor{
|
|
{
|
|
State: "success",
|
|
Matcher: "pathAll",
|
|
Argument: "ReplicationInstances[].ReplicationInstanceStatus",
|
|
Expected: "available",
|
|
},
|
|
},
|
|
}
|
|
|
|
w := waiter.Waiter{
|
|
Client: client,
|
|
Input: input,
|
|
Config: config,
|
|
}
|
|
|
|
return w.Wait()
|
|
}
|
|
|
|
func waitForInstanceDeleted(client *dms.DatabaseMigrationService, id string, delay int, maxAttempts int) error {
|
|
input := &dms.DescribeReplicationInstancesInput{
|
|
Filters: []*dms.Filter{
|
|
{
|
|
Name: aws.String("replication-instance-id"),
|
|
Values: []*string{aws.String(id)},
|
|
},
|
|
},
|
|
}
|
|
|
|
config := waiter.Config{
|
|
Operation: "DescribeReplicationInstances",
|
|
Delay: delay,
|
|
MaxAttempts: maxAttempts,
|
|
Acceptors: []waiter.WaitAcceptor{
|
|
{
|
|
State: "success",
|
|
Matcher: "path",
|
|
Argument: "length(ReplicationInstances[]) > `0`",
|
|
Expected: false,
|
|
},
|
|
},
|
|
}
|
|
|
|
w := waiter.Waiter{
|
|
Client: client,
|
|
Input: input,
|
|
Config: config,
|
|
}
|
|
|
|
return w.Wait()
|
|
}
|