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