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

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/awserr"
    11  	"github.com/aws/aws-sdk-go/private/waiter"
    12  	dms "github.com/aws/aws-sdk-go/service/databasemigrationservice"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  	"github.com/hashicorp/terraform/helper/validation"
    15  )
    16  
    17  func resourceAwsDmsReplicationTask() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsDmsReplicationTaskCreate,
    20  		Read:   resourceAwsDmsReplicationTaskRead,
    21  		Update: resourceAwsDmsReplicationTaskUpdate,
    22  		Delete: resourceAwsDmsReplicationTaskDelete,
    23  
    24  		Importer: &schema.ResourceImporter{
    25  			State: schema.ImportStatePassthrough,
    26  		},
    27  
    28  		Schema: map[string]*schema.Schema{
    29  			"cdc_start_time": {
    30  				Type:     schema.TypeInt,
    31  				Optional: true,
    32  				// Requires a Unix timestamp in seconds. Example 1484346880
    33  			},
    34  			"migration_type": {
    35  				Type:     schema.TypeString,
    36  				Required: true,
    37  				ValidateFunc: validation.StringInSlice([]string{
    38  					"full-load",
    39  					"cdc",
    40  					"full-load-and-cdc",
    41  				}, false),
    42  			},
    43  			"replication_instance_arn": {
    44  				Type:         schema.TypeString,
    45  				Required:     true,
    46  				ForceNew:     true,
    47  				ValidateFunc: validateArn,
    48  			},
    49  			"replication_task_arn": {
    50  				Type:     schema.TypeString,
    51  				Computed: true,
    52  			},
    53  			"replication_task_id": {
    54  				Type:         schema.TypeString,
    55  				Required:     true,
    56  				ForceNew:     true,
    57  				ValidateFunc: validateDmsReplicationTaskId,
    58  			},
    59  			"replication_task_settings": {
    60  				Type:             schema.TypeString,
    61  				Optional:         true,
    62  				ValidateFunc:     validateJsonString,
    63  				DiffSuppressFunc: suppressEquivalentJsonDiffs,
    64  			},
    65  			"source_endpoint_arn": {
    66  				Type:         schema.TypeString,
    67  				Required:     true,
    68  				ForceNew:     true,
    69  				ValidateFunc: validateArn,
    70  			},
    71  			"table_mappings": {
    72  				Type:             schema.TypeString,
    73  				Required:         true,
    74  				ValidateFunc:     validateJsonString,
    75  				DiffSuppressFunc: suppressEquivalentJsonDiffs,
    76  			},
    77  			"tags": {
    78  				Type:     schema.TypeMap,
    79  				Optional: true,
    80  			},
    81  			"target_endpoint_arn": {
    82  				Type:         schema.TypeString,
    83  				Required:     true,
    84  				ForceNew:     true,
    85  				ValidateFunc: validateArn,
    86  			},
    87  		},
    88  	}
    89  }
    90  
    91  func resourceAwsDmsReplicationTaskCreate(d *schema.ResourceData, meta interface{}) error {
    92  	conn := meta.(*AWSClient).dmsconn
    93  
    94  	request := &dms.CreateReplicationTaskInput{
    95  		MigrationType:             aws.String(d.Get("migration_type").(string)),
    96  		ReplicationInstanceArn:    aws.String(d.Get("replication_instance_arn").(string)),
    97  		ReplicationTaskIdentifier: aws.String(d.Get("replication_task_id").(string)),
    98  		SourceEndpointArn:         aws.String(d.Get("source_endpoint_arn").(string)),
    99  		TableMappings:             aws.String(d.Get("table_mappings").(string)),
   100  		Tags:                      dmsTagsFromMap(d.Get("tags").(map[string]interface{})),
   101  		TargetEndpointArn:         aws.String(d.Get("target_endpoint_arn").(string)),
   102  	}
   103  
   104  	if v, ok := d.GetOk("cdc_start_time"); ok {
   105  		seconds, err := strconv.ParseInt(v.(string), 10, 64)
   106  		if err != nil {
   107  			return fmt.Errorf("[ERROR] DMS create replication task. Invalid CDC Unix timestamp: %s", err)
   108  		}
   109  		request.CdcStartTime = aws.Time(time.Unix(seconds, 0))
   110  	}
   111  
   112  	if v, ok := d.GetOk("replication_task_settings"); ok {
   113  		request.ReplicationTaskSettings = aws.String(v.(string))
   114  	}
   115  
   116  	log.Println("[DEBUG] DMS create replication task:", request)
   117  
   118  	_, err := conn.CreateReplicationTask(request)
   119  	if err != nil {
   120  		return err
   121  	}
   122  
   123  	taskId := d.Get("replication_task_id").(string)
   124  
   125  	err = waitForTaskCreated(conn, taskId, 30, 10)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	d.SetId(taskId)
   131  	return resourceAwsDmsReplicationTaskRead(d, meta)
   132  }
   133  
   134  func resourceAwsDmsReplicationTaskRead(d *schema.ResourceData, meta interface{}) error {
   135  	conn := meta.(*AWSClient).dmsconn
   136  
   137  	response, err := conn.DescribeReplicationTasks(&dms.DescribeReplicationTasksInput{
   138  		Filters: []*dms.Filter{
   139  			{
   140  				Name:   aws.String("replication-task-id"),
   141  				Values: []*string{aws.String(d.Id())}, // Must use d.Id() to work with import.
   142  			},
   143  		},
   144  	})
   145  	if err != nil {
   146  		if dmserr, ok := err.(awserr.Error); ok && dmserr.Code() == "ResourceNotFoundFault" {
   147  			d.SetId("")
   148  			return nil
   149  		}
   150  		return err
   151  	}
   152  
   153  	err = resourceAwsDmsReplicationTaskSetState(d, response.ReplicationTasks[0])
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	tagsResp, err := conn.ListTagsForResource(&dms.ListTagsForResourceInput{
   159  		ResourceArn: aws.String(d.Get("replication_task_arn").(string)),
   160  	})
   161  	if err != nil {
   162  		return err
   163  	}
   164  	d.Set("tags", dmsTagsToMap(tagsResp.TagList))
   165  
   166  	return nil
   167  }
   168  
   169  func resourceAwsDmsReplicationTaskUpdate(d *schema.ResourceData, meta interface{}) error {
   170  	conn := meta.(*AWSClient).dmsconn
   171  
   172  	request := &dms.ModifyReplicationTaskInput{
   173  		ReplicationTaskArn: aws.String(d.Get("replication_task_arn").(string)),
   174  	}
   175  	hasChanges := false
   176  
   177  	if d.HasChange("cdc_start_time") {
   178  		seconds, err := strconv.ParseInt(d.Get("cdc_start_time").(string), 10, 64)
   179  		if err != nil {
   180  			return fmt.Errorf("[ERROR] DMS update replication task. Invalid CRC Unix timestamp: %s", err)
   181  		}
   182  		request.CdcStartTime = aws.Time(time.Unix(seconds, 0))
   183  		hasChanges = true
   184  	}
   185  
   186  	if d.HasChange("migration_type") {
   187  		request.MigrationType = aws.String(d.Get("migration_type").(string))
   188  		hasChanges = true
   189  	}
   190  
   191  	if d.HasChange("replication_task_settings") {
   192  		request.ReplicationTaskSettings = aws.String(d.Get("replication_task_settings").(string))
   193  		hasChanges = true
   194  	}
   195  
   196  	if d.HasChange("table_mappings") {
   197  		request.TableMappings = aws.String(d.Get("table_mappings").(string))
   198  		hasChanges = true
   199  	}
   200  
   201  	if d.HasChange("tags") {
   202  		err := dmsSetTags(d.Get("replication_task_arn").(string), d, meta)
   203  		if err != nil {
   204  			return err
   205  		}
   206  	}
   207  
   208  	if hasChanges {
   209  		log.Println("[DEBUG] DMS update replication task:", request)
   210  
   211  		_, err := conn.ModifyReplicationTask(request)
   212  		if err != nil {
   213  			return err
   214  		}
   215  
   216  		err = waitForTaskUpdated(conn, d.Get("replication_task_id").(string), 30, 10)
   217  		if err != nil {
   218  			return err
   219  		}
   220  
   221  		return resourceAwsDmsReplicationTaskRead(d, meta)
   222  	}
   223  
   224  	return nil
   225  }
   226  
   227  func resourceAwsDmsReplicationTaskDelete(d *schema.ResourceData, meta interface{}) error {
   228  	conn := meta.(*AWSClient).dmsconn
   229  
   230  	request := &dms.DeleteReplicationTaskInput{
   231  		ReplicationTaskArn: aws.String(d.Get("replication_task_arn").(string)),
   232  	}
   233  
   234  	log.Printf("[DEBUG] DMS delete replication task: %#v", request)
   235  
   236  	_, err := conn.DeleteReplicationTask(request)
   237  	if err != nil {
   238  		return err
   239  	}
   240  
   241  	waitErr := waitForTaskDeleted(conn, d.Get("replication_task_id").(string), 30, 10)
   242  	if waitErr != nil {
   243  		return waitErr
   244  	}
   245  
   246  	return nil
   247  }
   248  
   249  func resourceAwsDmsReplicationTaskSetState(d *schema.ResourceData, task *dms.ReplicationTask) error {
   250  	d.SetId(*task.ReplicationTaskIdentifier)
   251  
   252  	d.Set("migration_type", task.MigrationType)
   253  	d.Set("replication_instance_arn", task.ReplicationInstanceArn)
   254  	d.Set("replication_task_arn", task.ReplicationTaskArn)
   255  	d.Set("replication_task_id", task.ReplicationTaskIdentifier)
   256  	d.Set("replication_task_settings", task.ReplicationTaskSettings)
   257  	d.Set("source_endpoint_arn", task.SourceEndpointArn)
   258  	d.Set("table_mappings", task.TableMappings)
   259  	d.Set("target_endpoint_arn", task.TargetEndpointArn)
   260  
   261  	return nil
   262  }
   263  
   264  func waitForTaskCreated(client *dms.DatabaseMigrationService, id string, delay int, maxAttempts int) error {
   265  	input := &dms.DescribeReplicationTasksInput{
   266  		Filters: []*dms.Filter{
   267  			{
   268  				Name:   aws.String("replication-task-id"),
   269  				Values: []*string{aws.String(id)},
   270  			},
   271  		},
   272  	}
   273  
   274  	config := waiter.Config{
   275  		Operation:   "DescribeReplicationTasks",
   276  		Delay:       delay,
   277  		MaxAttempts: maxAttempts,
   278  		Acceptors: []waiter.WaitAcceptor{
   279  			{
   280  				State:    "retry",
   281  				Matcher:  "pathAll",
   282  				Argument: "ReplicationTasks[].Status",
   283  				Expected: "creating",
   284  			},
   285  			{
   286  				State:    "success",
   287  				Matcher:  "pathAll",
   288  				Argument: "ReplicationTasks[].Status",
   289  				Expected: "ready",
   290  			},
   291  		},
   292  	}
   293  
   294  	w := waiter.Waiter{
   295  		Client: client,
   296  		Input:  input,
   297  		Config: config,
   298  	}
   299  
   300  	return w.Wait()
   301  }
   302  
   303  func waitForTaskUpdated(client *dms.DatabaseMigrationService, id string, delay int, maxAttempts int) error {
   304  	input := &dms.DescribeReplicationTasksInput{
   305  		Filters: []*dms.Filter{
   306  			{
   307  				Name:   aws.String("replication-task-id"),
   308  				Values: []*string{aws.String(id)},
   309  			},
   310  		},
   311  	}
   312  
   313  	config := waiter.Config{
   314  		Operation:   "DescribeReplicationTasks",
   315  		Delay:       delay,
   316  		MaxAttempts: maxAttempts,
   317  		Acceptors: []waiter.WaitAcceptor{
   318  			{
   319  				State:    "retry",
   320  				Matcher:  "pathAll",
   321  				Argument: "ReplicationTasks[].Status",
   322  				Expected: "modifying",
   323  			},
   324  			{
   325  				State:    "success",
   326  				Matcher:  "pathAll",
   327  				Argument: "ReplicationTasks[].Status",
   328  				Expected: "ready",
   329  			},
   330  		},
   331  	}
   332  
   333  	w := waiter.Waiter{
   334  		Client: client,
   335  		Input:  input,
   336  		Config: config,
   337  	}
   338  
   339  	return w.Wait()
   340  }
   341  
   342  func waitForTaskDeleted(client *dms.DatabaseMigrationService, id string, delay int, maxAttempts int) error {
   343  	input := &dms.DescribeReplicationTasksInput{
   344  		Filters: []*dms.Filter{
   345  			{
   346  				Name:   aws.String("replication-task-id"),
   347  				Values: []*string{aws.String(id)},
   348  			},
   349  		},
   350  	}
   351  
   352  	config := waiter.Config{
   353  		Operation:   "DescribeReplicationTasks",
   354  		Delay:       delay,
   355  		MaxAttempts: maxAttempts,
   356  		Acceptors: []waiter.WaitAcceptor{
   357  			{
   358  				State:    "retry",
   359  				Matcher:  "pathAll",
   360  				Argument: "ReplicationTasks[].Status",
   361  				Expected: "deleting",
   362  			},
   363  			{
   364  				State:    "success",
   365  				Matcher:  "path",
   366  				Argument: "length(ReplicationTasks[]) > `0`",
   367  				Expected: false,
   368  			},
   369  		},
   370  	}
   371  
   372  	w := waiter.Waiter{
   373  		Client: client,
   374  		Input:  input,
   375  		Config: config,
   376  	}
   377  
   378  	return w.Wait()
   379  }