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