github.com/jgadling/terraform@v0.3.8-0.20150227214559-abd68c2c87bc/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 "allocated_storage": &schema.Schema{ 54 Type: schema.TypeInt, 55 Required: true, 56 ForceNew: true, 57 }, 58 59 "storage_type": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 Computed: true, 63 ForceNew: true, 64 }, 65 66 "identifier": &schema.Schema{ 67 Type: schema.TypeString, 68 Required: true, 69 ForceNew: true, 70 }, 71 72 "instance_class": &schema.Schema{ 73 Type: schema.TypeString, 74 Required: true, 75 ForceNew: true, 76 }, 77 78 "availability_zone": &schema.Schema{ 79 Type: schema.TypeString, 80 Optional: true, 81 Computed: true, 82 ForceNew: true, 83 }, 84 85 "backup_retention_period": &schema.Schema{ 86 Type: schema.TypeInt, 87 Optional: true, 88 ForceNew: true, 89 Default: 1, 90 }, 91 92 "backup_window": &schema.Schema{ 93 Type: schema.TypeString, 94 Optional: true, 95 Computed: true, 96 ForceNew: true, 97 }, 98 99 "iops": &schema.Schema{ 100 Type: schema.TypeInt, 101 Optional: true, 102 ForceNew: true, 103 }, 104 105 "maintenance_window": &schema.Schema{ 106 Type: schema.TypeString, 107 Optional: true, 108 Computed: true, 109 ForceNew: true, 110 }, 111 112 "multi_az": &schema.Schema{ 113 Type: schema.TypeBool, 114 Optional: true, 115 Computed: true, 116 ForceNew: true, 117 }, 118 119 "port": &schema.Schema{ 120 Type: schema.TypeInt, 121 Optional: true, 122 Computed: true, 123 ForceNew: true, 124 }, 125 126 "publicly_accessible": &schema.Schema{ 127 Type: schema.TypeBool, 128 Optional: true, 129 ForceNew: true, 130 }, 131 132 "vpc_security_group_ids": &schema.Schema{ 133 Type: schema.TypeSet, 134 Optional: true, 135 Elem: &schema.Schema{Type: schema.TypeString}, 136 Set: func(v interface{}) int { 137 return hashcode.String(v.(string)) 138 }, 139 }, 140 141 "security_group_names": &schema.Schema{ 142 Type: schema.TypeSet, 143 Optional: true, 144 Elem: &schema.Schema{Type: schema.TypeString}, 145 Set: func(v interface{}) int { 146 return hashcode.String(v.(string)) 147 }, 148 }, 149 150 "final_snapshot_identifier": &schema.Schema{ 151 Type: schema.TypeString, 152 Optional: true, 153 ForceNew: true, 154 }, 155 156 "db_subnet_group_name": &schema.Schema{ 157 Type: schema.TypeString, 158 Optional: true, 159 ForceNew: true, 160 }, 161 162 "parameter_group_name": &schema.Schema{ 163 Type: schema.TypeString, 164 Optional: true, 165 Computed: true, 166 ForceNew: true, 167 }, 168 169 "address": &schema.Schema{ 170 Type: schema.TypeString, 171 Computed: true, 172 }, 173 174 "endpoint": &schema.Schema{ 175 Type: schema.TypeString, 176 Computed: true, 177 }, 178 179 "status": &schema.Schema{ 180 Type: schema.TypeString, 181 Computed: true, 182 }, 183 }, 184 } 185 } 186 187 func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error { 188 conn := meta.(*AWSClient).rdsconn 189 opts := rds.CreateDBInstanceMessage{ 190 AllocatedStorage: aws.Integer(d.Get("allocated_storage").(int)), 191 DBInstanceClass: aws.String(d.Get("instance_class").(string)), 192 DBInstanceIdentifier: aws.String(d.Get("identifier").(string)), 193 DBName: aws.String(d.Get("name").(string)), 194 MasterUsername: aws.String(d.Get("username").(string)), 195 MasterUserPassword: aws.String(d.Get("password").(string)), 196 Engine: aws.String(d.Get("engine").(string)), 197 EngineVersion: aws.String(d.Get("engine_version").(string)), 198 } 199 200 if attr, ok := d.GetOk("storage_type"); ok { 201 opts.StorageType = aws.String(attr.(string)) 202 } 203 204 attr := d.Get("backup_retention_period") 205 opts.BackupRetentionPeriod = aws.Integer(attr.(int)) 206 207 if attr, ok := d.GetOk("iops"); ok { 208 opts.IOPS = aws.Integer(attr.(int)) 209 } 210 211 if attr, ok := d.GetOk("port"); ok { 212 opts.Port = aws.Integer(attr.(int)) 213 } 214 215 if attr, ok := d.GetOk("multi_az"); ok { 216 opts.MultiAZ = aws.Boolean(attr.(bool)) 217 } 218 219 if attr, ok := d.GetOk("availability_zone"); ok { 220 opts.AvailabilityZone = aws.String(attr.(string)) 221 } 222 223 if attr, ok := d.GetOk("maintenance_window"); ok { 224 opts.PreferredMaintenanceWindow = aws.String(attr.(string)) 225 } 226 227 if attr, ok := d.GetOk("backup_window"); ok { 228 opts.PreferredBackupWindow = aws.String(attr.(string)) 229 } 230 231 if attr, ok := d.GetOk("publicly_accessible"); ok { 232 opts.PubliclyAccessible = aws.Boolean(attr.(bool)) 233 } 234 235 if attr, ok := d.GetOk("db_subnet_group_name"); ok { 236 opts.DBSubnetGroupName = aws.String(attr.(string)) 237 } 238 239 if attr, ok := d.GetOk("parameter_group_name"); ok { 240 opts.DBParameterGroupName = aws.String(attr.(string)) 241 } 242 243 if attr := d.Get("vpc_security_group_ids").(*schema.Set); attr.Len() > 0 { 244 var s []string 245 for _, v := range attr.List() { 246 s = append(s, v.(string)) 247 } 248 opts.VPCSecurityGroupIDs = s 249 } 250 251 if attr := d.Get("security_group_names").(*schema.Set); attr.Len() > 0 { 252 var s []string 253 for _, v := range attr.List() { 254 s = append(s, v.(string)) 255 } 256 opts.DBSecurityGroups = s 257 } 258 259 log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) 260 _, err := conn.CreateDBInstance(&opts) 261 if err != nil { 262 return fmt.Errorf("Error creating DB Instance: %s", err) 263 } 264 265 d.SetId(d.Get("identifier").(string)) 266 267 log.Printf("[INFO] DB Instance ID: %s", d.Id()) 268 269 log.Println( 270 "[INFO] Waiting for DB Instance to be available") 271 272 stateConf := &resource.StateChangeConf{ 273 Pending: []string{"creating", "backing-up", "modifying"}, 274 Target: "available", 275 Refresh: resourceAwsDbInstanceStateRefreshFunc(d, meta), 276 Timeout: 40 * time.Minute, 277 MinTimeout: 10 * time.Second, 278 Delay: 30 * time.Second, // Wait 30 secs before starting 279 } 280 281 // Wait, catching any errors 282 _, err = stateConf.WaitForState() 283 if err != nil { 284 return err 285 } 286 287 return resourceAwsDbInstanceRead(d, meta) 288 } 289 290 func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { 291 v, err := resourceAwsBbInstanceRetrieve(d, meta) 292 293 if err != nil { 294 return err 295 } 296 if v == nil { 297 d.SetId("") 298 return nil 299 } 300 301 d.Set("name", *v.DBName) 302 d.Set("username", *v.MasterUsername) 303 d.Set("engine", *v.Engine) 304 d.Set("engine_version", *v.EngineVersion) 305 d.Set("allocated_storage", *v.AllocatedStorage) 306 d.Set("storage_type", *v.StorageType) 307 d.Set("instance_class", *v.DBInstanceClass) 308 d.Set("availability_zone", *v.AvailabilityZone) 309 d.Set("backup_retention_period", *v.BackupRetentionPeriod) 310 d.Set("backup_window", *v.PreferredBackupWindow) 311 d.Set("maintenance_window", *v.PreferredMaintenanceWindow) 312 d.Set("multi_az", *v.MultiAZ) 313 d.Set("port", *v.Endpoint.Port) 314 d.Set("db_subnet_group_name", *v.DBSubnetGroup.DBSubnetGroupName) 315 316 if len(v.DBParameterGroups) > 0 { 317 d.Set("parameter_group_name", *v.DBParameterGroups[0].DBParameterGroupName) 318 } 319 320 d.Set("address", *v.Endpoint.Port) 321 d.Set("endpoint", fmt.Sprintf("%s:%d", *v.Endpoint.Address, *v.Endpoint.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.VPCSecurityGroups { 331 ids.Add(*v.VPCSecurityGroupID) 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.DBSecurityGroups { 342 sgn.Add(*v.DBSecurityGroupName) 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.DeleteDBInstanceMessage{DBInstanceIdentifier: aws.String(d.Id())} 355 356 finalSnapshot := d.Get("final_snapshot_identifier").(string) 357 if finalSnapshot == "" { 358 opts.SkipFinalSnapshot = aws.Boolean(true) 359 } else { 360 opts.FinalDBSnapshotIdentifier = aws.String(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: 40 * 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.DescribeDBInstancesMessage{ 391 DBInstanceIdentifier: aws.String(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 dbinstanceerr, ok := err.(aws.APIError) 400 if ok && dbinstanceerr.Code == "DBInstanceNotFound" { 401 return nil, nil 402 } 403 return nil, fmt.Errorf("Error retrieving DB Instances: %s", err) 404 } 405 406 if len(resp.DBInstances) != 1 || 407 *resp.DBInstances[0].DBInstanceIdentifier != d.Id() { 408 if err != nil { 409 return nil, nil 410 } 411 } 412 413 v := resp.DBInstances[0] 414 415 return &v, nil 416 } 417 418 func resourceAwsDbInstanceStateRefreshFunc( 419 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 420 return func() (interface{}, string, error) { 421 v, err := resourceAwsBbInstanceRetrieve(d, meta) 422 423 if err != nil { 424 log.Printf("Error on retrieving DB Instance when waiting: %s", err) 425 return nil, "", err 426 } 427 428 if v == nil { 429 return nil, "", nil 430 } 431 432 return v, *v.DBInstanceStatus, nil 433 } 434 }