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