github.com/shvar/terraform@v0.6.9-0.20151215234924-3365cd2231df/builtin/providers/aws/resource_aws_db_subnet_group.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"regexp"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/aws/aws-sdk-go/aws"
    11  	"github.com/aws/aws-sdk-go/aws/awserr"
    12  	"github.com/aws/aws-sdk-go/service/iam"
    13  	"github.com/aws/aws-sdk-go/service/rds"
    14  	"github.com/hashicorp/terraform/helper/resource"
    15  	"github.com/hashicorp/terraform/helper/schema"
    16  )
    17  
    18  func resourceAwsDbSubnetGroup() *schema.Resource {
    19  	return &schema.Resource{
    20  		Create: resourceAwsDbSubnetGroupCreate,
    21  		Read:   resourceAwsDbSubnetGroupRead,
    22  		Update: resourceAwsDbSubnetGroupUpdate,
    23  		Delete: resourceAwsDbSubnetGroupDelete,
    24  
    25  		Schema: map[string]*schema.Schema{
    26  			"arn": &schema.Schema{
    27  				Type:     schema.TypeString,
    28  				Computed: true,
    29  			},
    30  
    31  			"name": &schema.Schema{
    32  				Type:     schema.TypeString,
    33  				ForceNew: true,
    34  				Required: true,
    35  				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    36  					value := v.(string)
    37  					if !regexp.MustCompile(`^[ .0-9A-Za-z-_]+$`).MatchString(value) {
    38  						errors = append(errors, fmt.Errorf(
    39  							"only alphanumeric characters, hyphens, underscores, periods, and spaces allowed in %q", k))
    40  					}
    41  					if len(value) > 255 {
    42  						errors = append(errors, fmt.Errorf(
    43  							"%q cannot be longer than 255 characters", k))
    44  					}
    45  					if regexp.MustCompile(`(?i)^default$`).MatchString(value) {
    46  						errors = append(errors, fmt.Errorf(
    47  							"%q is not allowed as %q", "Default", k))
    48  					}
    49  					return
    50  				},
    51  			},
    52  
    53  			"description": &schema.Schema{
    54  				Type:     schema.TypeString,
    55  				Required: true,
    56  				ForceNew: true,
    57  			},
    58  
    59  			"subnet_ids": &schema.Schema{
    60  				Type:     schema.TypeSet,
    61  				Required: true,
    62  				Elem:     &schema.Schema{Type: schema.TypeString},
    63  				Set:      schema.HashString,
    64  			},
    65  
    66  			"tags": tagsSchema(),
    67  		},
    68  	}
    69  }
    70  
    71  func resourceAwsDbSubnetGroupCreate(d *schema.ResourceData, meta interface{}) error {
    72  	rdsconn := meta.(*AWSClient).rdsconn
    73  	tags := tagsFromMapRDS(d.Get("tags").(map[string]interface{}))
    74  
    75  	subnetIdsSet := d.Get("subnet_ids").(*schema.Set)
    76  	subnetIds := make([]*string, subnetIdsSet.Len())
    77  	for i, subnetId := range subnetIdsSet.List() {
    78  		subnetIds[i] = aws.String(subnetId.(string))
    79  	}
    80  
    81  	createOpts := rds.CreateDBSubnetGroupInput{
    82  		DBSubnetGroupName:        aws.String(d.Get("name").(string)),
    83  		DBSubnetGroupDescription: aws.String(d.Get("description").(string)),
    84  		SubnetIds:                subnetIds,
    85  		Tags:                     tags,
    86  	}
    87  
    88  	log.Printf("[DEBUG] Create DB Subnet Group: %#v", createOpts)
    89  	_, err := rdsconn.CreateDBSubnetGroup(&createOpts)
    90  	if err != nil {
    91  		return fmt.Errorf("Error creating DB Subnet Group: %s", err)
    92  	}
    93  
    94  	d.SetId(*createOpts.DBSubnetGroupName)
    95  	log.Printf("[INFO] DB Subnet Group ID: %s", d.Id())
    96  	return resourceAwsDbSubnetGroupRead(d, meta)
    97  }
    98  
    99  func resourceAwsDbSubnetGroupRead(d *schema.ResourceData, meta interface{}) error {
   100  	rdsconn := meta.(*AWSClient).rdsconn
   101  
   102  	describeOpts := rds.DescribeDBSubnetGroupsInput{
   103  		DBSubnetGroupName: aws.String(d.Id()),
   104  	}
   105  
   106  	describeResp, err := rdsconn.DescribeDBSubnetGroups(&describeOpts)
   107  	if err != nil {
   108  		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "DBSubnetGroupNotFoundFault" {
   109  			// Update state to indicate the db subnet no longer exists.
   110  			d.SetId("")
   111  			return nil
   112  		}
   113  		return err
   114  	}
   115  
   116  	if len(describeResp.DBSubnetGroups) == 0 {
   117  		return fmt.Errorf("Unable to find DB Subnet Group: %#v", describeResp.DBSubnetGroups)
   118  	}
   119  
   120  	var subnetGroup *rds.DBSubnetGroup
   121  	for _, s := range describeResp.DBSubnetGroups {
   122  		// AWS is down casing the name provided, so we compare lower case versions
   123  		// of the names. We lower case both our name and their name in the check,
   124  		// incase they change that someday.
   125  		if strings.ToLower(d.Id()) == strings.ToLower(*s.DBSubnetGroupName) {
   126  			subnetGroup = describeResp.DBSubnetGroups[0]
   127  		}
   128  	}
   129  
   130  	if subnetGroup.DBSubnetGroupName == nil {
   131  		return fmt.Errorf("Unable to find DB Subnet Group: %#v", describeResp.DBSubnetGroups)
   132  	}
   133  
   134  	d.Set("name", d.Id())
   135  	d.Set("description", *subnetGroup.DBSubnetGroupDescription)
   136  
   137  	subnets := make([]string, 0, len(subnetGroup.Subnets))
   138  	for _, s := range subnetGroup.Subnets {
   139  		subnets = append(subnets, *s.SubnetIdentifier)
   140  	}
   141  	d.Set("subnet_ids", subnets)
   142  
   143  	// list tags for resource
   144  	// set tags
   145  	conn := meta.(*AWSClient).rdsconn
   146  	arn, err := buildRDSsubgrpARN(d, meta)
   147  	if err != nil {
   148  		log.Printf("[DEBUG] Error building ARN for DB Subnet Group, not setting Tags for group %s", *subnetGroup.DBSubnetGroupName)
   149  	} else {
   150  		d.Set("arn", arn)
   151  		resp, err := conn.ListTagsForResource(&rds.ListTagsForResourceInput{
   152  			ResourceName: aws.String(arn),
   153  		})
   154  
   155  		if err != nil {
   156  			log.Printf("[DEBUG] Error retreiving tags for ARN: %s", arn)
   157  		}
   158  
   159  		var dt []*rds.Tag
   160  		if len(resp.TagList) > 0 {
   161  			dt = resp.TagList
   162  		}
   163  		d.Set("tags", tagsToMapRDS(dt))
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  func resourceAwsDbSubnetGroupUpdate(d *schema.ResourceData, meta interface{}) error {
   170  	conn := meta.(*AWSClient).rdsconn
   171  	if d.HasChange("subnet_ids") {
   172  		_, n := d.GetChange("subnet_ids")
   173  		if n == nil {
   174  			n = new(schema.Set)
   175  		}
   176  		ns := n.(*schema.Set)
   177  
   178  		var sIds []*string
   179  		for _, s := range ns.List() {
   180  			sIds = append(sIds, aws.String(s.(string)))
   181  		}
   182  
   183  		_, err := conn.ModifyDBSubnetGroup(&rds.ModifyDBSubnetGroupInput{
   184  			DBSubnetGroupName: aws.String(d.Id()),
   185  			SubnetIds:         sIds,
   186  		})
   187  
   188  		if err != nil {
   189  			return err
   190  		}
   191  	}
   192  
   193  	if arn, err := buildRDSsubgrpARN(d, meta); err == nil {
   194  		if err := setTagsRDS(conn, d, arn); err != nil {
   195  			return err
   196  		} else {
   197  			d.SetPartial("tags")
   198  		}
   199  	}
   200  
   201  	return resourceAwsDbSubnetGroupRead(d, meta)
   202  }
   203  
   204  func resourceAwsDbSubnetGroupDelete(d *schema.ResourceData, meta interface{}) error {
   205  	stateConf := &resource.StateChangeConf{
   206  		Pending:    []string{"pending"},
   207  		Target:     "destroyed",
   208  		Refresh:    resourceAwsDbSubnetGroupDeleteRefreshFunc(d, meta),
   209  		Timeout:    3 * time.Minute,
   210  		MinTimeout: 1 * time.Second,
   211  	}
   212  	_, err := stateConf.WaitForState()
   213  	return err
   214  }
   215  
   216  func resourceAwsDbSubnetGroupDeleteRefreshFunc(
   217  	d *schema.ResourceData,
   218  	meta interface{}) resource.StateRefreshFunc {
   219  	rdsconn := meta.(*AWSClient).rdsconn
   220  
   221  	return func() (interface{}, string, error) {
   222  
   223  		deleteOpts := rds.DeleteDBSubnetGroupInput{
   224  			DBSubnetGroupName: aws.String(d.Id()),
   225  		}
   226  
   227  		if _, err := rdsconn.DeleteDBSubnetGroup(&deleteOpts); err != nil {
   228  			rdserr, ok := err.(awserr.Error)
   229  			if !ok {
   230  				return d, "error", err
   231  			}
   232  
   233  			if rdserr.Code() != "DBSubnetGroupNotFoundFault" {
   234  				return d, "error", err
   235  			}
   236  		}
   237  
   238  		return d, "destroyed", nil
   239  	}
   240  }
   241  
   242  func buildRDSsubgrpARN(d *schema.ResourceData, meta interface{}) (string, error) {
   243  	iamconn := meta.(*AWSClient).iamconn
   244  	region := meta.(*AWSClient).region
   245  	// An zero value GetUserInput{} defers to the currently logged in user
   246  	resp, err := iamconn.GetUser(&iam.GetUserInput{})
   247  	if err != nil {
   248  		return "", err
   249  	}
   250  	userARN := *resp.User.Arn
   251  	accountID := strings.Split(userARN, ":")[4]
   252  	arn := fmt.Sprintf("arn:aws:rds:%s:%s:subgrp:%s", region, accountID, d.Id())
   253  	return arn, nil
   254  }