github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/builtin/providers/aws/resource_aws_db_parameter_group.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "regexp" 8 "strings" 9 "time" 10 11 "github.com/hashicorp/terraform/helper/hashcode" 12 "github.com/hashicorp/terraform/helper/resource" 13 "github.com/hashicorp/terraform/helper/schema" 14 15 "github.com/aws/aws-sdk-go/aws" 16 "github.com/aws/aws-sdk-go/aws/awserr" 17 "github.com/aws/aws-sdk-go/service/rds" 18 ) 19 20 func resourceAwsDbParameterGroup() *schema.Resource { 21 return &schema.Resource{ 22 Create: resourceAwsDbParameterGroupCreate, 23 Read: resourceAwsDbParameterGroupRead, 24 Update: resourceAwsDbParameterGroupUpdate, 25 Delete: resourceAwsDbParameterGroupDelete, 26 Schema: map[string]*schema.Schema{ 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 ForceNew: true, 30 Required: true, 31 ValidateFunc: validateDbParamGroupName, 32 }, 33 "family": &schema.Schema{ 34 Type: schema.TypeString, 35 Required: true, 36 ForceNew: true, 37 }, 38 "description": &schema.Schema{ 39 Type: schema.TypeString, 40 Required: true, 41 ForceNew: true, 42 }, 43 "parameter": &schema.Schema{ 44 Type: schema.TypeSet, 45 Optional: true, 46 ForceNew: false, 47 Elem: &schema.Resource{ 48 Schema: map[string]*schema.Schema{ 49 "name": &schema.Schema{ 50 Type: schema.TypeString, 51 Required: true, 52 }, 53 "value": &schema.Schema{ 54 Type: schema.TypeString, 55 Required: true, 56 }, 57 "apply_method": &schema.Schema{ 58 Type: schema.TypeString, 59 Optional: true, 60 Default: "immediate", 61 // this parameter is not actually state, but a 62 // meta-parameter describing how the RDS API call 63 // to modify the parameter group should be made. 64 // Future reads of the resource from AWS don't tell 65 // us what we used for apply_method previously, so 66 // by squashing state to an empty string we avoid 67 // needing to do an update for every future run. 68 StateFunc: func(interface{}) string { return "" }, 69 }, 70 }, 71 }, 72 Set: resourceAwsDbParameterHash, 73 }, 74 }, 75 } 76 } 77 78 func resourceAwsDbParameterGroupCreate(d *schema.ResourceData, meta interface{}) error { 79 rdsconn := meta.(*AWSClient).rdsconn 80 81 createOpts := rds.CreateDBParameterGroupInput{ 82 DBParameterGroupName: aws.String(d.Get("name").(string)), 83 DBParameterGroupFamily: aws.String(d.Get("family").(string)), 84 Description: aws.String(d.Get("description").(string)), 85 } 86 87 log.Printf("[DEBUG] Create DB Parameter Group: %#v", createOpts) 88 _, err := rdsconn.CreateDBParameterGroup(&createOpts) 89 if err != nil { 90 return fmt.Errorf("Error creating DB Parameter Group: %s", err) 91 } 92 93 d.Partial(true) 94 d.SetPartial("name") 95 d.SetPartial("family") 96 d.SetPartial("description") 97 d.Partial(false) 98 99 d.SetId(*createOpts.DBParameterGroupName) 100 log.Printf("[INFO] DB Parameter Group ID: %s", d.Id()) 101 102 return resourceAwsDbParameterGroupUpdate(d, meta) 103 } 104 105 func resourceAwsDbParameterGroupRead(d *schema.ResourceData, meta interface{}) error { 106 rdsconn := meta.(*AWSClient).rdsconn 107 108 describeOpts := rds.DescribeDBParameterGroupsInput{ 109 DBParameterGroupName: aws.String(d.Id()), 110 } 111 112 describeResp, err := rdsconn.DescribeDBParameterGroups(&describeOpts) 113 if err != nil { 114 return err 115 } 116 117 if len(describeResp.DBParameterGroups) != 1 || 118 *describeResp.DBParameterGroups[0].DBParameterGroupName != d.Id() { 119 return fmt.Errorf("Unable to find Parameter Group: %#v", describeResp.DBParameterGroups) 120 } 121 122 d.Set("name", describeResp.DBParameterGroups[0].DBParameterGroupName) 123 d.Set("family", describeResp.DBParameterGroups[0].DBParameterGroupFamily) 124 d.Set("description", describeResp.DBParameterGroups[0].Description) 125 126 // Only include user customized parameters as there's hundreds of system/default ones 127 describeParametersOpts := rds.DescribeDBParametersInput{ 128 DBParameterGroupName: aws.String(d.Id()), 129 Source: aws.String("user"), 130 } 131 132 describeParametersResp, err := rdsconn.DescribeDBParameters(&describeParametersOpts) 133 if err != nil { 134 return err 135 } 136 137 d.Set("parameter", flattenParameters(describeParametersResp.Parameters)) 138 139 return nil 140 } 141 142 func resourceAwsDbParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { 143 rdsconn := meta.(*AWSClient).rdsconn 144 145 d.Partial(true) 146 147 if d.HasChange("parameter") { 148 o, n := d.GetChange("parameter") 149 if o == nil { 150 o = new(schema.Set) 151 } 152 if n == nil { 153 n = new(schema.Set) 154 } 155 156 os := o.(*schema.Set) 157 ns := n.(*schema.Set) 158 159 // Expand the "parameter" set to aws-sdk-go compat []rds.Parameter 160 parameters, err := expandParameters(ns.Difference(os).List()) 161 if err != nil { 162 return err 163 } 164 165 if len(parameters) > 0 { 166 modifyOpts := rds.ModifyDBParameterGroupInput{ 167 DBParameterGroupName: aws.String(d.Get("name").(string)), 168 Parameters: parameters, 169 } 170 171 log.Printf("[DEBUG] Modify DB Parameter Group: %s", modifyOpts) 172 _, err = rdsconn.ModifyDBParameterGroup(&modifyOpts) 173 if err != nil { 174 return fmt.Errorf("Error modifying DB Parameter Group: %s", err) 175 } 176 } 177 d.SetPartial("parameter") 178 } 179 180 d.Partial(false) 181 182 return resourceAwsDbParameterGroupRead(d, meta) 183 } 184 185 func resourceAwsDbParameterGroupDelete(d *schema.ResourceData, meta interface{}) error { 186 stateConf := &resource.StateChangeConf{ 187 Pending: []string{"pending"}, 188 Target: "destroyed", 189 Refresh: resourceAwsDbParameterGroupDeleteRefreshFunc(d, meta), 190 Timeout: 3 * time.Minute, 191 MinTimeout: 1 * time.Second, 192 } 193 _, err := stateConf.WaitForState() 194 return err 195 } 196 197 func resourceAwsDbParameterGroupDeleteRefreshFunc( 198 d *schema.ResourceData, 199 meta interface{}) resource.StateRefreshFunc { 200 rdsconn := meta.(*AWSClient).rdsconn 201 202 return func() (interface{}, string, error) { 203 204 deleteOpts := rds.DeleteDBParameterGroupInput{ 205 DBParameterGroupName: aws.String(d.Id()), 206 } 207 208 if _, err := rdsconn.DeleteDBParameterGroup(&deleteOpts); err != nil { 209 rdserr, ok := err.(awserr.Error) 210 if !ok { 211 return d, "error", err 212 } 213 214 if rdserr.Code() != "DBParameterGroupNotFoundFault" { 215 return d, "error", err 216 } 217 } 218 219 return d, "destroyed", nil 220 } 221 } 222 223 func resourceAwsDbParameterHash(v interface{}) int { 224 var buf bytes.Buffer 225 m := v.(map[string]interface{}) 226 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 227 // Store the value as a lower case string, to match how we store them in flattenParameters 228 buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["value"].(string)))) 229 230 return hashcode.String(buf.String()) 231 } 232 233 func validateDbParamGroupName(v interface{}, k string) (ws []string, errors []error) { 234 value := v.(string) 235 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 236 errors = append(errors, fmt.Errorf( 237 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 238 } 239 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 240 errors = append(errors, fmt.Errorf( 241 "first character of %q must be a letter", k)) 242 } 243 if regexp.MustCompile(`--`).MatchString(value) { 244 errors = append(errors, fmt.Errorf( 245 "%q cannot contain two consecutive hyphens", k)) 246 } 247 if regexp.MustCompile(`-$`).MatchString(value) { 248 errors = append(errors, fmt.Errorf( 249 "%q cannot end with a hyphen", k)) 250 } 251 if len(value) > 255 { 252 errors = append(errors, fmt.Errorf( 253 "%q cannot be greater than 255 characters", k)) 254 } 255 return 256 257 }