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