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