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