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