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