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