github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/builtin/providers/aws/resource_aws_db_instance.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/hashicorp/terraform/helper/hashcode" 10 "github.com/hashicorp/terraform/helper/resource" 11 "github.com/hashicorp/terraform/helper/schema" 12 "github.com/mitchellh/goamz/rds" 13 ) 14 15 func resourceAwsDbInstance() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAwsDbInstanceCreate, 18 Read: resourceAwsDbInstanceRead, 19 Delete: resourceAwsDbInstanceDelete, 20 21 Schema: map[string]*schema.Schema{ 22 "name": &schema.Schema{ 23 Type: schema.TypeString, 24 Optional: true, 25 ForceNew: true, 26 }, 27 28 "username": &schema.Schema{ 29 Type: schema.TypeString, 30 Required: true, 31 ForceNew: true, 32 }, 33 34 "password": &schema.Schema{ 35 Type: schema.TypeString, 36 Required: true, 37 ForceNew: true, 38 }, 39 40 "engine": &schema.Schema{ 41 Type: schema.TypeString, 42 Required: true, 43 ForceNew: true, 44 }, 45 46 "engine_version": &schema.Schema{ 47 Type: schema.TypeString, 48 Required: true, 49 ForceNew: true, 50 }, 51 52 "allocated_storage": &schema.Schema{ 53 Type: schema.TypeInt, 54 Required: true, 55 ForceNew: true, 56 }, 57 58 "storage_type": &schema.Schema{ 59 Type: schema.TypeString, 60 Optional: true, 61 Computed: true, 62 ForceNew: true, 63 }, 64 65 "identifier": &schema.Schema{ 66 Type: schema.TypeString, 67 Required: true, 68 ForceNew: true, 69 }, 70 71 "instance_class": &schema.Schema{ 72 Type: schema.TypeString, 73 Required: true, 74 ForceNew: true, 75 }, 76 77 "availability_zone": &schema.Schema{ 78 Type: schema.TypeString, 79 Optional: true, 80 Computed: true, 81 ForceNew: true, 82 }, 83 84 "backup_retention_period": &schema.Schema{ 85 Type: schema.TypeInt, 86 Optional: true, 87 Computed: true, 88 ForceNew: true, 89 }, 90 91 "backup_window": &schema.Schema{ 92 Type: schema.TypeString, 93 Optional: true, 94 Computed: true, 95 ForceNew: true, 96 }, 97 98 "iops": &schema.Schema{ 99 Type: schema.TypeInt, 100 Optional: true, 101 ForceNew: true, 102 }, 103 104 "maintenance_window": &schema.Schema{ 105 Type: schema.TypeString, 106 Optional: true, 107 Computed: true, 108 ForceNew: true, 109 }, 110 111 "multi_az": &schema.Schema{ 112 Type: schema.TypeBool, 113 Optional: true, 114 Computed: true, 115 ForceNew: true, 116 }, 117 118 "port": &schema.Schema{ 119 Type: schema.TypeInt, 120 Optional: true, 121 Computed: true, 122 ForceNew: true, 123 }, 124 125 "publicly_accessible": &schema.Schema{ 126 Type: schema.TypeBool, 127 Optional: true, 128 ForceNew: true, 129 }, 130 131 "vpc_security_group_ids": &schema.Schema{ 132 Type: schema.TypeSet, 133 Optional: true, 134 Elem: &schema.Schema{Type: schema.TypeString}, 135 Set: func(v interface{}) int { 136 return hashcode.String(v.(string)) 137 }, 138 }, 139 140 "security_group_names": &schema.Schema{ 141 Type: schema.TypeSet, 142 Optional: true, 143 Elem: &schema.Schema{Type: schema.TypeString}, 144 Set: func(v interface{}) int { 145 return hashcode.String(v.(string)) 146 }, 147 }, 148 149 "final_snapshot_identifier": &schema.Schema{ 150 Type: schema.TypeString, 151 Optional: true, 152 ForceNew: true, 153 }, 154 155 "db_subnet_group_name": &schema.Schema{ 156 Type: schema.TypeString, 157 Optional: true, 158 ForceNew: true, 159 }, 160 161 "parameter_group_name": &schema.Schema{ 162 Type: schema.TypeString, 163 Optional: true, 164 Computed: true, 165 ForceNew: true, 166 }, 167 168 "address": &schema.Schema{ 169 Type: schema.TypeString, 170 Computed: true, 171 }, 172 173 "endpoint": &schema.Schema{ 174 Type: schema.TypeString, 175 Computed: true, 176 }, 177 178 "status": &schema.Schema{ 179 Type: schema.TypeString, 180 Computed: true, 181 }, 182 }, 183 } 184 } 185 186 func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error { 187 conn := meta.(*AWSClient).rdsconn 188 opts := rds.CreateDBInstance{ 189 AllocatedStorage: d.Get("allocated_storage").(int), 190 SetAllocatedStorage: true, 191 DBInstanceClass: d.Get("instance_class").(string), 192 DBInstanceIdentifier: d.Get("identifier").(string), 193 DBName: d.Get("name").(string), 194 MasterUsername: d.Get("username").(string), 195 MasterUserPassword: d.Get("password").(string), 196 Engine: d.Get("engine").(string), 197 EngineVersion: d.Get("engine_version").(string), 198 } 199 200 if attr, ok := d.GetOk("storage_type"); ok { 201 opts.StorageType = attr.(string) 202 } 203 204 if attr, ok := d.GetOk("backup_retention_period"); ok { 205 opts.BackupRetentionPeriod = attr.(int) 206 opts.SetBackupRetentionPeriod = true 207 } 208 209 if attr, ok := d.GetOk("iops"); ok { 210 opts.Iops = attr.(int) 211 opts.SetIops = true 212 } 213 214 if attr, ok := d.GetOk("port"); ok { 215 opts.Port = attr.(int) 216 opts.SetPort = true 217 } 218 219 if attr, ok := d.GetOk("multi_az"); ok { 220 opts.MultiAZ = attr.(bool) 221 } 222 223 if attr, ok := d.GetOk("availability_zone"); ok { 224 opts.AvailabilityZone = attr.(string) 225 } 226 227 if attr, ok := d.GetOk("maintenance_window"); ok { 228 opts.PreferredMaintenanceWindow = attr.(string) 229 } 230 231 if attr, ok := d.GetOk("backup_window"); ok { 232 opts.PreferredBackupWindow = attr.(string) 233 } 234 235 if attr, ok := d.GetOk("publicly_accessible"); ok { 236 opts.PubliclyAccessible = attr.(bool) 237 } 238 239 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 240 opts.DBSubnetGroupName = attr.(string) 241 } 242 243 if attr, ok := d.GetOk("parameter_group_name"); ok { 244 opts.DBParameterGroupName = attr.(string) 245 } 246 247 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 248 var s []string 249 for _, v := range attr.List() { 250 s = append(s, v.(string)) 251 } 252 opts.VpcSecurityGroupIds = s 253 } 254 255 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 256 var s []string 257 for _, v := range attr.List() { 258 s = append(s, v.(string)) 259 } 260 opts.DBSecurityGroupNames = s 261 } 262 263 log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) 264 _, err := conn.CreateDBInstance(&opts) 265 if err != nil { 266 return fmt.Errorf("Error creating DB Instance: %s", err) 267 } 268 269 d.SetId(d.Get("identifier").(string)) 270 271 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 272 273 log.Println( 274 "[INFO] Waiting for DB Instance to be available") 275 276 stateConf := &resource.StateChangeConf{ 277 Pending: []string{"creating", "backing-up", "modifying"}, 278 Target: "available", 279 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 280 Timeout: 20 * time.Minute, 281 MinTimeout: 10 * time.Second, 282 Delay: 30 * time.Second, // Wait 30 secs before starting 283 } 284 285 // Wait, catching any errors 286 _, err = stateConf.WaitForState() 287 if err != nil { 288 return err 289 } 290 291 return resourceAwsDbInstanceRead(d, meta) 292 } 293 294 func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { 295 v, err := resourceAwsBbInstanceRetrieve(d, meta) 296 297 if err != nil { 298 return err 299 } 300 if v == nil { 301 d.SetId("") 302 return nil 303 } 304 305 d.Set("name", v.DBName) 306 d.Set("username", v.MasterUsername) 307 d.Set("engine", v.Engine) 308 d.Set("engine_version", v.EngineVersion) 309 d.Set("allocated_storage", v.AllocatedStorage) 310 d.Set("storage_type", v.StorageType) 311 d.Set("instance_class", v.DBInstanceClass) 312 d.Set("availability_zone", v.AvailabilityZone) 313 d.Set("backup_retention_period", v.BackupRetentionPeriod) 314 d.Set("backup_window", v.PreferredBackupWindow) 315 d.Set("maintenance_window", v.PreferredMaintenanceWindow) 316 d.Set("multi_az", v.MultiAZ) 317 d.Set("port", v.Port) 318 d.Set("db_subnet_group_name", v.DBSubnetGroup.Name) 319 d.Set("parameter_group_name", v.DBParameterGroupName) 320 d.Set("address", v.Address) 321 d.Set("endpoint", fmt.Sprintf("%s:%d", v.Address, v.Port)) 322 d.Set("status", v.DBInstanceStatus) 323 324 // Create an empty schema.Set to hold all vpc security group ids 325 ids := &schema.Set{ 326 F: func(v interface{}) int { 327 return hashcode.String(v.(string)) 328 }, 329 } 330 for _, v := range v.VpcSecurityGroupIds { 331 ids.Add(v) 332 } 333 d.Set("vpc_security_group_ids", ids) 334 335 // Create an empty schema.Set to hold all security group names 336 sgn := &schema.Set{ 337 F: func(v interface{}) int { 338 return hashcode.String(v.(string)) 339 }, 340 } 341 for _, v := range v.DBSecurityGroupNames { 342 sgn.Add(v) 343 } 344 d.Set("security_group_names", sgn) 345 346 return nil 347 } 348 349 func resourceAwsDbInstanceDelete(d *schema.ResourceData, meta interface{}) error { 350 conn := meta.(*AWSClient).rdsconn 351 352 log.Printf("[DEBUG] DB Instance destroy: %v", d.Id()) 353 354 opts := rds.DeleteDBInstance{DBInstanceIdentifier: d.Id()} 355 356 finalSnapshot := d.Get("final_snapshot_identifier").(string) 357 if finalSnapshot == "" { 358 opts.SkipFinalSnapshot = true 359 } else { 360 opts.FinalDBSnapshotIdentifier = finalSnapshot 361 } 362 363 log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts) 364 if _, err := conn.DeleteDBInstance(&opts); err != nil { 365 return err 366 } 367 368 log.Println( 369 "[INFO] Waiting for DB Instance to be destroyed") 370 stateConf := &resource.StateChangeConf{ 371 Pending: []string{"creating", "backing-up", 372 "modifying", "deleting", "available"}, 373 Target: "", 374 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 375 Timeout: 20 * time.Minute, 376 MinTimeout: 10 * time.Second, 377 Delay: 30 * time.Second, // Wait 30 secs before starting 378 } 379 if _, err := stateConf.WaitForState(); err != nil { 380 return err 381 } 382 383 return nil 384 } 385 386 func resourceAwsBbInstanceRetrieve( 387 d *schema.ResourceData, meta interface{}) (*rds.DBInstance, error) { 388 conn := meta.(*AWSClient).rdsconn 389 390 opts := rds.DescribeDBInstances{ 391 DBInstanceIdentifier: d.Id(), 392 } 393 394 log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts) 395 396 resp, err := conn.DescribeDBInstances(&opts) 397 398 if err != nil { 399 if strings.Contains(err.Error(), "DBInstanceNotFound") { 400 return nil, nil 401 } 402 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 403 } 404 405 if len(resp.DBInstances) != 1 || 406 resp.DBInstances[0].DBInstanceIdentifier != d.Id() { 407 if err != nil { 408 return nil, nil 409 } 410 } 411 412 v := resp.DBInstances[0] 413 414 return &v, nil 415 } 416 417 func resourceAwsDbInstanceStateRefreshFunc( 418 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 419 return func() (interface{}, string, error) { 420 v, err := resourceAwsBbInstanceRetrieve(d, meta) 421 422 if err != nil { 423 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 424 return nil, "", err 425 } 426 427 if v == nil { 428 return nil, "", nil 429 } 430 431 return v, v.DBInstanceStatus, nil 432 } 433 }