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