github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/builtin/providers/aws/resource_aws_db_instance.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 "time" 8 9 "github.com/hashicorp/terraform/flatmap" 10 "github.com/hashicorp/terraform/helper/config" 11 "github.com/hashicorp/terraform/helper/diff" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/terraform" 14 "github.com/mitchellh/goamz/rds" 15 ) 16 17 func resource_aws_db_instance_create( 18 s *terraform.ResourceState, 19 d *terraform.ResourceDiff, 20 meta interface{}) (*terraform.ResourceState, error) { 21 p := meta.(*ResourceProvider) 22 conn := p.rdsconn 23 24 // Merge the diff into the state so that we have all the attributes 25 // properly. 26 rs := s.MergeDiff(d) 27 28 var err error 29 var attr string 30 31 opts := rds.CreateDBInstance{} 32 33 if attr = rs.Attributes["allocated_storage"]; attr != "" { 34 opts.AllocatedStorage, err = strconv.Atoi(attr) 35 opts.SetAllocatedStorage = true 36 } 37 38 if attr = rs.Attributes["backup_retention_period"]; attr != "" { 39 opts.BackupRetentionPeriod, err = strconv.Atoi(attr) 40 opts.SetBackupRetentionPeriod = true 41 } 42 43 if attr = rs.Attributes["iops"]; attr != "" { 44 opts.Iops, err = strconv.Atoi(attr) 45 opts.SetIops = true 46 } 47 48 if attr = rs.Attributes["port"]; attr != "" { 49 opts.Port, err = strconv.Atoi(attr) 50 opts.SetPort = true 51 } 52 53 if attr = rs.Attributes["availability_zone"]; attr != "" { 54 opts.AvailabilityZone = attr 55 } 56 57 if attr = rs.Attributes["instance_class"]; attr != "" { 58 opts.DBInstanceClass = attr 59 } 60 61 if attr = rs.Attributes["maintenance_window"]; attr != "" { 62 opts.PreferredMaintenanceWindow = attr 63 } 64 65 if attr = rs.Attributes["backup_window"]; attr != "" { 66 opts.PreferredBackupWindow = attr 67 } 68 69 if attr = rs.Attributes["multi_az"]; attr == "true" { 70 opts.MultiAZ = true 71 } 72 73 if attr = rs.Attributes["publicly_accessible"]; attr == "true" { 74 opts.PubliclyAccessible = true 75 } 76 77 if err != nil { 78 return nil, fmt.Errorf("Error parsing configuration: %s", err) 79 } 80 81 if _, ok := rs.Attributes["vpc_security_group_ids.#"]; ok { 82 opts.VpcSecurityGroupIds = expandStringList(flatmap.Expand( 83 rs.Attributes, "vpc_security_group_ids").([]interface{})) 84 } 85 86 if _, ok := rs.Attributes["security_group_names.#"]; ok { 87 opts.DBSecurityGroupNames = expandStringList(flatmap.Expand( 88 rs.Attributes, "security_group_names").([]interface{})) 89 } 90 91 opts.DBInstanceIdentifier = rs.Attributes["identifier"] 92 opts.DBName = rs.Attributes["name"] 93 opts.MasterUsername = rs.Attributes["username"] 94 opts.MasterUserPassword = rs.Attributes["password"] 95 opts.EngineVersion = rs.Attributes["engine_version"] 96 opts.EngineVersion = rs.Attributes["engine"] 97 98 // Don't keep the password around in the state 99 delete(rs.Attributes, "password") 100 101 log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) 102 _, err = conn.CreateDBInstance(&opts) 103 if err != nil { 104 return nil, fmt.Errorf("Error creating DB Instance: %s", err) 105 } 106 107 rs.ID = rs.Attributes["identifier"] 108 109 log.Printf("[INFO] DB Instance ID: %s", rs.ID) 110 111 log.Println( 112 "[INFO] Waiting for DB Instance to be available") 113 114 stateConf := &resource.StateChangeConf{ 115 Pending: []string{"creating", "backing-up"}, 116 Target: "available", 117 Refresh: DBInstanceStateRefreshFunc(rs.ID, conn), 118 Timeout: 10 * time.Minute, 119 MinTimeout: 10 * time.Second, 120 Delay: 30 * time.Second, // Wait 30 secs before starting 121 } 122 123 // Wait, catching any errors 124 _, err = stateConf.WaitForState() 125 if err != nil { 126 return rs, err 127 } 128 129 v, err := resource_aws_db_instance_retrieve(rs.ID, conn) 130 if err != nil { 131 return rs, err 132 } 133 134 return resource_aws_db_instance_update_state(rs, v) 135 } 136 137 func resource_aws_db_instance_update( 138 s *terraform.ResourceState, 139 d *terraform.ResourceDiff, 140 meta interface{}) (*terraform.ResourceState, error) { 141 142 panic("Cannot update DB") 143 144 return nil, nil 145 } 146 147 func resource_aws_db_instance_destroy( 148 s *terraform.ResourceState, 149 meta interface{}) error { 150 p := meta.(*ResourceProvider) 151 conn := p.rdsconn 152 153 log.Printf("[DEBUG] DB Instance destroy: %v", s.ID) 154 155 opts := rds.DeleteDBInstance{DBInstanceIdentifier: s.ID} 156 157 if s.Attributes["skip_final_snapshot"] == "true" { 158 opts.SkipFinalSnapshot = true 159 } 160 161 log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts) 162 _, err := conn.DeleteDBInstance(&opts) 163 164 if err != nil { 165 newerr, ok := err.(*rds.Error) 166 if ok && newerr.Code == "InvalidDBInstance.NotFound" { 167 return nil 168 } 169 return err 170 } 171 172 return nil 173 } 174 175 func resource_aws_db_instance_refresh( 176 s *terraform.ResourceState, 177 meta interface{}) (*terraform.ResourceState, error) { 178 p := meta.(*ResourceProvider) 179 conn := p.rdsconn 180 181 v, err := resource_aws_db_instance_retrieve(s.ID, conn) 182 183 if err != nil { 184 return s, err 185 } 186 187 return resource_aws_db_instance_update_state(s, v) 188 } 189 190 func resource_aws_db_instance_diff( 191 s *terraform.ResourceState, 192 c *terraform.ResourceConfig, 193 meta interface{}) (*terraform.ResourceDiff, error) { 194 195 b := &diff.ResourceBuilder{ 196 Attrs: map[string]diff.AttrType{ 197 "allocated_storage": diff.AttrTypeCreate, 198 "availability_zone": diff.AttrTypeCreate, 199 "backup_retention_period": diff.AttrTypeCreate, 200 "backup_window": diff.AttrTypeCreate, 201 "engine": diff.AttrTypeCreate, 202 "engine_version": diff.AttrTypeCreate, 203 "identifier": diff.AttrTypeCreate, 204 "instance_class": diff.AttrTypeCreate, 205 "iops": diff.AttrTypeCreate, 206 "maintenance_window": diff.AttrTypeCreate, 207 "multi_az": diff.AttrTypeCreate, 208 "name": diff.AttrTypeCreate, 209 "password": diff.AttrTypeCreate, 210 "port": diff.AttrTypeCreate, 211 "publicly_accessible": diff.AttrTypeCreate, 212 "username": diff.AttrTypeCreate, 213 "vpc_security_group_ids": diff.AttrTypeCreate, 214 "security_group_names": diff.AttrTypeCreate, 215 }, 216 217 ComputedAttrs: []string{ 218 "address", 219 "availability_zone", 220 "backup_retention_period", 221 "backup_window", 222 "engine_version", 223 "maintenance_window", 224 "endpoint", 225 "status", 226 "multi_az", 227 "port", 228 "address", 229 }, 230 } 231 232 return b.Diff(s, c) 233 } 234 235 func resource_aws_db_instance_update_state( 236 s *terraform.ResourceState, 237 v *rds.DBInstance) (*terraform.ResourceState, error) { 238 239 s.Attributes["address"] = v.Address 240 s.Attributes["allocated_storage"] = strconv.Itoa(v.AllocatedStorage) 241 s.Attributes["availability_zone"] = v.AvailabilityZone 242 s.Attributes["backup_retention_period"] = strconv.Itoa(v.BackupRetentionPeriod) 243 s.Attributes["backup_window"] = v.PreferredBackupWindow 244 s.Attributes["endpoint"] = fmt.Sprintf("%s:%s", s.Attributes["address"], s.Attributes["port"]) 245 s.Attributes["engine"] = v.Engine 246 s.Attributes["engine_version"] = v.EngineVersion 247 s.Attributes["instance_class"] = v.DBInstanceClass 248 s.Attributes["maintenance_window"] = v.PreferredMaintenanceWindow 249 s.Attributes["multi_az"] = strconv.FormatBool(v.MultiAZ) 250 s.Attributes["name"] = v.DBName 251 s.Attributes["port"] = strconv.Itoa(v.Port) 252 s.Attributes["status"] = v.DBInstanceStatus 253 s.Attributes["username"] = v.MasterUsername 254 255 // Flatten our group values 256 toFlatten := make(map[string]interface{}) 257 258 if len(v.DBSecurityGroupNames) > 0 && v.DBSecurityGroupNames[0] != "" { 259 toFlatten["security_group_names"] = v.DBSecurityGroupNames 260 } 261 if len(v.VpcSecurityGroupIds) > 0 && v.VpcSecurityGroupIds[0] != "" { 262 toFlatten["vpc_security_group_ids"] = v.VpcSecurityGroupIds 263 } 264 for k, v := range flatmap.Flatten(toFlatten) { 265 s.Attributes[k] = v 266 } 267 268 return s, nil 269 } 270 271 func resource_aws_db_instance_retrieve(id string, conn *rds.Rds) (*rds.DBInstance, error) { 272 opts := rds.DescribeDBInstances{ 273 DBInstanceIdentifier: id, 274 } 275 276 log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) 277 278 resp, err := conn.DescribeDBInstances(&opts) 279 280 if err != nil { 281 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 282 } 283 284 if len(resp.DBInstances) != 1 || 285 resp.DBInstances[0].DBInstanceIdentifier != id { 286 if err != nil { 287 return nil, fmt.Errorf("Unable to find DB Instance: %#v", resp.DBInstances) 288 } 289 } 290 291 v := resp.DBInstances[0] 292 293 return &v, nil 294 } 295 296 func resource_aws_db_instance_validation() *config.Validator { 297 return &config.Validator{ 298 Required: []string{ 299 "allocated_storage", 300 "engine", 301 "engine_version", 302 "identifier", 303 "instance_class", 304 "name", 305 "password", 306 "username", 307 }, 308 Optional: []string{ 309 "availability_zone", 310 "backup_retention_period", 311 "backup_window", 312 "iops", 313 "maintenance_window", 314 "multi_az", 315 "port", 316 "publicly_accessible", 317 "vpc_security_group_ids.*", 318 "skip_final_snapshot", 319 "security_group_names.*", 320 }, 321 } 322 } 323 324 func DBInstanceStateRefreshFunc(id string, conn *rds.Rds) resource.StateRefreshFunc { 325 return func() (interface{}, string, error) { 326 v, err := resource_aws_db_instance_retrieve(id, conn) 327 328 if err != nil { 329 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 330 return nil, "", err 331 } 332 333 return v, v.DBInstanceStatus, nil 334 } 335 }