github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/builtin/providers/aws/resource_aws_db_instance.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/hashicorp/terraform/flatmap"
    10  	"github.com/hashicorp/terraform/helper/config"
    11  	"github.com/hashicorp/terraform/helper/diff"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/terraform"
    14  	"github.com/mitchellh/goamz/rds"
    15  )
    16  
    17  func resource_aws_db_instance_create(
    18  	s *terraform.ResourceState,
    19  	d *terraform.ResourceDiff,
    20  	meta interface{}) (*terraform.ResourceState, error) {
    21  	p := meta.(*ResourceProvider)
    22  	conn := p.rdsconn
    23  
    24  	// Merge the diff into the state so that we have all the attributes
    25  	// properly.
    26  	rs := s.MergeDiff(d)
    27  
    28  	var err error
    29  	var attr string
    30  
    31  	opts := rds.CreateDBInstance{}
    32  
    33  	if attr = rs.Attributes["allocated_storage"]; attr != "" {
    34  		opts.AllocatedStorage, err = strconv.Atoi(attr)
    35  		opts.SetAllocatedStorage = true
    36  	}
    37  
    38  	if attr = rs.Attributes["backup_retention_period"]; attr != "" {
    39  		opts.BackupRetentionPeriod, err = strconv.Atoi(attr)
    40  		opts.SetBackupRetentionPeriod = true
    41  	}
    42  
    43  	if attr = rs.Attributes["iops"]; attr != "" {
    44  		opts.Iops, err = strconv.Atoi(attr)
    45  		opts.SetIops = true
    46  	}
    47  
    48  	if attr = rs.Attributes["port"]; attr != "" {
    49  		opts.Port, err = strconv.Atoi(attr)
    50  		opts.SetPort = true
    51  	}
    52  
    53  	if attr = rs.Attributes["availability_zone"]; attr != "" {
    54  		opts.AvailabilityZone = attr
    55  	}
    56  
    57  	if attr = rs.Attributes["instance_class"]; attr != "" {
    58  		opts.DBInstanceClass = attr
    59  	}
    60  
    61  	if attr = rs.Attributes["maintenance_window"]; attr != "" {
    62  		opts.PreferredMaintenanceWindow = attr
    63  	}
    64  
    65  	if attr = rs.Attributes["backup_window"]; attr != "" {
    66  		opts.PreferredBackupWindow = attr
    67  	}
    68  
    69  	if attr = rs.Attributes["multi_az"]; attr == "true" {
    70  		opts.MultiAZ = true
    71  	}
    72  
    73  	if attr = rs.Attributes["publicly_accessible"]; attr == "true" {
    74  		opts.PubliclyAccessible = true
    75  	}
    76  
    77  	if err != nil {
    78  		return nil, fmt.Errorf("Error parsing configuration: %s", err)
    79  	}
    80  
    81  	if _, ok := rs.Attributes["vpc_security_group_ids.#"]; ok {
    82  		opts.VpcSecurityGroupIds = expandStringList(flatmap.Expand(
    83  			rs.Attributes, "vpc_security_group_ids").([]interface{}))
    84  	}
    85  
    86  	if _, ok := rs.Attributes["security_group_names.#"]; ok {
    87  		opts.DBSecurityGroupNames = expandStringList(flatmap.Expand(
    88  			rs.Attributes, "security_group_names").([]interface{}))
    89  	}
    90  
    91  	opts.DBInstanceIdentifier = rs.Attributes["identifier"]
    92  	opts.DBName = rs.Attributes["name"]
    93  	opts.MasterUsername = rs.Attributes["username"]
    94  	opts.MasterUserPassword = rs.Attributes["password"]
    95  	opts.EngineVersion = rs.Attributes["engine_version"]
    96  	opts.EngineVersion = rs.Attributes["engine"]
    97  
    98  	// Don't keep the password around in the state
    99  	delete(rs.Attributes, "password")
   100  
   101  	log.Printf("[DEBUG] DB Instance create configuration: %#v", opts)
   102  	_, err = conn.CreateDBInstance(&opts)
   103  	if err != nil {
   104  		return nil, fmt.Errorf("Error creating DB Instance: %s", err)
   105  	}
   106  
   107  	rs.ID = rs.Attributes["identifier"]
   108  
   109  	log.Printf("[INFO] DB Instance ID: %s", rs.ID)
   110  
   111  	log.Println(
   112  		"[INFO] Waiting for DB Instance to be available")
   113  
   114  	stateConf := &resource.StateChangeConf{
   115  		Pending:    []string{"creating", "backing-up"},
   116  		Target:     "available",
   117  		Refresh:    DBInstanceStateRefreshFunc(rs.ID, conn),
   118  		Timeout:    10 * time.Minute,
   119  		MinTimeout: 10 * time.Second,
   120  		Delay:      30 * time.Second, // Wait 30 secs before starting
   121  	}
   122  
   123  	// Wait, catching any errors
   124  	_, err = stateConf.WaitForState()
   125  	if err != nil {
   126  		return rs, err
   127  	}
   128  
   129  	v, err := resource_aws_db_instance_retrieve(rs.ID, conn)
   130  	if err != nil {
   131  		return rs, err
   132  	}
   133  
   134  	return resource_aws_db_instance_update_state(rs, v)
   135  }
   136  
   137  func resource_aws_db_instance_update(
   138  	s *terraform.ResourceState,
   139  	d *terraform.ResourceDiff,
   140  	meta interface{}) (*terraform.ResourceState, error) {
   141  
   142  	panic("Cannot update DB")
   143  
   144  	return nil, nil
   145  }
   146  
   147  func resource_aws_db_instance_destroy(
   148  	s *terraform.ResourceState,
   149  	meta interface{}) error {
   150  	p := meta.(*ResourceProvider)
   151  	conn := p.rdsconn
   152  
   153  	log.Printf("[DEBUG] DB Instance destroy: %v", s.ID)
   154  
   155  	opts := rds.DeleteDBInstance{DBInstanceIdentifier: s.ID}
   156  
   157  	if s.Attributes["skip_final_snapshot"] == "true" {
   158  		opts.SkipFinalSnapshot = true
   159  	}
   160  
   161  	log.Printf("[DEBUG] DB Instance destroy configuration: %v", opts)
   162  	_, err := conn.DeleteDBInstance(&opts)
   163  
   164  	if err != nil {
   165  		newerr, ok := err.(*rds.Error)
   166  		if ok && newerr.Code == "InvalidDBInstance.NotFound" {
   167  			return nil
   168  		}
   169  		return err
   170  	}
   171  
   172  	return nil
   173  }
   174  
   175  func resource_aws_db_instance_refresh(
   176  	s *terraform.ResourceState,
   177  	meta interface{}) (*terraform.ResourceState, error) {
   178  	p := meta.(*ResourceProvider)
   179  	conn := p.rdsconn
   180  
   181  	v, err := resource_aws_db_instance_retrieve(s.ID, conn)
   182  
   183  	if err != nil {
   184  		return s, err
   185  	}
   186  
   187  	return resource_aws_db_instance_update_state(s, v)
   188  }
   189  
   190  func resource_aws_db_instance_diff(
   191  	s *terraform.ResourceState,
   192  	c *terraform.ResourceConfig,
   193  	meta interface{}) (*terraform.ResourceDiff, error) {
   194  
   195  	b := &diff.ResourceBuilder{
   196  		Attrs: map[string]diff.AttrType{
   197  			"allocated_storage":       diff.AttrTypeCreate,
   198  			"availability_zone":       diff.AttrTypeCreate,
   199  			"backup_retention_period": diff.AttrTypeCreate,
   200  			"backup_window":           diff.AttrTypeCreate,
   201  			"engine":                  diff.AttrTypeCreate,
   202  			"engine_version":          diff.AttrTypeCreate,
   203  			"identifier":              diff.AttrTypeCreate,
   204  			"instance_class":          diff.AttrTypeCreate,
   205  			"iops":                    diff.AttrTypeCreate,
   206  			"maintenance_window":      diff.AttrTypeCreate,
   207  			"multi_az":                diff.AttrTypeCreate,
   208  			"name":                    diff.AttrTypeCreate,
   209  			"password":                diff.AttrTypeCreate,
   210  			"port":                    diff.AttrTypeCreate,
   211  			"publicly_accessible":     diff.AttrTypeCreate,
   212  			"username":                diff.AttrTypeCreate,
   213  			"vpc_security_group_ids":  diff.AttrTypeCreate,
   214  			"security_group_names":    diff.AttrTypeCreate,
   215  		},
   216  
   217  		ComputedAttrs: []string{
   218  			"address",
   219  			"availability_zone",
   220  			"backup_retention_period",
   221  			"backup_window",
   222  			"engine_version",
   223  			"maintenance_window",
   224  			"endpoint",
   225  			"status",
   226  			"multi_az",
   227  			"port",
   228  			"address",
   229  		},
   230  	}
   231  
   232  	return b.Diff(s, c)
   233  }
   234  
   235  func resource_aws_db_instance_update_state(
   236  	s *terraform.ResourceState,
   237  	v *rds.DBInstance) (*terraform.ResourceState, error) {
   238  
   239  	s.Attributes["address"] = v.Address
   240  	s.Attributes["allocated_storage"] = strconv.Itoa(v.AllocatedStorage)
   241  	s.Attributes["availability_zone"] = v.AvailabilityZone
   242  	s.Attributes["backup_retention_period"] = strconv.Itoa(v.BackupRetentionPeriod)
   243  	s.Attributes["backup_window"] = v.PreferredBackupWindow
   244  	s.Attributes["endpoint"] = fmt.Sprintf("%s:%s", s.Attributes["address"], s.Attributes["port"])
   245  	s.Attributes["engine"] = v.Engine
   246  	s.Attributes["engine_version"] = v.EngineVersion
   247  	s.Attributes["instance_class"] = v.DBInstanceClass
   248  	s.Attributes["maintenance_window"] = v.PreferredMaintenanceWindow
   249  	s.Attributes["multi_az"] = strconv.FormatBool(v.MultiAZ)
   250  	s.Attributes["name"] = v.DBName
   251  	s.Attributes["port"] = strconv.Itoa(v.Port)
   252  	s.Attributes["status"] = v.DBInstanceStatus
   253  	s.Attributes["username"] = v.MasterUsername
   254  
   255  	// Flatten our group values
   256  	toFlatten := make(map[string]interface{})
   257  
   258  	if len(v.DBSecurityGroupNames) > 0 && v.DBSecurityGroupNames[0] != "" {
   259  		toFlatten["security_group_names"] = v.DBSecurityGroupNames
   260  	}
   261  	if len(v.VpcSecurityGroupIds) > 0 && v.VpcSecurityGroupIds[0] != "" {
   262  		toFlatten["vpc_security_group_ids"] = v.VpcSecurityGroupIds
   263  	}
   264  	for k, v := range flatmap.Flatten(toFlatten) {
   265  		s.Attributes[k] = v
   266  	}
   267  
   268  	return s, nil
   269  }
   270  
   271  func resource_aws_db_instance_retrieve(id string, conn *rds.Rds) (*rds.DBInstance, error) {
   272  	opts := rds.DescribeDBInstances{
   273  		DBInstanceIdentifier: id,
   274  	}
   275  
   276  	log.Printf("[DEBUG] DB Instance describe configuration: %#v", opts)
   277  
   278  	resp, err := conn.DescribeDBInstances(&opts)
   279  
   280  	if err != nil {
   281  		return nil, fmt.Errorf("Error retrieving DB Instances: %s", err)
   282  	}
   283  
   284  	if len(resp.DBInstances) != 1 ||
   285  		resp.DBInstances[0].DBInstanceIdentifier != id {
   286  		if err != nil {
   287  			return nil, fmt.Errorf("Unable to find DB Instance: %#v", resp.DBInstances)
   288  		}
   289  	}
   290  
   291  	v := resp.DBInstances[0]
   292  
   293  	return &v, nil
   294  }
   295  
   296  func resource_aws_db_instance_validation() *config.Validator {
   297  	return &config.Validator{
   298  		Required: []string{
   299  			"allocated_storage",
   300  			"engine",
   301  			"engine_version",
   302  			"identifier",
   303  			"instance_class",
   304  			"name",
   305  			"password",
   306  			"username",
   307  		},
   308  		Optional: []string{
   309  			"availability_zone",
   310  			"backup_retention_period",
   311  			"backup_window",
   312  			"iops",
   313  			"maintenance_window",
   314  			"multi_az",
   315  			"port",
   316  			"publicly_accessible",
   317  			"vpc_security_group_ids.*",
   318  			"skip_final_snapshot",
   319  			"security_group_names.*",
   320  		},
   321  	}
   322  }
   323  
   324  func DBInstanceStateRefreshFunc(id string, conn *rds.Rds) resource.StateRefreshFunc {
   325  	return func() (interface{}, string, error) {
   326  		v, err := resource_aws_db_instance_retrieve(id, conn)
   327  
   328  		if err != nil {
   329  			log.Printf("Error on retrieving DB Instance when waiting: %s", err)
   330  			return nil, "", err
   331  		}
   332  
   333  		return v, v.DBInstanceStatus, nil
   334  	}
   335  }