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