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