github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_rds_cluster_instance.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/service/rds" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 ) 14 15 func resourceAwsRDSClusterInstance() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAwsRDSClusterInstanceCreate, 18 Read: resourceAwsRDSClusterInstanceRead, 19 Update: resourceAwsRDSClusterInstanceUpdate, 20 Delete: resourceAwsRDSClusterInstanceDelete, 21 Importer: &schema.ResourceImporter{ 22 State: schema.ImportStatePassthrough, 23 }, 24 25 Schema: map[string]*schema.Schema{ 26 "identifier": { 27 Type: schema.TypeString, 28 Optional: true, 29 Computed: true, 30 ForceNew: true, 31 ConflictsWith: []string{"identifier_prefix"}, 32 ValidateFunc: validateRdsIdentifier, 33 }, 34 "identifier_prefix": { 35 Type: schema.TypeString, 36 Optional: true, 37 Computed: true, 38 ForceNew: true, 39 ValidateFunc: validateRdsIdentifierPrefix, 40 }, 41 42 "db_subnet_group_name": { 43 Type: schema.TypeString, 44 Optional: true, 45 ForceNew: true, 46 Computed: true, 47 }, 48 49 "writer": { 50 Type: schema.TypeBool, 51 Computed: true, 52 }, 53 54 "cluster_identifier": { 55 Type: schema.TypeString, 56 Required: true, 57 ForceNew: true, 58 }, 59 60 "endpoint": { 61 Type: schema.TypeString, 62 Computed: true, 63 }, 64 65 "port": { 66 Type: schema.TypeInt, 67 Computed: true, 68 }, 69 70 "publicly_accessible": { 71 Type: schema.TypeBool, 72 Optional: true, 73 Default: false, 74 }, 75 76 "instance_class": { 77 Type: schema.TypeString, 78 Required: true, 79 }, 80 81 "db_parameter_group_name": { 82 Type: schema.TypeString, 83 Optional: true, 84 Computed: true, 85 }, 86 87 // apply_immediately is used to determine when the update modifications 88 // take place. 89 // See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html 90 "apply_immediately": { 91 Type: schema.TypeBool, 92 Optional: true, 93 Computed: true, 94 }, 95 96 "kms_key_id": { 97 Type: schema.TypeString, 98 Computed: true, 99 }, 100 101 "storage_encrypted": { 102 Type: schema.TypeBool, 103 Computed: true, 104 }, 105 106 "auto_minor_version_upgrade": { 107 Type: schema.TypeBool, 108 Optional: true, 109 Default: true, 110 }, 111 112 "monitoring_role_arn": { 113 Type: schema.TypeString, 114 Optional: true, 115 Computed: true, 116 }, 117 118 "preferred_maintenance_window": { 119 Type: schema.TypeString, 120 Optional: true, 121 Computed: true, 122 StateFunc: func(v interface{}) string { 123 if v != nil { 124 value := v.(string) 125 return strings.ToLower(value) 126 } 127 return "" 128 }, 129 ValidateFunc: validateOnceAWeekWindowFormat, 130 }, 131 132 "preferred_backup_window": { 133 Type: schema.TypeString, 134 Optional: true, 135 Computed: true, 136 ValidateFunc: validateOnceADayWindowFormat, 137 }, 138 139 "monitoring_interval": { 140 Type: schema.TypeInt, 141 Optional: true, 142 Default: 0, 143 }, 144 145 "promotion_tier": { 146 Type: schema.TypeInt, 147 Optional: true, 148 Default: 0, 149 }, 150 151 "tags": tagsSchema(), 152 }, 153 } 154 } 155 156 func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{}) error { 157 conn := meta.(*AWSClient).rdsconn 158 tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) 159 160 createOpts := &rds.CreateDBInstanceInput{ 161 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 162 DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), 163 Engine: aws.String("aurora"), 164 PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)), 165 PromotionTier: aws.Int64(int64(d.Get("promotion_tier").(int))), 166 AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)), 167 Tags: tags, 168 } 169 170 if attr, ok := d.GetOk("db_parameter_group_name"); ok { 171 createOpts.DBParameterGroupName = aws.String(attr.(string)) 172 } 173 174 if v, ok := d.GetOk("identifier"); ok { 175 createOpts.DBInstanceIdentifier = aws.String(v.(string)) 176 } else { 177 if v, ok := d.GetOk("identifier_prefix"); ok { 178 createOpts.DBInstanceIdentifier = aws.String(resource.PrefixedUniqueId(v.(string))) 179 } else { 180 createOpts.DBInstanceIdentifier = aws.String(resource.PrefixedUniqueId("tf-")) 181 } 182 } 183 184 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 185 createOpts.DBSubnetGroupName = aws.String(attr.(string)) 186 } 187 188 if attr, ok := d.GetOk("monitoring_role_arn"); ok { 189 createOpts.MonitoringRoleArn = aws.String(attr.(string)) 190 } 191 192 if attr, ok := d.GetOk("preferred_backup_window"); ok { 193 createOpts.PreferredBackupWindow = aws.String(attr.(string)) 194 } 195 196 if attr, ok := d.GetOk("preferred_maintenance_window"); ok { 197 createOpts.PreferredMaintenanceWindow = aws.String(attr.(string)) 198 } 199 200 if attr, ok := d.GetOk("monitoring_interval"); ok { 201 createOpts.MonitoringInterval = aws.Int64(int64(attr.(int))) 202 } 203 204 log.Printf("[DEBUG] Creating RDS DB Instance opts: %s", createOpts) 205 resp, err := conn.CreateDBInstance(createOpts) 206 if err != nil { 207 return err 208 } 209 210 d.SetId(*resp.DBInstance.DBInstanceIdentifier) 211 212 // reuse db_instance refresh func 213 stateConf := &resource.StateChangeConf{ 214 Pending: []string{"creating", "backing-up", "modifying"}, 215 Target: []string{"available"}, 216 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 217 Timeout: 40 * time.Minute, 218 MinTimeout: 10 * time.Second, 219 Delay: 10 * time.Second, 220 } 221 222 // Wait, catching any errors 223 _, err = stateConf.WaitForState() 224 if err != nil { 225 return err 226 } 227 228 return resourceAwsRDSClusterInstanceRead(d, meta) 229 } 230 231 func resourceAwsRDSClusterInstanceRead(d *schema.ResourceData, meta interface{}) error { 232 db, err := resourceAwsDbInstanceRetrieve(d, meta) 233 // Errors from this helper are always reportable 234 if err != nil { 235 return fmt.Errorf("[WARN] Error on retrieving RDS Cluster Instance (%s): %s", d.Id(), err) 236 } 237 // A nil response means "not found" 238 if db == nil { 239 log.Printf("[WARN] RDS Cluster Instance (%s): not found, removing from state.", d.Id()) 240 d.SetId("") 241 return nil 242 } 243 244 // Retrieve DB Cluster information, to determine if this Instance is a writer 245 conn := meta.(*AWSClient).rdsconn 246 resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{ 247 DBClusterIdentifier: db.DBClusterIdentifier, 248 }) 249 250 var dbc *rds.DBCluster 251 for _, c := range resp.DBClusters { 252 if *c.DBClusterIdentifier == *db.DBClusterIdentifier { 253 dbc = c 254 } 255 } 256 257 if dbc == nil { 258 return fmt.Errorf("[WARN] Error finding RDS Cluster (%s) for Cluster Instance (%s): %s", 259 *db.DBClusterIdentifier, *db.DBInstanceIdentifier, err) 260 } 261 262 for _, m := range dbc.DBClusterMembers { 263 if *db.DBInstanceIdentifier == *m.DBInstanceIdentifier { 264 if *m.IsClusterWriter == true { 265 d.Set("writer", true) 266 } else { 267 d.Set("writer", false) 268 } 269 } 270 } 271 272 if db.Endpoint != nil { 273 d.Set("endpoint", db.Endpoint.Address) 274 d.Set("port", db.Endpoint.Port) 275 } 276 277 d.Set("publicly_accessible", db.PubliclyAccessible) 278 d.Set("cluster_identifier", db.DBClusterIdentifier) 279 d.Set("instance_class", db.DBInstanceClass) 280 d.Set("identifier", db.DBInstanceIdentifier) 281 d.Set("storage_encrypted", db.StorageEncrypted) 282 d.Set("kms_key_id", db.KmsKeyId) 283 d.Set("auto_minor_version_upgrade", db.AutoMinorVersionUpgrade) 284 d.Set("promotion_tier", db.PromotionTier) 285 d.Set("preferred_backup_window", db.PreferredBackupWindow) 286 d.Set("preferred_maintenance_window", db.PreferredMaintenanceWindow) 287 288 if db.MonitoringInterval != nil { 289 d.Set("monitoring_interval", db.MonitoringInterval) 290 } 291 292 if db.MonitoringRoleArn != nil { 293 d.Set("monitoring_role_arn", db.MonitoringRoleArn) 294 } 295 296 if len(db.DBParameterGroups) > 0 { 297 d.Set("db_parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName) 298 } 299 300 // Fetch and save tags 301 arn, err := buildRDSARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region) 302 if err != nil { 303 log.Printf("[DEBUG] Error building ARN for RDS Cluster Instance (%s), not setting Tags", *db.DBInstanceIdentifier) 304 } else { 305 if err := saveTagsRDS(conn, d, arn); err != nil { 306 log.Printf("[WARN] Failed to save tags for RDS Cluster Instance (%s): %s", *db.DBClusterIdentifier, err) 307 } 308 } 309 310 return nil 311 } 312 313 func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 314 conn := meta.(*AWSClient).rdsconn 315 requestUpdate := false 316 317 req := &rds.ModifyDBInstanceInput{ 318 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 319 DBInstanceIdentifier: aws.String(d.Id()), 320 } 321 322 if d.HasChange("db_parameter_group_name") { 323 req.DBParameterGroupName = aws.String(d.Get("db_parameter_group_name").(string)) 324 requestUpdate = true 325 } 326 327 if d.HasChange("instance_class") { 328 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 329 requestUpdate = true 330 } 331 332 if d.HasChange("monitoring_role_arn") { 333 d.SetPartial("monitoring_role_arn") 334 req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string)) 335 requestUpdate = true 336 } 337 338 if d.HasChange("preferred_backup_window") { 339 d.SetPartial("preferred_backup_window") 340 req.PreferredBackupWindow = aws.String(d.Get("preferred_backup_window").(string)) 341 requestUpdate = true 342 } 343 344 if d.HasChange("preferred_maintenance_window") { 345 d.SetPartial("preferred_maintenance_window") 346 req.PreferredMaintenanceWindow = aws.String(d.Get("preferred_maintenance_window").(string)) 347 requestUpdate = true 348 } 349 350 if d.HasChange("monitoring_interval") { 351 d.SetPartial("monitoring_interval") 352 req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int))) 353 requestUpdate = true 354 } 355 356 if d.HasChange("auto_minor_version_upgrade") { 357 d.SetPartial("auto_minor_version_upgrade") 358 req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool)) 359 requestUpdate = true 360 } 361 362 if d.HasChange("promotion_tier") { 363 d.SetPartial("promotion_tier") 364 req.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int))) 365 requestUpdate = true 366 } 367 368 log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) 369 if requestUpdate { 370 log.Printf("[DEBUG] DB Instance Modification request: %#v", req) 371 _, err := conn.ModifyDBInstance(req) 372 if err != nil { 373 return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) 374 } 375 376 // reuse db_instance refresh func 377 stateConf := &resource.StateChangeConf{ 378 Pending: []string{"creating", "backing-up", "modifying"}, 379 Target: []string{"available"}, 380 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 381 Timeout: 40 * time.Minute, 382 MinTimeout: 10 * time.Second, 383 Delay: 10 * time.Second, 384 } 385 386 // Wait, catching any errors 387 _, err = stateConf.WaitForState() 388 if err != nil { 389 return err 390 } 391 392 } 393 394 if arn, err := buildRDSARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil { 395 if err := setTagsRDS(conn, d, arn); err != nil { 396 return err 397 } 398 } 399 400 return resourceAwsRDSClusterInstanceRead(d, meta) 401 } 402 403 func resourceAwsRDSClusterInstanceDelete(d *schema.ResourceData, meta interface{}) error { 404 conn := meta.(*AWSClient).rdsconn 405 406 log.Printf("[DEBUG] RDS Cluster Instance destroy: %v", d.Id()) 407 408 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 409 410 log.Printf("[DEBUG] RDS Cluster Instance destroy configuration: %s", opts) 411 if _, err := conn.DeleteDBInstance(&opts); err != nil { 412 return err 413 } 414 415 // re-uses db_instance refresh func 416 log.Println("[INFO] Waiting for RDS Cluster Instance to be destroyed") 417 stateConf := &resource.StateChangeConf{ 418 Pending: []string{"modifying", "deleting"}, 419 Target: []string{}, 420 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 421 Timeout: 40 * time.Minute, 422 MinTimeout: 10 * time.Second, 423 } 424 425 if _, err := stateConf.WaitForState(); err != nil { 426 return err 427 } 428 429 return nil 430 431 }