github.com/bradfeehan/terraform@v0.7.0-rc3.0.20170529055808-34b45c5ad841/builtin/providers/aws/resource_aws_dms_replication_instance.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/aws/awserr"
    10  	dms "github.com/aws/aws-sdk-go/service/databasemigrationservice"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsDmsReplicationInstance() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsDmsReplicationInstanceCreate,
    18  		Read:   resourceAwsDmsReplicationInstanceRead,
    19  		Update: resourceAwsDmsReplicationInstanceUpdate,
    20  		Delete: resourceAwsDmsReplicationInstanceDelete,
    21  
    22  		Timeouts: &schema.ResourceTimeout{
    23  			Create: schema.DefaultTimeout(30 * time.Minute),
    24  			Update: schema.DefaultTimeout(30 * time.Minute),
    25  			Delete: schema.DefaultTimeout(30 * time.Minute),
    26  		},
    27  
    28  		Importer: &schema.ResourceImporter{
    29  			State: schema.ImportStatePassthrough,
    30  		},
    31  
    32  		Schema: map[string]*schema.Schema{
    33  			"allocated_storage": {
    34  				Type:         schema.TypeInt,
    35  				Computed:     true,
    36  				Optional:     true,
    37  				ValidateFunc: validateIntegerInRange(5, 6144),
    38  			},
    39  			"apply_immediately": {
    40  				Type:     schema.TypeBool,
    41  				Optional: true,
    42  			},
    43  			"auto_minor_version_upgrade": {
    44  				Type:     schema.TypeBool,
    45  				Computed: true,
    46  				Optional: true,
    47  			},
    48  			"availability_zone": {
    49  				Type:     schema.TypeString,
    50  				Computed: true,
    51  				Optional: true,
    52  				ForceNew: true,
    53  			},
    54  			"engine_version": {
    55  				Type:     schema.TypeString,
    56  				Computed: true,
    57  				Optional: true,
    58  			},
    59  			"kms_key_arn": {
    60  				Type:         schema.TypeString,
    61  				Computed:     true,
    62  				Optional:     true,
    63  				ForceNew:     true,
    64  				ValidateFunc: validateArn,
    65  			},
    66  			"multi_az": {
    67  				Type:     schema.TypeBool,
    68  				Computed: true,
    69  				Optional: true,
    70  			},
    71  			"preferred_maintenance_window": {
    72  				Type:         schema.TypeString,
    73  				Computed:     true,
    74  				Optional:     true,
    75  				ValidateFunc: validateOnceAWeekWindowFormat,
    76  			},
    77  			"publicly_accessible": {
    78  				Type:     schema.TypeBool,
    79  				Computed: true,
    80  				Optional: true,
    81  				ForceNew: true,
    82  			},
    83  			"replication_instance_arn": {
    84  				Type:     schema.TypeString,
    85  				Computed: true,
    86  			},
    87  			"replication_instance_class": {
    88  				Type:     schema.TypeString,
    89  				Required: true,
    90  				// Valid Values: dms.t2.micro | dms.t2.small | dms.t2.medium | dms.t2.large | dms.c4.large |
    91  				// dms.c4.xlarge | dms.c4.2xlarge | dms.c4.4xlarge
    92  			},
    93  			"replication_instance_id": {
    94  				Type:         schema.TypeString,
    95  				Required:     true,
    96  				ForceNew:     true,
    97  				ValidateFunc: validateDmsReplicationInstanceId,
    98  			},
    99  			"replication_instance_private_ips": {
   100  				Type:     schema.TypeList,
   101  				Elem:     &schema.Schema{Type: schema.TypeString},
   102  				Computed: true,
   103  			},
   104  			"replication_instance_public_ips": {
   105  				Type:     schema.TypeList,
   106  				Elem:     &schema.Schema{Type: schema.TypeString},
   107  				Computed: true,
   108  			},
   109  			"replication_subnet_group_id": {
   110  				Type:     schema.TypeString,
   111  				Computed: true,
   112  				Optional: true,
   113  				ForceNew: true,
   114  			},
   115  			"tags": {
   116  				Type:     schema.TypeMap,
   117  				Optional: true,
   118  			},
   119  			"vpc_security_group_ids": {
   120  				Type:     schema.TypeSet,
   121  				Elem:     &schema.Schema{Type: schema.TypeString},
   122  				Set:      schema.HashString,
   123  				Computed: true,
   124  				Optional: true,
   125  			},
   126  		},
   127  	}
   128  }
   129  
   130  func resourceAwsDmsReplicationInstanceCreate(d *schema.ResourceData, meta interface{}) error {
   131  	conn := meta.(*AWSClient).dmsconn
   132  
   133  	request := &dms.CreateReplicationInstanceInput{
   134  		AutoMinorVersionUpgrade:       aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
   135  		PubliclyAccessible:            aws.Bool(d.Get("publicly_accessible").(bool)),
   136  		ReplicationInstanceClass:      aws.String(d.Get("replication_instance_class").(string)),
   137  		ReplicationInstanceIdentifier: aws.String(d.Get("replication_instance_id").(string)),
   138  		Tags: dmsTagsFromMap(d.Get("tags").(map[string]interface{})),
   139  	}
   140  
   141  	// WARNING: GetOk returns the zero value for the type if the key is omitted in config. This means for optional
   142  	// keys that the zero value is valid we cannot know if the zero value was in the config and cannot allow the API
   143  	// to set the default value. See GitHub Issue #5694 https://github.com/hashicorp/terraform/issues/5694
   144  
   145  	if v, ok := d.GetOk("allocated_storage"); ok {
   146  		request.AllocatedStorage = aws.Int64(int64(v.(int)))
   147  	}
   148  	if v, ok := d.GetOk("engine_version"); ok {
   149  		request.EngineVersion = aws.String(v.(string))
   150  	}
   151  	if v, ok := d.GetOk("kms_key_arn"); ok {
   152  		request.KmsKeyId = aws.String(v.(string))
   153  	}
   154  	if v, ok := d.GetOk("preferred_maintenance_window"); ok {
   155  		request.PreferredMaintenanceWindow = aws.String(v.(string))
   156  	}
   157  	if v, ok := d.GetOk("replication_subnet_group_id"); ok {
   158  		request.ReplicationSubnetGroupIdentifier = aws.String(v.(string))
   159  	}
   160  	if v, ok := d.GetOk("vpc_security_group_ids"); ok {
   161  		request.VpcSecurityGroupIds = expandStringList(v.(*schema.Set).List())
   162  	}
   163  
   164  	az, azSet := d.GetOk("availability_zone")
   165  	if azSet {
   166  		request.AvailabilityZone = aws.String(az.(string))
   167  	}
   168  
   169  	if multiAz, ok := d.GetOk("multi_az"); ok {
   170  		request.MultiAZ = aws.Bool(multiAz.(bool))
   171  
   172  		if multiAz.(bool) && azSet {
   173  			return fmt.Errorf("Cannot set availability_zone if multi_az is set to true")
   174  		}
   175  	}
   176  
   177  	log.Println("[DEBUG] DMS create replication instance:", request)
   178  
   179  	_, err := conn.CreateReplicationInstance(request)
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	d.SetId(d.Get("replication_instance_id").(string))
   185  
   186  	stateConf := &resource.StateChangeConf{
   187  		Pending:    []string{"creating"},
   188  		Target:     []string{"available"},
   189  		Refresh:    resourceAwsDmsReplicationInstanceStateRefreshFunc(d, meta),
   190  		Timeout:    d.Timeout(schema.TimeoutCreate),
   191  		MinTimeout: 10 * time.Second,
   192  		Delay:      30 * time.Second, // Wait 30 secs before starting
   193  	}
   194  
   195  	// Wait, catching any errors
   196  	_, err = stateConf.WaitForState()
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	return resourceAwsDmsReplicationInstanceRead(d, meta)
   202  }
   203  
   204  func resourceAwsDmsReplicationInstanceRead(d *schema.ResourceData, meta interface{}) error {
   205  	conn := meta.(*AWSClient).dmsconn
   206  
   207  	response, err := conn.DescribeReplicationInstances(&dms.DescribeReplicationInstancesInput{
   208  		Filters: []*dms.Filter{
   209  			{
   210  				Name:   aws.String("replication-instance-id"),
   211  				Values: []*string{aws.String(d.Id())}, // Must use d.Id() to work with import.
   212  			},
   213  		},
   214  	})
   215  	if err != nil {
   216  		if dmserr, ok := err.(awserr.Error); ok && dmserr.Code() == "ResourceNotFoundFault" {
   217  			log.Printf("[DEBUG] DMS Replication Instance %q Not Found", d.Id())
   218  			d.SetId("")
   219  			return nil
   220  		}
   221  		return err
   222  	}
   223  
   224  	err = resourceAwsDmsReplicationInstanceSetState(d, response.ReplicationInstances[0])
   225  	if err != nil {
   226  		return err
   227  	}
   228  
   229  	tagsResp, err := conn.ListTagsForResource(&dms.ListTagsForResourceInput{
   230  		ResourceArn: aws.String(d.Get("replication_instance_arn").(string)),
   231  	})
   232  	if err != nil {
   233  		return err
   234  	}
   235  	d.Set("tags", dmsTagsToMap(tagsResp.TagList))
   236  
   237  	return nil
   238  }
   239  
   240  func resourceAwsDmsReplicationInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   241  	request := &dms.ModifyReplicationInstanceInput{
   242  		ApplyImmediately:       aws.Bool(d.Get("apply_immediately").(bool)),
   243  		ReplicationInstanceArn: aws.String(d.Get("replication_instance_arn").(string)),
   244  	}
   245  	hasChanges := false
   246  
   247  	if d.HasChange("auto_minor_version_upgrade") {
   248  		request.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool))
   249  		hasChanges = true
   250  	}
   251  
   252  	if d.HasChange("allocated_storage") {
   253  		if v, ok := d.GetOk("allocated_storage"); ok {
   254  			request.AllocatedStorage = aws.Int64(int64(v.(int)))
   255  			hasChanges = true
   256  		}
   257  	}
   258  
   259  	if d.HasChange("engine_version") {
   260  		if v, ok := d.GetOk("engine_version"); ok {
   261  			request.ReplicationInstanceClass = aws.String(v.(string))
   262  			hasChanges = true
   263  		}
   264  	}
   265  
   266  	if d.HasChange("multi_az") {
   267  		if v, ok := d.GetOk("multi_az"); ok {
   268  			request.MultiAZ = aws.Bool(v.(bool))
   269  			hasChanges = true
   270  		}
   271  	}
   272  
   273  	if d.HasChange("preferred_maintenance_window") {
   274  		if v, ok := d.GetOk("preferred_maintenance_window"); ok {
   275  			request.PreferredMaintenanceWindow = aws.String(v.(string))
   276  			hasChanges = true
   277  		}
   278  	}
   279  
   280  	if d.HasChange("replication_instance_class") {
   281  		if v, ok := d.GetOk("replication_instance_class"); ok {
   282  			request.ReplicationInstanceClass = aws.String(v.(string))
   283  			hasChanges = true
   284  		}
   285  	}
   286  
   287  	if d.HasChange("vpc_security_group_ids") {
   288  		if v, ok := d.GetOk("vpc_security_group_ids"); ok {
   289  			request.VpcSecurityGroupIds = expandStringList(v.(*schema.Set).List())
   290  			hasChanges = true
   291  		}
   292  	}
   293  
   294  	if d.HasChange("tags") {
   295  		err := dmsSetTags(d.Get("replication_instance_arn").(string), d, meta)
   296  		if err != nil {
   297  			return err
   298  		}
   299  	}
   300  
   301  	if hasChanges {
   302  		conn := meta.(*AWSClient).dmsconn
   303  
   304  		_, err := conn.ModifyReplicationInstance(request)
   305  		if err != nil {
   306  			return err
   307  		}
   308  
   309  		stateConf := &resource.StateChangeConf{
   310  			Pending:    []string{"modifying"},
   311  			Target:     []string{"available"},
   312  			Refresh:    resourceAwsDmsReplicationInstanceStateRefreshFunc(d, meta),
   313  			Timeout:    d.Timeout(schema.TimeoutUpdate),
   314  			MinTimeout: 10 * time.Second,
   315  			Delay:      30 * time.Second, // Wait 30 secs before starting
   316  		}
   317  
   318  		// Wait, catching any errors
   319  		_, err = stateConf.WaitForState()
   320  		if err != nil {
   321  			return err
   322  		}
   323  
   324  		return resourceAwsDmsReplicationInstanceRead(d, meta)
   325  	}
   326  
   327  	return nil
   328  }
   329  
   330  func resourceAwsDmsReplicationInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   331  	conn := meta.(*AWSClient).dmsconn
   332  
   333  	request := &dms.DeleteReplicationInstanceInput{
   334  		ReplicationInstanceArn: aws.String(d.Get("replication_instance_arn").(string)),
   335  	}
   336  
   337  	log.Printf("[DEBUG] DMS delete replication instance: %#v", request)
   338  
   339  	_, err := conn.DeleteReplicationInstance(request)
   340  	if err != nil {
   341  		return err
   342  	}
   343  
   344  	stateConf := &resource.StateChangeConf{
   345  		Pending:    []string{"deleting"},
   346  		Target:     []string{},
   347  		Refresh:    resourceAwsDmsReplicationInstanceStateRefreshFunc(d, meta),
   348  		Timeout:    d.Timeout(schema.TimeoutDelete),
   349  		MinTimeout: 10 * time.Second,
   350  		Delay:      30 * time.Second, // Wait 30 secs before starting
   351  	}
   352  
   353  	// Wait, catching any errors
   354  	_, err = stateConf.WaitForState()
   355  	if err != nil {
   356  		return err
   357  	}
   358  
   359  	return nil
   360  }
   361  
   362  func resourceAwsDmsReplicationInstanceSetState(d *schema.ResourceData, instance *dms.ReplicationInstance) error {
   363  	d.SetId(*instance.ReplicationInstanceIdentifier)
   364  
   365  	d.Set("replication_instance_id", instance.ReplicationInstanceIdentifier)
   366  	d.Set("allocated_storage", instance.AllocatedStorage)
   367  	d.Set("auto_minor_version_upgrade", instance.AutoMinorVersionUpgrade)
   368  	d.Set("availability_zone", instance.AvailabilityZone)
   369  	d.Set("engine_version", instance.EngineVersion)
   370  	d.Set("kms_key_arn", instance.KmsKeyId)
   371  	d.Set("multi_az", instance.MultiAZ)
   372  	d.Set("preferred_maintenance_window", instance.PreferredMaintenanceWindow)
   373  	d.Set("publicly_accessible", instance.PubliclyAccessible)
   374  	d.Set("replication_instance_arn", instance.ReplicationInstanceArn)
   375  	d.Set("replication_instance_class", instance.ReplicationInstanceClass)
   376  	d.Set("replication_subnet_group_id", instance.ReplicationSubnetGroup.ReplicationSubnetGroupIdentifier)
   377  
   378  	vpc_security_group_ids := []string{}
   379  	for _, sg := range instance.VpcSecurityGroups {
   380  		vpc_security_group_ids = append(vpc_security_group_ids, aws.StringValue(sg.VpcSecurityGroupId))
   381  	}
   382  
   383  	d.Set("vpc_security_group_ids", vpc_security_group_ids)
   384  
   385  	private_ip_addresses := []string{}
   386  	for _, ip := range instance.ReplicationInstancePrivateIpAddresses {
   387  		private_ip_addresses = append(private_ip_addresses, aws.StringValue(ip))
   388  	}
   389  
   390  	d.Set("replication_instance_private_ips", private_ip_addresses)
   391  
   392  	public_ip_addresses := []string{}
   393  	for _, ip := range instance.ReplicationInstancePublicIpAddresses {
   394  		public_ip_addresses = append(public_ip_addresses, aws.StringValue(ip))
   395  	}
   396  
   397  	d.Set("replication_instance_public_ips", public_ip_addresses)
   398  
   399  	return nil
   400  }
   401  
   402  func resourceAwsDmsReplicationInstanceStateRefreshFunc(
   403  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   404  	return func() (interface{}, string, error) {
   405  		conn := meta.(*AWSClient).dmsconn
   406  
   407  		v, err := conn.DescribeReplicationInstances(&dms.DescribeReplicationInstancesInput{
   408  			Filters: []*dms.Filter{
   409  				{
   410  					Name:   aws.String("replication-instance-id"),
   411  					Values: []*string{aws.String(d.Id())}, // Must use d.Id() to work with import.
   412  				},
   413  			},
   414  		})
   415  		if err != nil {
   416  			if dmserr, ok := err.(awserr.Error); ok && dmserr.Code() == "ResourceNotFoundFault" {
   417  				return nil, "", nil
   418  			}
   419  			log.Printf("Error on retrieving DMS Replication Instance when waiting: %s", err)
   420  			return nil, "", err
   421  		}
   422  
   423  		if v == nil {
   424  			return nil, "", nil
   425  		}
   426  
   427  		if v.ReplicationInstances == nil {
   428  			return nil, "", fmt.Errorf("Error on retrieving DMS Replication Instance when waiting for State")
   429  		}
   430  
   431  		return v, *v.ReplicationInstances[0].ReplicationInstanceStatus, nil
   432  	}
   433  }