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