github.com/gabrielperezs/terraform@v0.7.0-rc2.0.20160715084931-f7da2612946f/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 "tags": tagsSchema(), 87 }, 88 } 89 } 90 91 func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{}) error { 92 conn := meta.(*AWSClient).rdsconn 93 tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) 94 95 createOpts := &rds.CreateDBInstanceInput{ 96 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 97 DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), 98 Engine: aws.String("aurora"), 99 PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)), 100 Tags: tags, 101 } 102 103 if attr, ok := d.GetOk("db_parameter_group_name"); ok { 104 createOpts.DBParameterGroupName = aws.String(attr.(string)) 105 } 106 107 if v := d.Get("identifier").(string); v != "" { 108 createOpts.DBInstanceIdentifier = aws.String(v) 109 } else { 110 createOpts.DBInstanceIdentifier = aws.String(resource.UniqueId()) 111 } 112 113 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 114 createOpts.DBSubnetGroupName = aws.String(attr.(string)) 115 } 116 117 log.Printf("[DEBUG] Creating RDS DB Instance opts: %s", createOpts) 118 resp, err := conn.CreateDBInstance(createOpts) 119 if err != nil { 120 return err 121 } 122 123 d.SetId(*resp.DBInstance.DBInstanceIdentifier) 124 125 // reuse db_instance refresh func 126 stateConf := &resource.StateChangeConf{ 127 Pending: []string{"creating", "backing-up", "modifying"}, 128 Target: []string{"available"}, 129 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 130 Timeout: 40 * time.Minute, 131 MinTimeout: 10 * time.Second, 132 Delay: 10 * time.Second, 133 } 134 135 // Wait, catching any errors 136 _, err = stateConf.WaitForState() 137 if err != nil { 138 return err 139 } 140 141 return resourceAwsRDSClusterInstanceRead(d, meta) 142 } 143 144 func resourceAwsRDSClusterInstanceRead(d *schema.ResourceData, meta interface{}) error { 145 db, err := resourceAwsDbInstanceRetrieve(d, meta) 146 // Errors from this helper are always reportable 147 if err != nil { 148 return fmt.Errorf("[WARN] Error on retrieving RDS Cluster Instance (%s): %s", d.Id(), err) 149 } 150 // A nil response means "not found" 151 if db == nil { 152 log.Printf("[WARN] RDS Cluster Instance (%s): not found, removing from state.", d.Id()) 153 d.SetId("") 154 return nil 155 } 156 157 // Retreive DB Cluster information, to determine if this Instance is a writer 158 conn := meta.(*AWSClient).rdsconn 159 resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{ 160 DBClusterIdentifier: db.DBClusterIdentifier, 161 }) 162 163 var dbc *rds.DBCluster 164 for _, c := range resp.DBClusters { 165 if *c.DBClusterIdentifier == *db.DBClusterIdentifier { 166 dbc = c 167 } 168 } 169 170 if dbc == nil { 171 return fmt.Errorf("[WARN] Error finding RDS Cluster (%s) for Cluster Instance (%s): %s", 172 *db.DBClusterIdentifier, *db.DBInstanceIdentifier, err) 173 } 174 175 for _, m := range dbc.DBClusterMembers { 176 if *db.DBInstanceIdentifier == *m.DBInstanceIdentifier { 177 if *m.IsClusterWriter == true { 178 d.Set("writer", true) 179 } else { 180 d.Set("writer", false) 181 } 182 } 183 } 184 185 if db.Endpoint != nil { 186 d.Set("endpoint", db.Endpoint.Address) 187 d.Set("port", db.Endpoint.Port) 188 } 189 190 d.Set("publicly_accessible", db.PubliclyAccessible) 191 d.Set("cluster_identifier", db.DBClusterIdentifier) 192 d.Set("instance_class", db.DBInstanceClass) 193 d.Set("identifier", db.DBInstanceIdentifier) 194 195 if len(db.DBParameterGroups) > 0 { 196 d.Set("db_parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName) 197 } 198 199 // Fetch and save tags 200 arn, err := buildRDSARN(d.Id(), meta) 201 if err != nil { 202 log.Printf("[DEBUG] Error building ARN for RDS Cluster Instance (%s), not setting Tags", *db.DBInstanceIdentifier) 203 } else { 204 if err := saveTagsRDS(conn, d, arn); err != nil { 205 log.Printf("[WARN] Failed to save tags for RDS Cluster Instance (%s): %s", *db.DBClusterIdentifier, err) 206 } 207 } 208 209 return nil 210 } 211 212 func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 213 conn := meta.(*AWSClient).rdsconn 214 requestUpdate := false 215 216 req := &rds.ModifyDBInstanceInput{ 217 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 218 DBInstanceIdentifier: aws.String(d.Id()), 219 } 220 221 if d.HasChange("db_parameter_group_name") { 222 req.DBParameterGroupName = aws.String(d.Get("db_parameter_group_name").(string)) 223 requestUpdate = true 224 225 } 226 227 if d.HasChange("instance_class") { 228 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 229 requestUpdate = true 230 231 } 232 233 log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) 234 if requestUpdate { 235 log.Printf("[DEBUG] DB Instance Modification request: %#v", req) 236 _, err := conn.ModifyDBInstance(req) 237 if err != nil { 238 return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) 239 } 240 241 // reuse db_instance refresh func 242 stateConf := &resource.StateChangeConf{ 243 Pending: []string{"creating", "backing-up", "modifying"}, 244 Target: []string{"available"}, 245 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 246 Timeout: 40 * time.Minute, 247 MinTimeout: 10 * time.Second, 248 Delay: 10 * time.Second, 249 } 250 251 // Wait, catching any errors 252 _, err = stateConf.WaitForState() 253 if err != nil { 254 return err 255 } 256 257 } 258 259 if arn, err := buildRDSARN(d.Id(), meta); err == nil { 260 if err := setTagsRDS(conn, d, arn); err != nil { 261 return err 262 } 263 } 264 265 return resourceAwsRDSClusterInstanceRead(d, meta) 266 } 267 268 func resourceAwsRDSClusterInstanceDelete(d *schema.ResourceData, meta interface{}) error { 269 conn := meta.(*AWSClient).rdsconn 270 271 log.Printf("[DEBUG] RDS Cluster Instance destroy: %v", d.Id()) 272 273 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 274 275 log.Printf("[DEBUG] RDS Cluster Instance destroy configuration: %s", opts) 276 if _, err := conn.DeleteDBInstance(&opts); err != nil { 277 return err 278 } 279 280 // re-uses db_instance refresh func 281 log.Println("[INFO] Waiting for RDS Cluster Instance to be destroyed") 282 stateConf := &resource.StateChangeConf{ 283 Pending: []string{"modifying", "deleting"}, 284 Target: []string{}, 285 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 286 Timeout: 40 * time.Minute, 287 MinTimeout: 10 * time.Second, 288 } 289 290 if _, err := stateConf.WaitForState(); err != nil { 291 return err 292 } 293 294 return nil 295 296 }