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