github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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  		Importer: &schema.ResourceImporter{
    21  			State: schema.ImportStatePassthrough,
    22  		},
    23  
    24  		Schema: map[string]*schema.Schema{
    25  			"identifier": {
    26  				Type:         schema.TypeString,
    27  				Optional:     true,
    28  				ForceNew:     true,
    29  				ValidateFunc: validateRdsId,
    30  			},
    31  
    32  			"db_subnet_group_name": {
    33  				Type:     schema.TypeString,
    34  				Optional: true,
    35  				ForceNew: true,
    36  				Computed: true,
    37  			},
    38  
    39  			"writer": {
    40  				Type:     schema.TypeBool,
    41  				Computed: true,
    42  			},
    43  
    44  			"cluster_identifier": {
    45  				Type:     schema.TypeString,
    46  				Required: true,
    47  				ForceNew: true,
    48  			},
    49  
    50  			"endpoint": {
    51  				Type:     schema.TypeString,
    52  				Computed: true,
    53  			},
    54  
    55  			"port": {
    56  				Type:     schema.TypeInt,
    57  				Computed: true,
    58  			},
    59  
    60  			"publicly_accessible": {
    61  				Type:     schema.TypeBool,
    62  				Optional: true,
    63  				Default:  false,
    64  			},
    65  
    66  			"instance_class": {
    67  				Type:     schema.TypeString,
    68  				Required: true,
    69  			},
    70  
    71  			"db_parameter_group_name": {
    72  				Type:     schema.TypeString,
    73  				Optional: true,
    74  				Computed: true,
    75  			},
    76  
    77  			// apply_immediately is used to determine when the update modifications
    78  			// take place.
    79  			// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
    80  			"apply_immediately": {
    81  				Type:     schema.TypeBool,
    82  				Optional: true,
    83  				Computed: true,
    84  			},
    85  
    86  			"kms_key_id": {
    87  				Type:     schema.TypeString,
    88  				Computed: true,
    89  			},
    90  
    91  			"storage_encrypted": {
    92  				Type:     schema.TypeBool,
    93  				Computed: true,
    94  			},
    95  
    96  			"auto_minor_version_upgrade": {
    97  				Type:     schema.TypeBool,
    98  				Optional: true,
    99  				Default:  true,
   100  			},
   101  
   102  			"monitoring_role_arn": {
   103  				Type:     schema.TypeString,
   104  				Optional: true,
   105  				Computed: true,
   106  			},
   107  
   108  			"monitoring_interval": {
   109  				Type:     schema.TypeInt,
   110  				Optional: true,
   111  				Default:  0,
   112  			},
   113  
   114  			"promotion_tier": {
   115  				Type:     schema.TypeInt,
   116  				Optional: true,
   117  				Default:  0,
   118  			},
   119  
   120  			"tags": tagsSchema(),
   121  		},
   122  	}
   123  }
   124  
   125  func resourceAwsRDSClusterInstanceCreate(d *schema.ResourceData, meta interface{}) error {
   126  	conn := meta.(*AWSClient).rdsconn
   127  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
   128  
   129  	createOpts := &rds.CreateDBInstanceInput{
   130  		DBInstanceClass:         aws.String(d.Get("instance_class").(string)),
   131  		DBClusterIdentifier:     aws.String(d.Get("cluster_identifier").(string)),
   132  		Engine:                  aws.String("aurora"),
   133  		PubliclyAccessible:      aws.Bool(d.Get("publicly_accessible").(bool)),
   134  		PromotionTier:           aws.Int64(int64(d.Get("promotion_tier").(int))),
   135  		AutoMinorVersionUpgrade: aws.Bool(d.Get("auto_minor_version_upgrade").(bool)),
   136  		Tags: tags,
   137  	}
   138  
   139  	if attr, ok := d.GetOk("db_parameter_group_name"); ok {
   140  		createOpts.DBParameterGroupName = aws.String(attr.(string))
   141  	}
   142  
   143  	if v := d.Get("identifier").(string); v != "" {
   144  		createOpts.DBInstanceIdentifier = aws.String(v)
   145  	} else {
   146  		createOpts.DBInstanceIdentifier = aws.String(resource.UniqueId())
   147  	}
   148  
   149  	if attr, ok := d.GetOk("db_subnet_group_name"); ok {
   150  		createOpts.DBSubnetGroupName = aws.String(attr.(string))
   151  	}
   152  
   153  	if attr, ok := d.GetOk("monitoring_role_arn"); ok {
   154  		createOpts.MonitoringRoleArn = aws.String(attr.(string))
   155  	}
   156  
   157  	if attr, ok := d.GetOk("monitoring_interval"); ok {
   158  		createOpts.MonitoringInterval = aws.Int64(int64(attr.(int)))
   159  	}
   160  
   161  	log.Printf("[DEBUG] Creating RDS DB Instance opts: %s", createOpts)
   162  	resp, err := conn.CreateDBInstance(createOpts)
   163  	if err != nil {
   164  		return err
   165  	}
   166  
   167  	d.SetId(*resp.DBInstance.DBInstanceIdentifier)
   168  
   169  	// reuse db_instance refresh func
   170  	stateConf := &resource.StateChangeConf{
   171  		Pending:    []string{"creating", "backing-up", "modifying"},
   172  		Target:     []string{"available"},
   173  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   174  		Timeout:    40 * time.Minute,
   175  		MinTimeout: 10 * time.Second,
   176  		Delay:      10 * time.Second,
   177  	}
   178  
   179  	// Wait, catching any errors
   180  	_, err = stateConf.WaitForState()
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	return resourceAwsRDSClusterInstanceRead(d, meta)
   186  }
   187  
   188  func resourceAwsRDSClusterInstanceRead(d *schema.ResourceData, meta interface{}) error {
   189  	db, err := resourceAwsDbInstanceRetrieve(d, meta)
   190  	// Errors from this helper are always reportable
   191  	if err != nil {
   192  		return fmt.Errorf("[WARN] Error on retrieving RDS Cluster Instance (%s): %s", d.Id(), err)
   193  	}
   194  	// A nil response means "not found"
   195  	if db == nil {
   196  		log.Printf("[WARN] RDS Cluster Instance (%s): not found, removing from state.", d.Id())
   197  		d.SetId("")
   198  		return nil
   199  	}
   200  
   201  	// Retrieve DB Cluster information, to determine if this Instance is a writer
   202  	conn := meta.(*AWSClient).rdsconn
   203  	resp, err := conn.DescribeDBClusters(&rds.DescribeDBClustersInput{
   204  		DBClusterIdentifier: db.DBClusterIdentifier,
   205  	})
   206  
   207  	var dbc *rds.DBCluster
   208  	for _, c := range resp.DBClusters {
   209  		if *c.DBClusterIdentifier == *db.DBClusterIdentifier {
   210  			dbc = c
   211  		}
   212  	}
   213  
   214  	if dbc == nil {
   215  		return fmt.Errorf("[WARN] Error finding RDS Cluster (%s) for Cluster Instance (%s): %s",
   216  			*db.DBClusterIdentifier, *db.DBInstanceIdentifier, err)
   217  	}
   218  
   219  	for _, m := range dbc.DBClusterMembers {
   220  		if *db.DBInstanceIdentifier == *m.DBInstanceIdentifier {
   221  			if *m.IsClusterWriter == true {
   222  				d.Set("writer", true)
   223  			} else {
   224  				d.Set("writer", false)
   225  			}
   226  		}
   227  	}
   228  
   229  	if db.Endpoint != nil {
   230  		d.Set("endpoint", db.Endpoint.Address)
   231  		d.Set("port", db.Endpoint.Port)
   232  	}
   233  
   234  	d.Set("publicly_accessible", db.PubliclyAccessible)
   235  	d.Set("cluster_identifier", db.DBClusterIdentifier)
   236  	d.Set("instance_class", db.DBInstanceClass)
   237  	d.Set("identifier", db.DBInstanceIdentifier)
   238  	d.Set("storage_encrypted", db.StorageEncrypted)
   239  	d.Set("kms_key_id", db.KmsKeyId)
   240  	d.Set("auto_minor_version_upgrade", db.AutoMinorVersionUpgrade)
   241  	d.Set("promotion_tier", db.PromotionTier)
   242  
   243  	if db.MonitoringInterval != nil {
   244  		d.Set("monitoring_interval", db.MonitoringInterval)
   245  	}
   246  
   247  	if db.MonitoringRoleArn != nil {
   248  		d.Set("monitoring_role_arn", db.MonitoringRoleArn)
   249  	}
   250  
   251  	if len(db.DBParameterGroups) > 0 {
   252  		d.Set("db_parameter_group_name", db.DBParameterGroups[0].DBParameterGroupName)
   253  	}
   254  
   255  	// Fetch and save tags
   256  	arn, err := buildRDSARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region)
   257  	if err != nil {
   258  		log.Printf("[DEBUG] Error building ARN for RDS Cluster Instance (%s), not setting Tags", *db.DBInstanceIdentifier)
   259  	} else {
   260  		if err := saveTagsRDS(conn, d, arn); err != nil {
   261  			log.Printf("[WARN] Failed to save tags for RDS Cluster Instance (%s): %s", *db.DBClusterIdentifier, err)
   262  		}
   263  	}
   264  
   265  	return nil
   266  }
   267  
   268  func resourceAwsRDSClusterInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   269  	conn := meta.(*AWSClient).rdsconn
   270  	requestUpdate := false
   271  
   272  	req := &rds.ModifyDBInstanceInput{
   273  		ApplyImmediately:     aws.Bool(d.Get("apply_immediately").(bool)),
   274  		DBInstanceIdentifier: aws.String(d.Id()),
   275  	}
   276  
   277  	if d.HasChange("db_parameter_group_name") {
   278  		req.DBParameterGroupName = aws.String(d.Get("db_parameter_group_name").(string))
   279  		requestUpdate = true
   280  	}
   281  
   282  	if d.HasChange("instance_class") {
   283  		req.DBInstanceClass = aws.String(d.Get("instance_class").(string))
   284  		requestUpdate = true
   285  	}
   286  
   287  	if d.HasChange("monitoring_role_arn") {
   288  		d.SetPartial("monitoring_role_arn")
   289  		req.MonitoringRoleArn = aws.String(d.Get("monitoring_role_arn").(string))
   290  		requestUpdate = true
   291  	}
   292  
   293  	if d.HasChange("monitoring_interval") {
   294  		d.SetPartial("monitoring_interval")
   295  		req.MonitoringInterval = aws.Int64(int64(d.Get("monitoring_interval").(int)))
   296  		requestUpdate = true
   297  	}
   298  
   299  	if d.HasChange("auto_minor_version_upgrade") {
   300  		d.SetPartial("auto_minor_version_upgrade")
   301  		req.AutoMinorVersionUpgrade = aws.Bool(d.Get("auto_minor_version_upgrade").(bool))
   302  		requestUpdate = true
   303  	}
   304  
   305  	if d.HasChange("promotion_tier") {
   306  		d.SetPartial("promotion_tier")
   307  		req.PromotionTier = aws.Int64(int64(d.Get("promotion_tier").(int)))
   308  		requestUpdate = true
   309  	}
   310  
   311  	log.Printf("[DEBUG] Send DB Instance Modification request: %#v", requestUpdate)
   312  	if requestUpdate {
   313  		log.Printf("[DEBUG] DB Instance Modification request: %#v", req)
   314  		_, err := conn.ModifyDBInstance(req)
   315  		if err != nil {
   316  			return fmt.Errorf("Error modifying DB Instance %s: %s", d.Id(), err)
   317  		}
   318  
   319  		// reuse db_instance refresh func
   320  		stateConf := &resource.StateChangeConf{
   321  			Pending:    []string{"creating", "backing-up", "modifying"},
   322  			Target:     []string{"available"},
   323  			Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   324  			Timeout:    40 * time.Minute,
   325  			MinTimeout: 10 * time.Second,
   326  			Delay:      10 * time.Second,
   327  		}
   328  
   329  		// Wait, catching any errors
   330  		_, err = stateConf.WaitForState()
   331  		if err != nil {
   332  			return err
   333  		}
   334  
   335  	}
   336  
   337  	if arn, err := buildRDSARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil {
   338  		if err := setTagsRDS(conn, d, arn); err != nil {
   339  			return err
   340  		}
   341  	}
   342  
   343  	return resourceAwsRDSClusterInstanceRead(d, meta)
   344  }
   345  
   346  func resourceAwsRDSClusterInstanceDelete(d *schema.ResourceData, meta interface{}) error {
   347  	conn := meta.(*AWSClient).rdsconn
   348  
   349  	log.Printf("[DEBUG] RDS Cluster Instance destroy: %v", d.Id())
   350  
   351  	opts := rds.DeleteDBInstanceInput{DBInstanceIdentifier: aws.String(d.Id())}
   352  
   353  	log.Printf("[DEBUG] RDS Cluster Instance destroy configuration: %s", opts)
   354  	if _, err := conn.DeleteDBInstance(&opts); err != nil {
   355  		return err
   356  	}
   357  
   358  	// re-uses db_instance refresh func
   359  	log.Println("[INFO] Waiting for RDS Cluster Instance to be destroyed")
   360  	stateConf := &resource.StateChangeConf{
   361  		Pending:    []string{"modifying", "deleting"},
   362  		Target:     []string{},
   363  		Refresh:    resourceAwsDbInstanceStateRefreshFunc(d, meta),
   364  		Timeout:    40 * time.Minute,
   365  		MinTimeout: 10 * time.Second,
   366  	}
   367  
   368  	if _, err := stateConf.WaitForState(); err != nil {
   369  		return err
   370  	}
   371  
   372  	return nil
   373  
   374  }