github.com/ottenhoff/terraform@v0.7.0-rc1.0.20160607213102-ac2d195cc560/builtin/providers/aws/resource_aws_redshift_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/aws/aws-sdk-go/aws" 12 "github.com/aws/aws-sdk-go/aws/awserr" 13 "github.com/aws/aws-sdk-go/service/redshift" 14 "github.com/hashicorp/terraform/helper/hashcode" 15 "github.com/hashicorp/terraform/helper/resource" 16 "github.com/hashicorp/terraform/helper/schema" 17 ) 18 19 func resourceAwsRedshiftParameterGroup() *schema.Resource { 20 return &schema.Resource{ 21 Create: resourceAwsRedshiftParameterGroupCreate, 22 Read: resourceAwsRedshiftParameterGroupRead, 23 Update: resourceAwsRedshiftParameterGroupUpdate, 24 Delete: resourceAwsRedshiftParameterGroupDelete, 25 26 Schema: map[string]*schema.Schema{ 27 "name": &schema.Schema{ 28 Type: schema.TypeString, 29 ForceNew: true, 30 Required: true, 31 ValidateFunc: validateRedshiftParamGroupName, 32 }, 33 34 "family": &schema.Schema{ 35 Type: schema.TypeString, 36 Required: true, 37 ForceNew: true, 38 }, 39 40 "description": &schema.Schema{ 41 Type: schema.TypeString, 42 Optional: true, 43 ForceNew: true, 44 Default: "Managed by Terraform", 45 }, 46 47 "parameter": &schema.Schema{ 48 Type: schema.TypeSet, 49 Optional: true, 50 ForceNew: false, 51 Elem: &schema.Resource{ 52 Schema: map[string]*schema.Schema{ 53 "name": &schema.Schema{ 54 Type: schema.TypeString, 55 Required: true, 56 }, 57 "value": &schema.Schema{ 58 Type: schema.TypeString, 59 Required: true, 60 }, 61 }, 62 }, 63 Set: resourceAwsRedshiftParameterHash, 64 }, 65 }, 66 } 67 } 68 69 func resourceAwsRedshiftParameterGroupCreate(d *schema.ResourceData, meta interface{}) error { 70 conn := meta.(*AWSClient).redshiftconn 71 72 createOpts := redshift.CreateClusterParameterGroupInput{ 73 ParameterGroupName: aws.String(d.Get("name").(string)), 74 ParameterGroupFamily: aws.String(d.Get("family").(string)), 75 Description: aws.String(d.Get("description").(string)), 76 } 77 78 log.Printf("[DEBUG] Create Redshift Parameter Group: %#v", createOpts) 79 _, err := conn.CreateClusterParameterGroup(&createOpts) 80 if err != nil { 81 return fmt.Errorf("Error creating Redshift Parameter Group: %s", err) 82 } 83 84 d.SetId(*createOpts.ParameterGroupName) 85 log.Printf("[INFO] Redshift Parameter Group ID: %s", d.Id()) 86 87 return resourceAwsRedshiftParameterGroupUpdate(d, meta) 88 } 89 90 func resourceAwsRedshiftParameterGroupRead(d *schema.ResourceData, meta interface{}) error { 91 conn := meta.(*AWSClient).redshiftconn 92 93 describeOpts := redshift.DescribeClusterParameterGroupsInput{ 94 ParameterGroupName: aws.String(d.Id()), 95 } 96 97 describeResp, err := conn.DescribeClusterParameterGroups(&describeOpts) 98 if err != nil { 99 return err 100 } 101 102 if len(describeResp.ParameterGroups) != 1 || 103 *describeResp.ParameterGroups[0].ParameterGroupName != d.Id() { 104 d.SetId("") 105 return fmt.Errorf("Unable to find Parameter Group: %#v", describeResp.ParameterGroups) 106 } 107 108 d.Set("name", describeResp.ParameterGroups[0].ParameterGroupName) 109 d.Set("family", describeResp.ParameterGroups[0].ParameterGroupFamily) 110 d.Set("description", describeResp.ParameterGroups[0].Description) 111 112 describeParametersOpts := redshift.DescribeClusterParametersInput{ 113 ParameterGroupName: aws.String(d.Id()), 114 Source: aws.String("user"), 115 } 116 117 describeParametersResp, err := conn.DescribeClusterParameters(&describeParametersOpts) 118 if err != nil { 119 return err 120 } 121 122 d.Set("parameter", flattenRedshiftParameters(describeParametersResp.Parameters)) 123 return nil 124 } 125 126 func resourceAwsRedshiftParameterGroupUpdate(d *schema.ResourceData, meta interface{}) error { 127 conn := meta.(*AWSClient).redshiftconn 128 129 d.Partial(true) 130 131 if d.HasChange("parameter") { 132 o, n := d.GetChange("parameter") 133 if o == nil { 134 o = new(schema.Set) 135 } 136 if n == nil { 137 n = new(schema.Set) 138 } 139 140 os := o.(*schema.Set) 141 ns := n.(*schema.Set) 142 143 // Expand the "parameter" set to aws-sdk-go compat []redshift.Parameter 144 parameters, err := expandRedshiftParameters(ns.Difference(os).List()) 145 if err != nil { 146 return err 147 } 148 149 if len(parameters) > 0 { 150 modifyOpts := redshift.ModifyClusterParameterGroupInput{ 151 ParameterGroupName: aws.String(d.Get("name").(string)), 152 Parameters: parameters, 153 } 154 155 log.Printf("[DEBUG] Modify Redshift Parameter Group: %s", modifyOpts) 156 _, err = conn.ModifyClusterParameterGroup(&modifyOpts) 157 if err != nil { 158 return fmt.Errorf("Error modifying Redshift Parameter Group: %s", err) 159 } 160 } 161 d.SetPartial("parameter") 162 } 163 164 d.Partial(false) 165 return resourceAwsRedshiftParameterGroupRead(d, meta) 166 } 167 168 func resourceAwsRedshiftParameterGroupDelete(d *schema.ResourceData, meta interface{}) error { 169 stateConf := &resource.StateChangeConf{ 170 Pending: []string{"pending"}, 171 Target: []string{"destroyed"}, 172 Refresh: resourceAwsRedshiftParameterGroupDeleteRefreshFunc(d, meta), 173 Timeout: 3 * time.Minute, 174 MinTimeout: 1 * time.Second, 175 } 176 _, err := stateConf.WaitForState() 177 return err 178 } 179 180 func resourceAwsRedshiftParameterGroupDeleteRefreshFunc( 181 d *schema.ResourceData, 182 meta interface{}) resource.StateRefreshFunc { 183 conn := meta.(*AWSClient).redshiftconn 184 185 return func() (interface{}, string, error) { 186 187 deleteOpts := redshift.DeleteClusterParameterGroupInput{ 188 ParameterGroupName: aws.String(d.Id()), 189 } 190 191 if _, err := conn.DeleteClusterParameterGroup(&deleteOpts); err != nil { 192 redshiftErr, ok := err.(awserr.Error) 193 if !ok { 194 return d, "error", err 195 } 196 197 if redshiftErr.Code() != "RedshiftParameterGroupNotFoundFault" { 198 return d, "error", err 199 } 200 } 201 202 return d, "destroyed", nil 203 } 204 } 205 206 func resourceAwsRedshiftParameterHash(v interface{}) int { 207 var buf bytes.Buffer 208 m := v.(map[string]interface{}) 209 buf.WriteString(fmt.Sprintf("%s-", m["name"].(string))) 210 // Store the value as a lower case string, to match how we store them in flattenParameters 211 buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["value"].(string)))) 212 213 return hashcode.String(buf.String()) 214 } 215 216 func validateRedshiftParamGroupName(v interface{}, k string) (ws []string, errors []error) { 217 value := v.(string) 218 if !regexp.MustCompile(`^[0-9a-z-]+$`).MatchString(value) { 219 errors = append(errors, fmt.Errorf( 220 "only lowercase alphanumeric characters and hyphens allowed in %q", k)) 221 } 222 if !regexp.MustCompile(`^[a-z]`).MatchString(value) { 223 errors = append(errors, fmt.Errorf( 224 "first character of %q must be a letter", k)) 225 } 226 if regexp.MustCompile(`--`).MatchString(value) { 227 errors = append(errors, fmt.Errorf( 228 "%q cannot contain two consecutive hyphens", k)) 229 } 230 if regexp.MustCompile(`-$`).MatchString(value) { 231 errors = append(errors, fmt.Errorf( 232 "%q cannot end with a hyphen", k)) 233 } 234 if len(value) > 255 { 235 errors = append(errors, fmt.Errorf( 236 "%q cannot be greater than 255 characters", k)) 237 } 238 return 239 }