github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_dms_replication_instance.go (about)

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