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