github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_db_parameter_group.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/terraform/helper/hashcode" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 14 "github.com/aws/aws-sdk-go/aws" 15 "github.com/aws/aws-sdk-go/aws/awserr" 16 "github.com/aws/aws-sdk-go/service/rds" 17 ) 18 19 func resourceAwsDbParameterGroup() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceAwsDbParameterGroupCreate, 22 Read: resourceAwsDbParameterGroupRead, 23 Update: resourceAwsDbParameterGroupUpdate, 24 Delete: resourceAwsDbParameterGroupDelete, 25 Importer: &schema.ResourceImporter{ 26 State: schema.ImportStatePassthrough, 27 }, 28 29 Schema: map[string]*schema.Schema{ 30 "arn": &schema.Schema{ 31 Type: schema.TypeString, 32 Computed: true, 33 }, 34 "name": &schema.Schema{ 35 Type: schema.TypeString, 36 ForceNew: true, 37 Required: true, 38 ValidateFunc: validateDbParamGroupName, 39 }, 40 "family": &schema.Schema{ 41 Type: schema.TypeString, 42 Required: true, 43 ForceNew: true, 44 }, 45 "description": &schema.Schema{ 46 Type: schema.TypeString, 47 Optional: true, 48 ForceNew: true, 49 Default: "Managed by Terraform", 50 }, 51 "parameter": &schema.Schema{ 52 Type: schema.TypeSet, 53 Optional: true, 54 ForceNew: false, 55 Elem: &schema.Resource{ 56 Schema: map[string]*schema.Schema{ 57 "name": &schema.Schema{ 58 Type: schema.TypeString, 59 Required: true, 60 }, 61 "value": &schema.Schema{ 62 Type: schema.TypeString, 63 Required: true, 64 }, 65 "apply_method": &schema.Schema{ 66 Type: schema.TypeString, 67 Optional: true, 68 Default: "immediate", 69 }, 70 }, 71 }, 72 Set: resourceAwsDbParameterHash, 73 }, 74 75 "tags": tagsSchema(), 76 }, 77 } 78 } 79 80 func resourceAwsDbParameterGroupCreate(d *schema.ResourceData, meta interface{}) error { 81 rdsconn := meta.(*AWSClient).rdsconn 82 tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{})) 83 84 createOpts := rds.CreateDBParameterGroupInput{ 85 DBParameterGroupName: aws.String(d.Get("name").(string)), 86 DBParameterGroupFamily: aws.String(d.Get("family").(string)), 87 Description: aws.String(d.Get("description").(string)), 88 Tags: tags, 89 } 90 91 log.Printf("[DEBUG] Create DB Parameter Group: %#v", createOpts) 92 _, err := rdsconn.CreateDBParameterGroup(&createOpts) 93 if err != nil { 94 return fmt.Errorf("Error creating DB Parameter Group: %s", err) 95 } 96 97 d.Partial(true) 98 d.SetPartial("name") 99 d.SetPartial("family") 100 d.SetPartial("description") 101 d.Partial(false) 102 103 d.SetId(*createOpts.DBParameterGroupName) 104 log.Printf("[INFO] DB Parameter Group ID: %s", d.Id()) 105 106 return resourceAwsDbParameterGroupUpdate(d, meta) 107 } 108 109 func resourceAwsDbParameterGroupRead(d *schema.ResourceData, meta interface{}) error { 110 rdsconn := meta.(*AWSClient).rdsconn 111 112 describeOpts := rds.DescribeDBParameterGroupsInput{ 113 DBParameterGroupName: aws.String(d.Id()), 114 } 115 116 describeResp, err := rdsconn.DescribeDBParameterGroups(&describeOpts) 117 if err != nil { 118 return err 119 } 120 121 if len(describeResp.DBParameterGroups) != 1 || 122 *describeResp.DBParameterGroups[0].DBParameterGroupName != d.Id() { 123 return fmt.Errorf("Unable to find Parameter Group: %#v", describeResp.DBParameterGroups) 124 } 125 126 d.Set("name", describeResp.DBParameterGroups[0].DBParameterGroupName) 127 d.Set("family", describeResp.DBParameterGroups[0].DBParameterGroupFamily) 128 d.Set("description", describeResp.DBParameterGroups[0].Description) 129 130 // Only include user customized parameters as there's hundreds of system/default ones 131 describeParametersOpts := rds.DescribeDBParametersInput{ 132 DBParameterGroupName: aws.String(d.Id()), 133 Source: aws.String("user"), 134 } 135 136 describeParametersResp, err := rdsconn.DescribeDBParameters(&describeParametersOpts) 137 if err != nil { 138 return err 139 } 140 141 d.Set("parameter", flattenParameters(describeParametersResp.Parameters)) 142 143 paramGroup := describeResp.DBParameterGroups[0] 144 arn, err := buildRDSPGARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region) 145 if err != nil { 146 name := "<empty>" 147 if paramGroup.DBParameterGroupName != nil && *paramGroup.DBParameterGroupName != "" { 148 name = *paramGroup.DBParameterGroupName 149 } 150 log.Printf("[DEBUG] Error building ARN for DB Parameter Group, not setting Tags for Param Group %s", name) 151 } else { 152 d.Set("arn", arn) 153 resp, err := rdsconn.ListTagsForResource(&rds.ListTagsForResourceInput{ 154 ResourceName: aws.String(arn), 155 }) 156 157 if err != nil { 158 log.Printf("[DEBUG] Error retrieving tags for ARN: %s", arn) 159 } 160 161 var dt []*rds.Tag 162 if len(resp.TagList) > 0 { 163 dt = resp.TagList 164 } 165 d.Set("tags", tagsToMapRDS(dt)) 166 } 167 168 return nil 169 } 170 171 func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { 172 rdsconn := meta.(*AWSClient).rdsconn 173 174 d.Partial(true) 175 176 if d.HasChange("parameter") { 177 o, n := d.GetChange("parameter") 178 if o == nil { 179 o = new(schema.Set) 180 } 181 if n == nil { 182 n = new(schema.Set) 183 } 184 185 os := o.(*schema.Set) 186 ns := n.(*schema.Set) 187 188 // Expand the "parameter" set to aws-sdk-go compat []rds.Parameter 189 parameters, err := expandParameters(ns.Difference(os).List()) 190 if err != nil { 191 return err 192 } 193 194 if len(parameters) > 0 { 195 // We can only modify 20 parameters at a time, so walk them until 196 // we've got them all. 197 maxParams := 20 198 for parameters != nil { 199 paramsToModify := make([]*rds.Parameter, 0) 200 if len(parameters) <= maxParams { 201 paramsToModify, parameters = parameters[:], nil 202 } else { 203 paramsToModify, parameters = parameters[:maxParams], parameters[maxParams:] 204 } 205 modifyOpts := rds.ModifyDBParameterGroupInput{ 206 DBParameterGroupName: aws.String(d.Get("name").(string)), 207 Parameters: paramsToModify, 208 } 209 210 log.Printf("[DEBUG] Modify DB Parameter Group: %s", modifyOpts) 211 _, err = rdsconn.ModifyDBParameterGroup(&modifyOpts) 212 if err != nil { 213 return fmt.Errorf("Error modifying DB Parameter Group: %s", err) 214 } 215 } 216 d.SetPartial("parameter") 217 } 218 } 219 220 if arn, err := buildRDSPGARN(d.Id(), meta.(*AWSClient).partition, meta.(*AWSClient).accountid, meta.(*AWSClient).region); err == nil { 221 if err := setTagsRDS(rdsconn, d, arn); err != nil { 222 return err 223 } else { 224 d.SetPartial("tags") 225 } 226 } 227 228 d.Partial(false) 229 230 return resourceAwsDbParameterGroupRead(d, meta) 231 } 232 233 func resourceAwsDbParameterGroupDelete(d *schema.ResourceData, meta interface{}) error { 234 stateConf := &resource.StateChangeConf{ 235 Pending: []string{"pending"}, 236 Target: []string{"destroyed"}, 237 Refresh: resourceAwsDbParameterGroupDeleteRefreshFunc(d, meta), 238 Timeout: 3 * time.Minute, 239 MinTimeout: 1 * time.Second, 240 } 241 _, err := stateConf.WaitForState() 242 return err 243 } 244 245 func resourceAwsDbParameterGroupDeleteRefreshFunc( 246 d *schema.ResourceData, 247 meta interface{}) resource.StateRefreshFunc { 248 rdsconn := meta.(*AWSClient).rdsconn 249 250 return func() (interface{}, string, error) { 251 252 deleteOpts := rds.DeleteDBParameterGroupInput{ 253 DBParameterGroupName: aws.String(d.Id()), 254 } 255 256 if _, err := rdsconn.DeleteDBParameterGroup(&deleteOpts); err != nil { 257 rdserr, ok := err.(awserr.Error) 258 if !ok { 259 return d, "error", err 260 } 261 262 if rdserr.Code() != "DBParameterGroupNotFoundFault" { 263 return d, "error", err 264 } 265 } 266 267 return d, "destroyed", nil 268 } 269 } 270 271 func resourceAwsDbParameterHash(v interface{}) int { 272 var buf bytes.Buffer 273 m := v.(map[string]interface{}) 274 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 275 // Store the value as a lower case string, to match how we store them in flattenParameters 276 buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["value"].(string)))) 277 278 return hashcode.String(buf.String()) 279 } 280 281 func buildRDSPGARN(identifier, partition, accountid, region string) (string, error) { 282 if partition == "" { 283 return "", fmt.Errorf("Unable to construct RDS ARN because of missing AWS partition") 284 } 285 if accountid == "" { 286 return "", fmt.Errorf("Unable to construct RDS ARN because of missing AWS Account ID") 287 } 288 arn := fmt.Sprintf("arn:%s:rds:%s:%s:pg:%s", partition, region, accountid, identifier) 289 return arn, nil 290 291 }