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