github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/builtin/providers/aws/resource_aws_db_security_group.go (about) 1 package aws 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "time" 8 9 "github.com/hashicorp/aws-sdk-go/aws" 10 "github.com/hashicorp/aws-sdk-go/gen/rds" 11 "github.com/hashicorp/terraform/helper/hashcode" 12 "github.com/hashicorp/terraform/helper/multierror" 13 "github.com/hashicorp/terraform/helper/resource" 14 "github.com/hashicorp/terraform/helper/schema" 15 ) 16 17 func resourceAwsDbSecurityGroup() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceAwsDbSecurityGroupCreate, 20 Read: resourceAwsDbSecurityGroupRead, 21 Delete: resourceAwsDbSecurityGroupDelete, 22 23 Schema: map[string]*schema.Schema{ 24 "name": &schema.Schema{ 25 Type: schema.TypeString, 26 Required: true, 27 ForceNew: true, 28 }, 29 30 "description": &schema.Schema{ 31 Type: schema.TypeString, 32 Required: true, 33 ForceNew: true, 34 }, 35 36 "ingress": &schema.Schema{ 37 Type: schema.TypeSet, 38 Required: true, 39 ForceNew: true, 40 Elem: &schema.Resource{ 41 Schema: map[string]*schema.Schema{ 42 "cidr": &schema.Schema{ 43 Type: schema.TypeString, 44 Optional: true, 45 }, 46 47 "security_group_name": &schema.Schema{ 48 Type: schema.TypeString, 49 Optional: true, 50 Computed: true, 51 }, 52 53 "security_group_id": &schema.Schema{ 54 Type: schema.TypeString, 55 Optional: true, 56 Computed: true, 57 }, 58 59 "security_group_owner_id": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 Computed: true, 63 }, 64 }, 65 }, 66 Set: resourceAwsDbSecurityGroupIngressHash, 67 }, 68 }, 69 } 70 } 71 72 func resourceAwsDbSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { 73 conn := meta.(*AWSClient).rdsconn 74 75 var err error 76 var errs []error 77 78 opts := rds.CreateDBSecurityGroupMessage{ 79 DBSecurityGroupName: aws.String(d.Get("name").(string)), 80 DBSecurityGroupDescription: aws.String(d.Get("description").(string)), 81 } 82 83 log.Printf("[DEBUG] DB Security Group create configuration: %#v", opts) 84 _, err = conn.CreateDBSecurityGroup(&opts) 85 if err != nil { 86 return fmt.Errorf("Error creating DB Security Group: %s", err) 87 } 88 89 d.SetId(d.Get("name").(string)) 90 91 log.Printf("[INFO] DB Security Group ID: %s", d.Id()) 92 93 sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 94 if err != nil { 95 return err 96 } 97 98 ingresses := d.Get("ingress").(*schema.Set) 99 for _, ing := range ingresses.List() { 100 err := resourceAwsDbSecurityGroupAuthorizeRule(ing, *sg.DBSecurityGroupName, conn) 101 if err != nil { 102 errs = append(errs, err) 103 } 104 } 105 106 if len(errs) > 0 { 107 return &multierror.Error{Errors: errs} 108 } 109 110 log.Println( 111 "[INFO] Waiting for Ingress Authorizations to be authorized") 112 113 stateConf := &resource.StateChangeConf{ 114 Pending: []string{"authorizing"}, 115 Target: "authorized", 116 Refresh: resourceAwsDbSecurityGroupStateRefreshFunc(d, meta), 117 Timeout: 10 * time.Minute, 118 } 119 120 // Wait, catching any errors 121 _, err = stateConf.WaitForState() 122 if err != nil { 123 return err 124 } 125 126 return resourceAwsDbSecurityGroupRead(d, meta) 127 } 128 129 func resourceAwsDbSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { 130 sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 131 if err != nil { 132 return err 133 } 134 135 d.Set("name", *sg.DBSecurityGroupName) 136 d.Set("description", *sg.DBSecurityGroupDescription) 137 138 // Create an empty schema.Set to hold all ingress rules 139 rules := &schema.Set{ 140 F: resourceAwsDbSecurityGroupIngressHash, 141 } 142 143 for _, v := range sg.IPRanges { 144 rule := map[string]interface{}{"cidr": *v.CIDRIP} 145 rules.Add(rule) 146 } 147 148 for _, g := range sg.EC2SecurityGroups { 149 rule := map[string]interface{}{ 150 "security_group_name": *g.EC2SecurityGroupName, 151 "security_group_id": *g.EC2SecurityGroupID, 152 "security_group_owner_id": *g.EC2SecurityGroupOwnerID, 153 } 154 rules.Add(rule) 155 } 156 157 d.Set("ingress", rules) 158 159 return nil 160 } 161 162 func resourceAwsDbSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { 163 conn := meta.(*AWSClient).rdsconn 164 165 log.Printf("[DEBUG] DB Security Group destroy: %v", d.Id()) 166 167 opts := rds.DeleteDBSecurityGroupMessage{DBSecurityGroupName: aws.String(d.Id())} 168 169 log.Printf("[DEBUG] DB Security Group destroy configuration: %v", opts) 170 err := conn.DeleteDBSecurityGroup(&opts) 171 172 if err != nil { 173 newerr, ok := err.(aws.APIError) 174 if ok && newerr.Code == "InvalidDBSecurityGroup.NotFound" { 175 return nil 176 } 177 return err 178 } 179 180 return nil 181 } 182 183 func resourceAwsDbSecurityGroupRetrieve(d *schema.ResourceData, meta interface{}) (*rds.DBSecurityGroup, error) { 184 conn := meta.(*AWSClient).rdsconn 185 186 opts := rds.DescribeDBSecurityGroupsMessage{ 187 DBSecurityGroupName: aws.String(d.Id()), 188 } 189 190 log.Printf("[DEBUG] DB Security Group describe configuration: %#v", opts) 191 192 resp, err := conn.DescribeDBSecurityGroups(&opts) 193 194 if err != nil { 195 return nil, fmt.Errorf("Error retrieving DB Security Groups: %s", err) 196 } 197 198 if len(resp.DBSecurityGroups) != 1 || 199 *resp.DBSecurityGroups[0].DBSecurityGroupName != d.Id() { 200 return nil, fmt.Errorf("Unable to find DB Security Group: %#v", resp.DBSecurityGroups) 201 } 202 203 v := resp.DBSecurityGroups[0] 204 205 return &v, nil 206 } 207 208 // Authorizes the ingress rule on the db security group 209 func resourceAwsDbSecurityGroupAuthorizeRule(ingress interface{}, dbSecurityGroupName string, conn *rds.RDS) error { 210 ing := ingress.(map[string]interface{}) 211 212 opts := rds.AuthorizeDBSecurityGroupIngressMessage{ 213 DBSecurityGroupName: aws.String(dbSecurityGroupName), 214 } 215 216 if attr, ok := ing["cidr"]; ok && attr != "" { 217 opts.CIDRIP = aws.String(attr.(string)) 218 } 219 220 if attr, ok := ing["security_group_name"]; ok && attr != "" { 221 opts.EC2SecurityGroupName = aws.String(attr.(string)) 222 } 223 224 if attr, ok := ing["security_group_id"]; ok && attr != "" { 225 opts.EC2SecurityGroupID = aws.String(attr.(string)) 226 } 227 228 if attr, ok := ing["security_group_owner_id"]; ok && attr != "" { 229 opts.EC2SecurityGroupOwnerID = aws.String(attr.(string)) 230 } 231 232 log.Printf("[DEBUG] Authorize ingress rule configuration: %#v", opts) 233 234 _, err := conn.AuthorizeDBSecurityGroupIngress(&opts) 235 236 if err != nil { 237 return fmt.Errorf("Error authorizing security group ingress: %s", err) 238 } 239 240 return nil 241 } 242 243 func resourceAwsDbSecurityGroupIngressHash(v interface{}) int { 244 var buf bytes.Buffer 245 m := v.(map[string]interface{}) 246 247 if v, ok := m["cidr"]; ok { 248 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 249 } 250 251 if v, ok := m["security_group_name"]; ok { 252 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 253 } 254 255 if v, ok := m["security_group_id"]; ok { 256 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 257 } 258 259 if v, ok := m["security_group_owner_id"]; ok { 260 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 261 } 262 263 return hashcode.String(buf.String()) 264 } 265 266 func resourceAwsDbSecurityGroupStateRefreshFunc( 267 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 268 return func() (interface{}, string, error) { 269 v, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 270 271 if err != nil { 272 log.Printf("Error on retrieving DB Security Group when waiting: %s", err) 273 return nil, "", err 274 } 275 276 statuses := make([]string, 0, len(v.EC2SecurityGroups)+len(v.IPRanges)) 277 for _, ec2g := range v.EC2SecurityGroups { 278 statuses = append(statuses, *ec2g.Status) 279 } 280 for _, ips := range v.IPRanges { 281 statuses = append(statuses, *ips.Status) 282 } 283 284 for _, stat := range statuses { 285 // Not done 286 if stat != "authorized" { 287 return nil, "authorizing", nil 288 } 289 } 290 291 return v, "authorized", nil 292 } 293 }