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