github.com/blacked/terraform@v0.6.2-0.20150806163846-669c4ad71586/builtin/providers/aws/resource_aws_elasticache_replication_group.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"time"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/aws/awserr"
    10  	"github.com/aws/aws-sdk-go/service/elasticache"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  )
    14  
    15  func resourceAwsElasticacheReplicationGroup() *schema.Resource {
    16  	return &schema.Resource{
    17  		Create: resourceAwsElasticacheReplicationGroupCreate,
    18  		Read:   resourceAwsElasticacheReplicationGroupRead,
    19  		Update: resourceAwsElasticacheReplicationGroupUpdate,
    20  		Delete: resourceAwsElasticacheReplicationGroupDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"replication_group_id": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  				ForceNew: true,
    27  			},
    28  			"description": &schema.Schema{
    29  				Type:     schema.TypeString,
    30  				Required: true,
    31  			},
    32  			"cache_node_type": &schema.Schema{
    33  				Type:     schema.TypeString,
    34  				Optional: true,
    35  				ForceNew: true,
    36  			},
    37  			"automatic_failover": &schema.Schema{
    38  				Type:     schema.TypeBool,
    39  				Optional: true,
    40  			},
    41  			"num_cache_clusters": &schema.Schema{
    42  				Type:     schema.TypeInt,
    43  				Optional: true,
    44  				Default:  1,
    45  				ForceNew: true,
    46  			},
    47  			"parameter_group_name": &schema.Schema{
    48  				Type:     schema.TypeString,
    49  				Optional: true,
    50  			},
    51  			"subnet_group_name": &schema.Schema{
    52  				Type:     schema.TypeString,
    53  				Optional: true,
    54  				ForceNew: true,
    55  			},
    56  			"security_group_names": &schema.Schema{
    57  				Type:     schema.TypeSet,
    58  				Optional: true,
    59  				Computed: true,
    60  				Elem:     &schema.Schema{Type: schema.TypeString},
    61  				Set:      schema.HashString,
    62  			},
    63  			"security_group_ids": &schema.Schema{
    64  				Type:     schema.TypeSet,
    65  				Optional: true,
    66  				Computed: true,
    67  				Elem:     &schema.Schema{Type: schema.TypeString},
    68  				Set:      schema.HashString,
    69  			},
    70  			"engine": &schema.Schema{
    71  				Type:     schema.TypeString,
    72  				Optional: true,
    73  				ForceNew: true,
    74  				Default:  "redis",
    75  			},
    76  			"engine_version": &schema.Schema{
    77  				Type:     schema.TypeString,
    78  				Optional: true,
    79  			},
    80  			"primary_endpoint": &schema.Schema{
    81  				Type:     schema.TypeString,
    82  				Computed: true,
    83  			},
    84  		},
    85  	}
    86  }
    87  
    88  func resourceAwsElasticacheReplicationGroupCreate(d *schema.ResourceData, meta interface{}) error {
    89  	conn := meta.(*AWSClient).elasticacheconn
    90  
    91  	replicationGroupId := d.Get("replication_group_id").(string)
    92  	description := d.Get("description").(string)
    93  	cacheNodeType := d.Get("cache_node_type").(string)
    94  	automaticFailover := d.Get("automatic_failover").(bool)
    95  	numCacheClusters := d.Get("num_cache_clusters").(int)
    96  	engine := d.Get("engine").(string)
    97  	engineVersion := d.Get("engine_version").(string)
    98  	securityNameSet := d.Get("security_group_names").(*schema.Set)
    99  	securityIdSet := d.Get("security_group_ids").(*schema.Set)
   100  	subnetGroupName := d.Get("subnet_group_name").(string)
   101  
   102  	securityNames := expandStringList(securityNameSet.List())
   103  	securityIds := expandStringList(securityIdSet.List())
   104  
   105  	req := &elasticache.CreateReplicationGroupInput{
   106  		ReplicationGroupID:          aws.String(replicationGroupId),
   107  		ReplicationGroupDescription: aws.String(description),
   108  		CacheNodeType:               aws.String(cacheNodeType),
   109  		AutomaticFailoverEnabled:    aws.Bool(automaticFailover),
   110  		NumCacheClusters:            aws.Int64(int64(numCacheClusters)),
   111  		Engine:                      aws.String(engine),
   112  		CacheSubnetGroupName:        aws.String(subnetGroupName),
   113  		EngineVersion:               aws.String(engineVersion),
   114  		CacheSecurityGroupNames:     securityNames,
   115  		SecurityGroupIDs:            securityIds,
   116  	}
   117  
   118  	if v, ok := d.GetOk("parameter_group_name"); ok {
   119  		req.CacheParameterGroupName = aws.String(v.(string))
   120  	}
   121  
   122  	_, err := conn.CreateReplicationGroup(req)
   123  	if err != nil {
   124  		return fmt.Errorf("Error creating Elasticache replication group: %s", err)
   125  	}
   126  
   127  	pending := []string{"creating"}
   128  	stateConf := &resource.StateChangeConf{
   129  		Pending:    pending,
   130  		Target:     "available",
   131  		Refresh:    ReplicationGroupStateRefreshFunc(conn, d.Id(), "available", pending),
   132  		Timeout:    60 * time.Minute,
   133  		Delay:      20 * time.Second,
   134  		MinTimeout: 5 * time.Second,
   135  	}
   136  
   137  	log.Printf("[DEBUG] Waiting for state to become available: %v", d.Id())
   138  	_, sterr := stateConf.WaitForState()
   139  	if sterr != nil {
   140  		return fmt.Errorf("Error waiting for elasticache (%s) to be created: %s", d.Id(), sterr)
   141  	}
   142  
   143  	d.SetId(replicationGroupId)
   144  
   145  	return nil
   146  }
   147  
   148  func resourceAwsElasticacheReplicationGroupRead(d *schema.ResourceData, meta interface{}) error {
   149  	conn := meta.(*AWSClient).elasticacheconn
   150  
   151  	req := &elasticache.DescribeReplicationGroupsInput{
   152  		ReplicationGroupID: aws.String(d.Id()),
   153  	}
   154  
   155  	res, err := conn.DescribeReplicationGroups(req)
   156  	if err != nil {
   157  		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "ReplicationGroupNotFoundFault" {
   158  			// Update state to indicate the replication group no longer exists.
   159  			d.SetId("")
   160  			return nil
   161  		}
   162  
   163  		return err
   164  	}
   165  
   166  	if len(res.ReplicationGroups) == 1 {
   167  		c := res.ReplicationGroups[0]
   168  		d.Set("replication_group_id", c.ReplicationGroupID)
   169  		d.Set("description", c.Description)
   170  		d.Set("automatic_failover", c.AutomaticFailover)
   171  		d.Set("num_cache_clusters", len(c.MemberClusters))
   172  	}
   173  	d.Set("primary_endpoint", res.ReplicationGroups[0].NodeGroups[0].PrimaryEndpoint.Address)
   174  
   175  	return nil
   176  }
   177  
   178  func resourceAwsElasticacheReplicationGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   179  	conn := meta.(*AWSClient).elasticacheconn
   180  
   181  	req := &elasticache.ModifyReplicationGroupInput{
   182  		ApplyImmediately:   aws.Bool(true),
   183  		ReplicationGroupID: aws.String(d.Id()),
   184  	}
   185  
   186  	if d.HasChange("automatic_failover") {
   187  		automaticFailover := d.Get("automatic_failover").(bool)
   188  		req.AutomaticFailoverEnabled = aws.Bool(automaticFailover)
   189  	}
   190  
   191  	if d.HasChange("description") {
   192  		description := d.Get("description").(string)
   193  		req.ReplicationGroupDescription = aws.String(description)
   194  	}
   195  
   196  	if d.HasChange("engine_version") {
   197  		engine_version := d.Get("engine_version").(string)
   198  		req.EngineVersion = aws.String(engine_version)
   199  	}
   200  
   201  	if d.HasChange("security_group_ids") {
   202  		securityIdSet := d.Get("security_group_ids").(*schema.Set)
   203  		securityIds := expandStringList(securityIdSet.List())
   204  		req.SecurityGroupIDs = securityIds
   205  	}
   206  
   207  	if d.HasChange("security_group_names") {
   208  		securityNameSet := d.Get("security_group_names").(*schema.Set)
   209  		securityNames := expandStringList(securityNameSet.List())
   210  		req.CacheSecurityGroupNames = securityNames
   211  	}
   212  
   213  	_, err := conn.ModifyReplicationGroup(req)
   214  	if err != nil {
   215  		return fmt.Errorf("Error updating Elasticache replication group: %s", err)
   216  	}
   217  
   218  	return resourceAwsElasticacheReplicationGroupRead(d, meta)
   219  }
   220  
   221  func resourceAwsElasticacheReplicationGroupDelete(d *schema.ResourceData, meta interface{}) error {
   222  	conn := meta.(*AWSClient).elasticacheconn
   223  
   224  	req := &elasticache.DeleteReplicationGroupInput{
   225  		ReplicationGroupID: aws.String(d.Id()),
   226  	}
   227  
   228  	_, err := conn.DeleteReplicationGroup(req)
   229  	if err != nil {
   230  		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "ReplicationGroupNotFoundFault" {
   231  			// Update state to indicate the replication group no longer exists.
   232  			d.SetId("")
   233  			return nil
   234  		}
   235  
   236  		return fmt.Errorf("Error deleting Elasticache replication group: %s", err)
   237  	}
   238  
   239  	log.Printf("[DEBUG] Waiting for deletion: %v", d.Id())
   240  	stateConf := &resource.StateChangeConf{
   241  		Pending:    []string{"creating", "available", "deleting"},
   242  		Target:     "",
   243  		Refresh:    ReplicationGroupStateRefreshFunc(conn, d.Id(), "", []string{}),
   244  		Timeout:    15 * time.Minute,
   245  		Delay:      20 * time.Second,
   246  		MinTimeout: 5 * time.Second,
   247  	}
   248  
   249  	_, sterr := stateConf.WaitForState()
   250  	if sterr != nil {
   251  		return fmt.Errorf("Error waiting for replication group (%s) to delete: %s", d.Id(), sterr)
   252  	}
   253  
   254  	return nil
   255  }
   256  
   257  func ReplicationGroupStateRefreshFunc(conn *elasticache.ElastiCache, replicationGroupID, givenState string, pending []string) resource.StateRefreshFunc {
   258  	return func() (interface{}, string, error) {
   259  		resp, err := conn.DescribeReplicationGroups(&elasticache.DescribeReplicationGroupsInput{
   260  			ReplicationGroupID: aws.String(replicationGroupID),
   261  		})
   262  		if err != nil {
   263  			ec2err, ok := err.(awserr.Error)
   264  
   265  			if ok {
   266  				log.Printf("[DEBUG] message: %v, code: %v", ec2err.Message(), ec2err.Code())
   267  				if ec2err.Code() == "ReplicationGroupNotFoundFault" {
   268  					log.Printf("[DEBUG] Detect deletion")
   269  					return nil, "", nil
   270  				}
   271  			}
   272  
   273  			log.Printf("[ERROR] ReplicationGroupStateRefreshFunc: %s", err)
   274  			return nil, "", err
   275  		}
   276  
   277  		c := resp.ReplicationGroups[0]
   278  		log.Printf("[DEBUG] status: %v", *c.Status)
   279  
   280  		// return the current state if it's in the pending array
   281  		for _, p := range pending {
   282  			s := *c.Status
   283  			if p == s {
   284  				log.Printf("[DEBUG] Return with status: %v", *c.Status)
   285  				return c, p, nil
   286  			}
   287  		}
   288  
   289  		// return given state if it's not in pending
   290  		if givenState != "" {
   291  			return c, givenState, nil
   292  		}
   293  		log.Printf("[DEBUG] current status: %v", *c.Status)
   294  		return c, *c.Status, nil
   295  	}
   296  }