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  }