github.com/adrian-bl/terraform@v0.7.0-rc2.0.20160705220747-de0a34fc3517/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 21 Schema: map[string]*schema.Schema{ 22 "identifier": &schema.Schema{ 23 Type: schema.TypeString, 24 Optional: true, 25 ForceNew: true, 26 ValidateFunc: validateRdsId, 27 }, 28 29 "db_subnet_group_name": &schema.Schema{ 30 Type: schema.TypeString, 31 Optional: true, 32 ForceNew: true, 33 Computed: true, 34 }, 35 36 "writer": &schema.Schema{ 37 Type: schema.TypeBool, 38 Computed: true, 39 }, 40 41 "cluster_identifier": &schema.Schema{ 42 Type: schema.TypeString, 43 Required: true, 44 ForceNew: true, 45 }, 46 47 "endpoint": &schema.Schema{ 48 Type: schema.TypeString, 49 Computed: true, 50 }, 51 52 "port": &schema.Schema{ 53 Type: schema.TypeInt, 54 Computed: true, 55 }, 56 57 "publicly_accessible": &schema.Schema{ 58 Type: schema.TypeBool, 59 Optional: true, 60 Default: false, 61 }, 62 63 "instance_class": &schema.Schema{ 64 Type: schema.TypeString, 65 Required: true, 66 }, 67 68 "db_parameter_group_name": &schema.Schema{ 69 Type: schema.TypeString, 70 Optional: true, 71 Computed: true, 72 }, 73 74 // apply_immediately is used to determine when the update modifications 75 // take place. 76 // See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html 77 "apply_immediately": &schema.Schema{ 78 Type: schema.TypeBool, 79 Optional: true, 80 Computed: true, 81 }, 82 83 "tags": tagsSchema(), 84 }, 85 } 86 } 87 88 func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{}) error { 89 conn := meta.(*AWSClient).rdsconn 90 tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) 91 92 createOpts := &rds.CreateDBInstanceInput{ 93 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 94 DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)), 95 Engine: aws.String("aurora"), 96 PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)), 97 Tags: tags, 98 } 99 100 if attr, ok := d.GetOk("db_parameter_group_name"); ok { 101 createOpts.DBParameterGroupName = aws.String(attr.(string)) 102 } 103 104 if v := d.Get("identifier").(string); v != "" { 105 createOpts.DBInstanceIdentifier = aws.String(v) 106 } else { 107 createOpts.DBInstanceIdentifier = aws.String(resource.UniqueId()) 108 } 109 110 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 111 createOpts.DBSubnetGroupName = aws.String(attr.(string)) 112 } 113 114 log.Printf("[DEBUG] Creating RDS DB Instance opts: %s", createOpts) 115 resp, err := conn.CreateDBInstance(createOpts) 116 if err != nil { 117 return err 118 } 119 120 d.SetId(*resp.DBInstance.DBInstanceIdentifier) 121 122 // reuse db_instance refresh func 123 stateConf := &resource.StateChangeConf{ 124 Pending: []string{"creating", "backing-up", "modifying"}, 125 Target: []string{"available"}, 126 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 127 Timeout: 40 * time.Minute, 128 MinTimeout: 10 * time.Second, 129 Delay: 10 * time.Second, 130 } 131 132 // Wait, catching any errors 133 _, err = stateConf.WaitForState() 134 if err != nil { 135 return err 136 } 137 138 return resourceAwsRDSClusterInstanceRead(d, meta) 139 } 140 141 func resourceAwsRDSClusterInstanceRead(d *schema.ResourceData, meta interface{}) error { 142 db, err := resourceAwsDbInstanceRetrieve(d, meta) 143 // Errors from this helper are always reportable 144 if err != nil { 145 return fmt.Errorf("[WARN] Error on retrieving RDS Cluster Instance (%s): %s", d.Id(), err) 146 } 147 // A nil response means "not found" 148 if db == nil { 149 log.Printf("[WARN] RDS Cluster Instance (%s): not found, removing from state.", d.Id()) 150 d.SetId("") 151 return nil 152 } 153 154 // Retreive DB Cluster information, to determine if this Instance is a writer 155 conn := meta.(*AWSClient).rdsconn 156 resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{ 157 DBClusterIdentifier: db.DBClusterIdentifier, 158 }) 159 160 var dbc *rds.DBCluster 161 for _, c := range resp.DBClusters { 162 if *c.DBClusterIdentifier == *db.DBClusterIdentifier { 163 dbc = c 164 } 165 } 166 167 if dbc == nil { 168 return fmt.Errorf("[WARN] Error finding RDS Cluster (%s) for Cluster Instance (%s): %s", 169 *db.DBClusterIdentifier, *db.DBInstanceIdentifier, err) 170 } 171 172 for _, m := range dbc.DBClusterMembers { 173 if *db.DBInstanceIdentifier == *m.DBInstanceIdentifier { 174 if *m.IsClusterWriter == true { 175 d.Set("writer", true) 176 } else { 177 d.Set("writer", false) 178 } 179 } 180 } 181 182 if db.Endpoint != nil { 183 d.Set("endpoint", db.Endpoint.Address) 184 d.Set("port", db.Endpoint.Port) 185 } 186 187 d.Set("publicly_accessible", db.PubliclyAccessible) 188 189 if len(db.DBParameterGroups) > 0 { 190 d.Set("parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName) 191 } 192 193 // Fetch and save tags 194 arn, err := buildRDSARN(d.Id(), meta) 195 if err != nil { 196 log.Printf("[DEBUG] Error building ARN for RDS Cluster Instance (%s), not setting Tags", *db.DBInstanceIdentifier) 197 } else { 198 if err := saveTagsRDS(conn, d, arn); err != nil { 199 log.Printf("[WARN] Failed to save tags for RDS Cluster Instance (%s): %s", *db.DBClusterIdentifier, err) 200 } 201 } 202 203 return nil 204 } 205 206 func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{}) error { 207 conn := meta.(*AWSClient).rdsconn 208 requestUpdate := false 209 210 req := &rds.ModifyDBInstanceInput{ 211 ApplyImmediately: aws.Bool(d.Get("apply_immediately").(bool)), 212 DBInstanceIdentifier: aws.String(d.Id()), 213 } 214 215 if d.HasChange("db_parameter_group_name") { 216 req.DBParameterGroupName = aws.String(d.Get("db_parameter_group_name").(string)) 217 requestUpdate = true 218 219 } 220 221 if d.HasChange("instance_class") { 222 req.DBInstanceClass = aws.String(d.Get("instance_class").(string)) 223 requestUpdate = true 224 225 } 226 227 log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate) 228 if requestUpdate { 229 log.Printf("[DEBUG] DB Instance Modification request: %#v", req) 230 _, err := conn.ModifyDBInstance(req) 231 if err != nil { 232 return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err) 233 } 234 235 // reuse db_instance refresh func 236 stateConf := &resource.StateChangeConf{ 237 Pending: []string{"creating", "backing-up", "modifying"}, 238 Target: []string{"available"}, 239 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 240 Timeout: 40 * time.Minute, 241 MinTimeout: 10 * time.Second, 242 Delay: 10 * time.Second, 243 } 244 245 // Wait, catching any errors 246 _, err = stateConf.WaitForState() 247 if err != nil { 248 return err 249 } 250 251 } 252 253 if arn, err := buildRDSARN(d.Id(), meta); err == nil { 254 if err := setTagsRDS(conn, d, arn); err != nil { 255 return err 256 } 257 } 258 259 return resourceAwsRDSClusterInstanceRead(d, meta) 260 } 261 262 func resourceAwsRDSClusterInstanceDelete(d *schema.ResourceData, meta interface{}) error { 263 conn := meta.(*AWSClient).rdsconn 264 265 log.Printf("[DEBUG] RDS Cluster Instance destroy: %v", d.Id()) 266 267 opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())} 268 269 log.Printf("[DEBUG] RDS Cluster Instance destroy configuration: %s", opts) 270 if _, err := conn.DeleteDBInstance(&opts); err != nil { 271 return err 272 } 273 274 // re-uses db_instance refresh func 275 log.Println("[INFO] Waiting for RDS Cluster Instance to be destroyed") 276 stateConf := &resource.StateChangeConf{ 277 Pending: []string{"modifying", "deleting"}, 278 Target: []string{}, 279 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 280 Timeout: 40 * time.Minute, 281 MinTimeout: 10 * time.Second, 282 } 283 284 if _, err := stateConf.WaitForState(); err != nil { 285 return err 286 } 287 288 return nil 289 290 }