github.com/markdia/terraform@v0.5.1-0.20150508012022-f1ae920aa970/builtin/providers/aws/resource_aws_elasticache_cluster.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/awslabs/aws-sdk-go/aws" 9 "github.com/awslabs/aws-sdk-go/service/elasticache" 10 "github.com/hashicorp/terraform/helper/hashcode" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 ) 14 15 func resourceAwsElasticacheCluster() *schema.Resource { 16 return &schema.Resource{ 17 Create: resourceAwsElasticacheClusterCreate, 18 Read: resourceAwsElasticacheClusterRead, 19 Delete: resourceAwsElasticacheClusterDelete, 20 21 Schema: map[string]*schema.Schema{ 22 "cluster_id": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 ForceNew: true, 26 }, 27 "engine": &schema.Schema{ 28 Type: schema.TypeString, 29 Required: true, 30 ForceNew: true, 31 }, 32 "node_type": &schema.Schema{ 33 Type: schema.TypeString, 34 Required: true, 35 ForceNew: true, 36 }, 37 "num_cache_nodes": &schema.Schema{ 38 Type: schema.TypeInt, 39 Required: true, 40 ForceNew: true, 41 }, 42 "parameter_group_name": &schema.Schema{ 43 Type: schema.TypeString, 44 Optional: true, 45 ForceNew: true, 46 }, 47 "port": &schema.Schema{ 48 Type: schema.TypeInt, 49 Default: 11211, 50 Optional: true, 51 ForceNew: true, 52 }, 53 "engine_version": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 Computed: true, 57 ForceNew: true, 58 }, 59 "subnet_group_name": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 ForceNew: true, 63 }, 64 "security_group_names": &schema.Schema{ 65 Type: schema.TypeSet, 66 Optional: true, 67 Computed: true, 68 ForceNew: true, 69 Elem: &schema.Schema{Type: schema.TypeString}, 70 Set: func(v interface{}) int { 71 return hashcode.String(v.(string)) 72 }, 73 }, 74 "security_group_ids": &schema.Schema{ 75 Type: schema.TypeSet, 76 Optional: true, 77 Computed: true, 78 ForceNew: true, 79 Elem: &schema.Schema{Type: schema.TypeString}, 80 Set: func(v interface{}) int { 81 return hashcode.String(v.(string)) 82 }, 83 }, 84 }, 85 } 86 } 87 88 func resourceAwsElasticacheClusterCreate(d *schema.ResourceData, meta interface{}) error { 89 conn := meta.(*AWSClient).elasticacheconn 90 91 clusterId := d.Get("cluster_id").(string) 92 nodeType := d.Get("node_type").(string) // e.g) cache.m1.small 93 numNodes := int64(d.Get("num_cache_nodes").(int)) // 2 94 engine := d.Get("engine").(string) // memcached 95 engineVersion := d.Get("engine_version").(string) // 1.4.14 96 port := int64(d.Get("port").(int)) // 11211 97 subnetGroupName := d.Get("subnet_group_name").(string) 98 securityNameSet := d.Get("security_group_names").(*schema.Set) 99 securityIdSet := d.Get("security_group_ids").(*schema.Set) 100 paramGroupName := d.Get("parameter_group_name").(string) // default.memcached1.4 101 102 securityNames := expandStringList(securityNameSet.List()) 103 securityIds := expandStringList(securityIdSet.List()) 104 105 req := &elasticache.CreateCacheClusterInput{ 106 CacheClusterID: aws.String(clusterId), 107 CacheNodeType: aws.String(nodeType), 108 NumCacheNodes: aws.Long(numNodes), 109 Engine: aws.String(engine), 110 EngineVersion: aws.String(engineVersion), 111 Port: aws.Long(port), 112 CacheSubnetGroupName: aws.String(subnetGroupName), 113 CacheSecurityGroupNames: securityNames, 114 SecurityGroupIDs: securityIds, 115 CacheParameterGroupName: aws.String(paramGroupName), 116 } 117 118 _, err := conn.CreateCacheCluster(req) 119 if err != nil { 120 return fmt.Errorf("Error creating Elasticache: %s", err) 121 } 122 123 pending := []string{"creating"} 124 stateConf := &resource.StateChangeConf{ 125 Pending: pending, 126 Target: "available", 127 Refresh: CacheClusterStateRefreshFunc(conn, d.Id(), "available", pending), 128 Timeout: 10 * time.Minute, 129 Delay: 10 * time.Second, 130 MinTimeout: 3 * time.Second, 131 } 132 133 log.Printf("[DEBUG] Waiting for state to become available: %v", d.Id()) 134 _, sterr := stateConf.WaitForState() 135 if sterr != nil { 136 return fmt.Errorf("Error waiting for elasticache (%s) to be created: %s", d.Id(), sterr) 137 } 138 139 d.SetId(clusterId) 140 141 return nil 142 } 143 144 func resourceAwsElasticacheClusterRead(d *schema.ResourceData, meta interface{}) error { 145 conn := meta.(*AWSClient).elasticacheconn 146 req := &elasticache.DescribeCacheClustersInput{ 147 CacheClusterID: aws.String(d.Id()), 148 } 149 150 res, err := conn.DescribeCacheClusters(req) 151 if err != nil { 152 return err 153 } 154 155 if len(res.CacheClusters) == 1 { 156 c := res.CacheClusters[0] 157 d.Set("cluster_id", c.CacheClusterID) 158 d.Set("node_type", c.CacheNodeType) 159 d.Set("num_cache_nodes", c.NumCacheNodes) 160 d.Set("engine", c.Engine) 161 d.Set("engine_version", c.EngineVersion) 162 if c.ConfigurationEndpoint != nil { 163 d.Set("port", c.ConfigurationEndpoint.Port) 164 } 165 d.Set("subnet_group_name", c.CacheSubnetGroupName) 166 d.Set("security_group_names", c.CacheSecurityGroups) 167 d.Set("security_group_ids", c.SecurityGroups) 168 d.Set("parameter_group_name", c.CacheParameterGroup) 169 } 170 171 return nil 172 } 173 174 func resourceAwsElasticacheClusterDelete(d *schema.ResourceData, meta interface{}) error { 175 conn := meta.(*AWSClient).elasticacheconn 176 177 req := &elasticache.DeleteCacheClusterInput{ 178 CacheClusterID: aws.String(d.Id()), 179 } 180 _, err := conn.DeleteCacheCluster(req) 181 if err != nil { 182 return err 183 } 184 185 log.Printf("[DEBUG] Waiting for deletion: %v", d.Id()) 186 stateConf := &resource.StateChangeConf{ 187 Pending: []string{"creating", "available", "deleting", "incompatible-parameters", "incompatible-network", "restore-failed"}, 188 Target: "", 189 Refresh: CacheClusterStateRefreshFunc(conn, d.Id(), "", []string{}), 190 Timeout: 10 * time.Minute, 191 Delay: 10 * time.Second, 192 MinTimeout: 3 * time.Second, 193 } 194 195 _, sterr := stateConf.WaitForState() 196 if sterr != nil { 197 return fmt.Errorf("Error waiting for elasticache (%s) to delete: %s", d.Id(), sterr) 198 } 199 200 d.SetId("") 201 202 return nil 203 } 204 205 func CacheClusterStateRefreshFunc(conn *elasticache.ElastiCache, clusterID, givenState string, pending []string) resource.StateRefreshFunc { 206 return func() (interface{}, string, error) { 207 resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{ 208 CacheClusterID: aws.String(clusterID), 209 }) 210 if err != nil { 211 apierr := err.(aws.APIError) 212 log.Printf("[DEBUG] message: %v, code: %v", apierr.Message, apierr.Code) 213 if apierr.Message == fmt.Sprintf("CacheCluster not found: %v", clusterID) { 214 log.Printf("[DEBUG] Detect deletion") 215 return nil, "", nil 216 } 217 218 log.Printf("[ERROR] CacheClusterStateRefreshFunc: %s", err) 219 return nil, "", err 220 } 221 222 c := resp.CacheClusters[0] 223 log.Printf("[DEBUG] status: %v", *c.CacheClusterStatus) 224 225 // return the current state if it's in the pending array 226 for _, p := range pending { 227 s := *c.CacheClusterStatus 228 if p == s { 229 log.Printf("[DEBUG] Return with status: %v", *c.CacheClusterStatus) 230 return c, p, nil 231 } 232 } 233 234 // return given state if it's not in pending 235 if givenState != "" { 236 return c, givenState, nil 237 } 238 log.Printf("[DEBUG] current status: %v", *c.CacheClusterStatus) 239 return c, *c.CacheClusterStatus, nil 240 } 241 }