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  }