github.com/adrian-bl/terraform@v0.7.0-rc2.0.20160705220747-de0a34fc3517/builtin/providers/aws/resource_aws_rds_cluster_instance.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/service/rds"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceAwsRDSClusterInstance() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceAwsRDSClusterInstanceCreate,
    17  		Read:   resourceAwsRDSClusterInstanceRead,
    18  		Update: resourceAwsRDSClusterInstanceUpdate,
    19  		Delete: resourceAwsRDSClusterInstanceDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"identifier": &schema.Schema{
    23  				Type:         schema.TypeString,
    24  				Optional:     true,
    25  				ForceNew:     true,
    26  				ValidateFunc: validateRdsId,
    27  			},
    28  
    29  			"db_subnet_group_name": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Optional: true,
    32  				ForceNew: true,
    33  				Computed: true,
    34  			},
    35  
    36  			"writer": &schema.Schema{
    37  				Type:     schema.TypeBool,
    38  				Computed: true,
    39  			},
    40  
    41  			"cluster_identifier": &schema.Schema{
    42  				Type:     schema.TypeString,
    43  				Required: true,
    44  				ForceNew: true,
    45  			},
    46  
    47  			"endpoint": &schema.Schema{
    48  				Type:     schema.TypeString,
    49  				Computed: true,
    50  			},
    51  
    52  			"port": &schema.Schema{
    53  				Type:     schema.TypeInt,
    54  				Computed: true,
    55  			},
    56  
    57  			"publicly_accessible": &schema.Schema{
    58  				Type:     schema.TypeBool,
    59  				Optional: true,
    60  				Default:  false,
    61  			},
    62  
    63  			"instance_class": &schema.Schema{
    64  				Type:     schema.TypeString,
    65  				Required: true,
    66  			},
    67  
    68  			"db_parameter_group_name": &schema.Schema{
    69  				Type:     schema.TypeString,
    70  				Optional: true,
    71  				Computed: true,
    72  			},
    73  
    74  			// apply_immediately is used to determine when the update modifications
    75  			// take place.
    76  			// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
    77  			"apply_immediately": &schema.Schema{
    78  				Type:     schema.TypeBool,
    79  				Optional: true,
    80  				Computed: true,
    81  			},
    82  
    83  			"tags": tagsSchema(),
    84  		},
    85  	}
    86  }
    87  
    88  func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{}) error {
    89  	conn := meta.(*AWSClient).rdsconn
    90  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
    91  
    92  	createOpts := &rds.CreateDBInstanceInput{
    93  		DBInstanceClass:     aws.String(d.Get("instance_class").(string)),
    94  		DBClusterIdentifier: aws.String(d.Get("cluster_identifier").(string)),
    95  		Engine:              aws.String("aurora"),
    96  		PubliclyAccessible:  aws.Bool(d.Get("publicly_accessible").(bool)),
    97  		Tags:                tags,
    98  	}
    99  
   100  	if attr, ok := d.GetOk("db_parameter_group_name"); ok {
   101  		createOpts.DBParameterGroupName = aws.String(attr.(string))
   102  	}
   103  
   104  	if v := d.Get("identifier").(string); v != "" {
   105  		createOpts.DBInstanceIdentifier = aws.String(v)
   106  	} else {
   107  		createOpts.DBInstanceIdentifier = aws.String(resource.UniqueId())
   108  	}
   109  
   110  	if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   111  		createOpts.DBSubnetGroupName = aws.String(attr.(string))
   112  	}
   113  
   114  	log.Printf("[DEBUG] Creating RDS DB Instance opts: %s", createOpts)
   115  	resp, err := conn.CreateDBInstance(createOpts)
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	d.SetId(*resp.DBInstance.DBInstanceIdentifier)
   121  
   122  	// reuse db_instance refresh func
   123  	stateConf := &resource.StateChangeConf{
   124  		Pending:    []string{"creating", "backing-up", "modifying"},
   125  		Target:     []string{"available"},
   126  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   127  		Timeout:    40 * time.Minute,
   128  		MinTimeout: 10 * time.Second,
   129  		Delay:      10 * time.Second,
   130  	}
   131  
   132  	// Wait, catching any errors
   133  	_, err = stateConf.WaitForState()
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	return resourceAwsRDSClusterInstanceRead(d, meta)
   139  }
   140  
   141  func resourceAwsRDSClusterInstanceRead(d *schema.ResourceData, meta interface{}) error {
   142  	db, err := resourceAwsDbInstanceRetrieve(d, meta)
   143  	// Errors from this helper are always reportable
   144  	if err != nil {
   145  		return fmt.Errorf("[WARN] Error on retrieving RDS Cluster Instance (%s): %s", d.Id(), err)
   146  	}
   147  	// A nil response means "not found"
   148  	if db == nil {
   149  		log.Printf("[WARN] RDS Cluster Instance (%s): not found, removing from state.", d.Id())
   150  		d.SetId("")
   151  		return nil
   152  	}
   153  
   154  	// Retreive DB Cluster information, to determine if this Instance is a writer
   155  	conn := meta.(*AWSClient).rdsconn
   156  	resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{
   157  		DBClusterIdentifier: db.DBClusterIdentifier,
   158  	})
   159  
   160  	var dbc *rds.DBCluster
   161  	for _, c := range resp.DBClusters {
   162  		if *c.DBClusterIdentifier == *db.DBClusterIdentifier {
   163  			dbc = c
   164  		}
   165  	}
   166  
   167  	if dbc == nil {
   168  		return fmt.Errorf("[WARN] Error finding RDS Cluster (%s) for Cluster Instance (%s): %s",
   169  			*db.DBClusterIdentifier, *db.DBInstanceIdentifier, err)
   170  	}
   171  
   172  	for _, m := range dbc.DBClusterMembers {
   173  		if *db.DBInstanceIdentifier == *m.DBInstanceIdentifier {
   174  			if *m.IsClusterWriter == true {
   175  				d.Set("writer", true)
   176  			} else {
   177  				d.Set("writer", false)
   178  			}
   179  		}
   180  	}
   181  
   182  	if db.Endpoint != nil {
   183  		d.Set("endpoint", db.Endpoint.Address)
   184  		d.Set("port", db.Endpoint.Port)
   185  	}
   186  
   187  	d.Set("publicly_accessible", db.PubliclyAccessible)
   188  
   189  	if len(db.DBParameterGroups) > 0 {
   190  		d.Set("parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName)
   191  	}
   192  
   193  	// Fetch and save tags
   194  	arn, err := buildRDSARN(d.Id(), meta)
   195  	if err != nil {
   196  		log.Printf("[DEBUG] Error building ARN for RDS Cluster Instance (%s), not setting Tags", *db.DBInstanceIdentifier)
   197  	} else {
   198  		if err := saveTagsRDS(conn, d, arn); err != nil {
   199  			log.Printf("[WARN] Failed to save tags for RDS Cluster Instance (%s): %s", *db.DBClusterIdentifier, err)
   200  		}
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   207  	conn := meta.(*AWSClient).rdsconn
   208  	requestUpdate := false
   209  
   210  	req := &rds.ModifyDBInstanceInput{
   211  		ApplyImmediately:     aws.Bool(d.Get("apply_immediately").(bool)),
   212  		DBInstanceIdentifier: aws.String(d.Id()),
   213  	}
   214  
   215  	if d.HasChange("db_parameter_group_name") {
   216  		req.DBParameterGroupName = aws.String(d.Get("db_parameter_group_name").(string))
   217  		requestUpdate = true
   218  
   219  	}
   220  
   221  	if d.HasChange("instance_class") {
   222  		req.DBInstanceClass = aws.String(d.Get("instance_class").(string))
   223  		requestUpdate = true
   224  
   225  	}
   226  
   227  	log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate)
   228  	if requestUpdate {
   229  		log.Printf("[DEBUG] DB Instance Modification request: %#v", req)
   230  		_, err := conn.ModifyDBInstance(req)
   231  		if err != nil {
   232  			return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err)
   233  		}
   234  
   235  		// reuse db_instance refresh func
   236  		stateConf := &resource.StateChangeConf{
   237  			Pending:    []string{"creating", "backing-up", "modifying"},
   238  			Target:     []string{"available"},
   239  			Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   240  			Timeout:    40 * time.Minute,
   241  			MinTimeout: 10 * time.Second,
   242  			Delay:      10 * time.Second,
   243  		}
   244  
   245  		// Wait, catching any errors
   246  		_, err = stateConf.WaitForState()
   247  		if err != nil {
   248  			return err
   249  		}
   250  
   251  	}
   252  
   253  	if arn, err := buildRDSARN(d.Id(), meta); err == nil {
   254  		if err := setTagsRDS(conn, d, arn); err != nil {
   255  			return err
   256  		}
   257  	}
   258  
   259  	return resourceAwsRDSClusterInstanceRead(d, meta)
   260  }
   261  
   262  func resourceAwsRDSClusterInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   263  	conn := meta.(*AWSClient).rdsconn
   264  
   265  	log.Printf("[DEBUG] RDS Cluster Instance destroy: %v", d.Id())
   266  
   267  	opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())}
   268  
   269  	log.Printf("[DEBUG] RDS Cluster Instance destroy configuration: %s", opts)
   270  	if _, err := conn.DeleteDBInstance(&opts); err != nil {
   271  		return err
   272  	}
   273  
   274  	// re-uses db_instance refresh func
   275  	log.Println("[INFO] Waiting for RDS Cluster Instance to be destroyed")
   276  	stateConf := &resource.StateChangeConf{
   277  		Pending:    []string{"modifying", "deleting"},
   278  		Target:     []string{},
   279  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   280  		Timeout:    40 * time.Minute,
   281  		MinTimeout: 10 * time.Second,
   282  	}
   283  
   284  	if _, err := stateConf.WaitForState(); err != nil {
   285  		return err
   286  	}
   287  
   288  	return nil
   289  
   290  }