github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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 }