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