github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_rds_cluster_instance.go (about)

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