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