github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/builtin/providers/aws/resource_aws_db_subnet_group.go (about)

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