github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_rds_cluster_parameter_group.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/aws/awserr"
    10  	"github.com/aws/aws-sdk-go/service/rds"
    11  
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  )
    15  
    16  func resourceAwsRDSClusterParameterGroup() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAwsRDSClusterParameterGroupCreate,
    19  		Read:   resourceAwsRDSClusterParameterGroupRead,
    20  		Update: resourceAwsRDSClusterParameterGroupUpdate,
    21  		Delete: resourceAwsRDSClusterParameterGroupDelete,
    22  		Importer: &schema.ResourceImporter{
    23  			State: schema.ImportStatePassthrough,
    24  		},
    25  
    26  		Schema: map[string]*schema.Schema{
    27  			"arn": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Computed: true,
    30  			},
    31  			"name": &schema.Schema{
    32  				Type:          schema.TypeString,
    33  				Optional:      true,
    34  				Computed:      true,
    35  				ForceNew:      true,
    36  				ConflictsWith: []string{"name_prefix"},
    37  				ValidateFunc:  validateDbParamGroupName,
    38  			},
    39  			"name_prefix": &schema.Schema{
    40  				Type:         schema.TypeString,
    41  				Optional:     true,
    42  				Computed:     true,
    43  				ForceNew:     true,
    44  				ValidateFunc: validateDbParamGroupNamePrefix,
    45  			},
    46  			"family": &schema.Schema{
    47  				Type:     schema.TypeString,
    48  				Required: true,
    49  				ForceNew: true,
    50  			},
    51  			"description": &schema.Schema{
    52  				Type:     schema.TypeString,
    53  				Optional: true,
    54  				ForceNew: true,
    55  				Default:  "Managed by Terraform",
    56  			},
    57  			"parameter": &schema.Schema{
    58  				Type:     schema.TypeSet,
    59  				Optional: true,
    60  				ForceNew: false,
    61  				Elem: &schema.Resource{
    62  					Schema: map[string]*schema.Schema{
    63  						"name": &schema.Schema{
    64  							Type:     schema.TypeString,
    65  							Required: true,
    66  						},
    67  						"value": &schema.Schema{
    68  							Type:     schema.TypeString,
    69  							Required: true,
    70  						},
    71  						"apply_method": &schema.Schema{
    72  							Type:     schema.TypeString,
    73  							Optional: true,
    74  							Default:  "immediate",
    75  							// this parameter is not actually state, but a
    76  							// meta-parameter describing how the RDS API call
    77  							// to modify the parameter group should be made.
    78  							// Future reads of the resource from AWS don't tell
    79  							// us what we used for apply_method previously, so
    80  							// by squashing state to an empty string we avoid
    81  							// needing to do an update for every future run.
    82  							StateFunc: func(interface{}) string { return "" },
    83  						},
    84  					},
    85  				},
    86  				Set: resourceAwsDbParameterHash,
    87  			},
    88  
    89  			"tags": tagsSchema(),
    90  		},
    91  	}
    92  }
    93  
    94  func resourceAwsRDSClusterParameterGroupCreate(d *schema.ResourceData, meta interface{}) error {
    95  	rdsconn := meta.(*AWSClient).rdsconn
    96  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
    97  
    98  	var groupName string
    99  	if v, ok := d.GetOk("name"); ok {
   100  		groupName = v.(string)
   101  	} else if v, ok := d.GetOk("name_prefix"); ok {
   102  		groupName = resource.PrefixedUniqueId(v.(string))
   103  	} else {
   104  		groupName = resource.UniqueId()
   105  	}
   106  
   107  	createOpts := rds.CreateDBClusterParameterGroupInput{
   108  		DBClusterParameterGroupName: aws.String(groupName),
   109  		DBParameterGroupFamily:      aws.String(d.Get("family").(string)),
   110  		Description:                 aws.String(d.Get("description").(string)),
   111  		Tags:                        tags,
   112  	}
   113  
   114  	log.Printf("[DEBUG] Create DB Cluster Parameter Group: %#v", createOpts)
   115  	_, err := rdsconn.CreateDBClusterParameterGroup(&createOpts)
   116  	if err != nil {
   117  		return fmt.Errorf("Error creating DB Cluster Parameter Group: %s", err)
   118  	}
   119  
   120  	d.SetId(*createOpts.DBClusterParameterGroupName)
   121  	log.Printf("[INFO] DB Cluster Parameter Group ID: %s", d.Id())
   122  
   123  	return resourceAwsRDSClusterParameterGroupUpdate(d, meta)
   124  }
   125  
   126  func resourceAwsRDSClusterParameterGroupRead(d *schema.ResourceData, meta interface{}) error {
   127  	rdsconn := meta.(*AWSClient).rdsconn
   128  
   129  	describeOpts := rds.DescribeDBClusterParameterGroupsInput{
   130  		DBClusterParameterGroupName: aws.String(d.Id()),
   131  	}
   132  
   133  	describeResp, err := rdsconn.DescribeDBClusterParameterGroups(&describeOpts)
   134  	if err != nil {
   135  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "DBParameterGroupNotFound" {
   136  			log.Printf("[WARN] DB Cluster Parameter Group (%s) not found, error code (404)", d.Id())
   137  			d.SetId("")
   138  			return nil
   139  		}
   140  
   141  		return err
   142  	}
   143  
   144  	if len(describeResp.DBClusterParameterGroups) != 1 ||
   145  		*describeResp.DBClusterParameterGroups[0].DBClusterParameterGroupName != d.Id() {
   146  		return fmt.Errorf("Unable to find Cluster Parameter Group: %#v", describeResp.DBClusterParameterGroups)
   147  	}
   148  
   149  	d.Set("name", describeResp.DBClusterParameterGroups[0].DBClusterParameterGroupName)
   150  	d.Set("family", describeResp.DBClusterParameterGroups[0].DBParameterGroupFamily)
   151  	d.Set("description", describeResp.DBClusterParameterGroups[0].Description)
   152  
   153  	// Only include user customized parameters as there's hundreds of system/default ones
   154  	describeParametersOpts := rds.DescribeDBClusterParametersInput{
   155  		DBClusterParameterGroupName: aws.String(d.Id()),
   156  		Source: aws.String("user"),
   157  	}
   158  
   159  	describeParametersResp, err := rdsconn.DescribeDBClusterParameters(&describeParametersOpts)
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	d.Set("parameter", flattenParameters(describeParametersResp.Parameters))
   165  
   166  	paramGroup := describeResp.DBClusterParameterGroups[0]
   167  	arn, err := buildRDSCPGARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region)
   168  	if err != nil {
   169  		name := "<empty>"
   170  		if paramGroup.DBClusterParameterGroupName != nil && *paramGroup.DBClusterParameterGroupName != "" {
   171  			name = *paramGroup.DBClusterParameterGroupName
   172  		}
   173  		log.Printf("[DEBUG] Error building ARN for DB Cluster Parameter Group, not setting Tags for Cluster Param Group %s", name)
   174  	} else {
   175  		d.Set("arn", arn)
   176  		resp, err := rdsconn.ListTagsForResource(&rds.ListTagsForResourceInput{
   177  			ResourceName: aws.String(arn),
   178  		})
   179  
   180  		if err != nil {
   181  			log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn)
   182  		}
   183  
   184  		var dt []*rds.Tag
   185  		if len(resp.TagList) > 0 {
   186  			dt = resp.TagList
   187  		}
   188  		d.Set("tags", tagsToMapRDS(dt))
   189  	}
   190  
   191  	return nil
   192  }
   193  
   194  func resourceAwsRDSClusterParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   195  	rdsconn := meta.(*AWSClient).rdsconn
   196  
   197  	d.Partial(true)
   198  
   199  	if d.HasChange("parameter") {
   200  		o, n := d.GetChange("parameter")
   201  		if o == nil {
   202  			o = new(schema.Set)
   203  		}
   204  		if n == nil {
   205  			n = new(schema.Set)
   206  		}
   207  
   208  		os := o.(*schema.Set)
   209  		ns := n.(*schema.Set)
   210  
   211  		// Expand the "parameter" set to aws-sdk-go compat []rds.Parameter
   212  		parameters, err := expandParameters(ns.Difference(os).List())
   213  		if err != nil {
   214  			return err
   215  		}
   216  
   217  		if len(parameters) > 0 {
   218  			modifyOpts := rds.ModifyDBClusterParameterGroupInput{
   219  				DBClusterParameterGroupName: aws.String(d.Get("name").(string)),
   220  				Parameters:                  parameters,
   221  			}
   222  
   223  			log.Printf("[DEBUG] Modify DB Cluster Parameter Group: %s", modifyOpts)
   224  			_, err = rdsconn.ModifyDBClusterParameterGroup(&modifyOpts)
   225  			if err != nil {
   226  				return fmt.Errorf("Error modifying DB Cluster Parameter Group: %s", err)
   227  			}
   228  		}
   229  		d.SetPartial("parameter")
   230  	}
   231  
   232  	if arn, err := buildRDSCPGARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil {
   233  		if err := setTagsRDS(rdsconn, d, arn); err != nil {
   234  			return err
   235  		} else {
   236  			d.SetPartial("tags")
   237  		}
   238  	}
   239  
   240  	d.Partial(false)
   241  
   242  	return resourceAwsRDSClusterParameterGroupRead(d, meta)
   243  }
   244  
   245  func resourceAwsRDSClusterParameterGroupDelete(d *schema.ResourceData, meta interface{}) error {
   246  	stateConf := &resource.StateChangeConf{
   247  		Pending:    []string{"pending"},
   248  		Target:     []string{"destroyed"},
   249  		Refresh:    resourceAwsRDSClusterParameterGroupDeleteRefreshFunc(d, meta),
   250  		Timeout:    3 * time.Minute,
   251  		MinTimeout: 1 * time.Second,
   252  	}
   253  	_, err := stateConf.WaitForState()
   254  	return err
   255  }
   256  
   257  func resourceAwsRDSClusterParameterGroupDeleteRefreshFunc(
   258  	d *schema.ResourceData,
   259  	meta interface{}) resource.StateRefreshFunc {
   260  	rdsconn := meta.(*AWSClient).rdsconn
   261  
   262  	return func() (interface{}, string, error) {
   263  
   264  		deleteOpts := rds.DeleteDBClusterParameterGroupInput{
   265  			DBClusterParameterGroupName: aws.String(d.Id()),
   266  		}
   267  
   268  		if _, err := rdsconn.DeleteDBClusterParameterGroup(&deleteOpts); err != nil {
   269  			rdserr, ok := err.(awserr.Error)
   270  			if !ok {
   271  				return d, "error", err
   272  			}
   273  
   274  			if rdserr.Code() != "DBParameterGroupNotFound" {
   275  				return d, "error", err
   276  			}
   277  		}
   278  
   279  		return d, "destroyed", nil
   280  	}
   281  }
   282  
   283  func buildRDSCPGARN(identifier, partition, accountid, region string) (string, error) {
   284  	if partition == "" {
   285  		return "", fmt.Errorf("Unable to construct RDS Cluster ARN because of missing AWS partition")
   286  	}
   287  	if accountid == "" {
   288  		return "", fmt.Errorf("Unable to construct RDS Cluster ARN because of missing AWS Account ID")
   289  	}
   290  	arn := fmt.Sprintf("arn:%s:rds:%s:%s:cluster-pg:%s", partition, region, accountid, identifier)
   291  	return arn, nil
   292  
   293  }