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 }