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 }