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  }