github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/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/terraform/helper/hashcode" 10 "github.com/hashicorp/terraform/helper/multierror" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/helper/schema" 13 "github.com/mitchellh/goamz/rds" 14 ) 15 16 func resourceAwsDbSecurityGroup() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceAwsDbSecurityGroupCreate, 19 Read: resourceAwsDbSecurityGroupRead, 20 Delete: resourceAwsDbSecurityGroupDelete, 21 22 Schema: map[string]*schema.Schema{ 23 "name": &schema.Schema{ 24 Type: schema.TypeString, 25 Required: true, 26 ForceNew: true, 27 }, 28 29 "description": &schema.Schema{ 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 }, 34 35 "ingress": &schema.Schema{ 36 Type: schema.TypeSet, 37 Required: true, 38 ForceNew: true, 39 Elem: &schema.Resource{ 40 Schema: map[string]*schema.Schema{ 41 "cidr": &schema.Schema{ 42 Type: schema.TypeString, 43 Optional: true, 44 }, 45 46 "security_group_name": &schema.Schema{ 47 Type: schema.TypeString, 48 Optional: true, 49 Computed: true, 50 }, 51 52 "security_group_id": &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 Computed: true, 56 }, 57 58 "security_group_owner_id": &schema.Schema{ 59 Type: schema.TypeString, 60 Optional: true, 61 Computed: true, 62 }, 63 }, 64 }, 65 Set: resourceAwsDbSecurityGroupIngressHash, 66 }, 67 }, 68 } 69 } 70 71 func resourceAwsDbSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { 72 conn := meta.(*AWSClient).rdsconn 73 74 var err error 75 var errs []error 76 77 opts := rds.CreateDBSecurityGroup{ 78 DBSecurityGroupName: d.Get("name").(string), 79 DBSecurityGroupDescription: d.Get("description").(string), 80 } 81 82 log.Printf("[DEBUG] DB Security Group create configuration: %#v", opts) 83 _, err = conn.CreateDBSecurityGroup(&opts) 84 if err != nil { 85 return fmt.Errorf("Error creating DB Security Group: %s", err) 86 } 87 88 d.SetId(d.Get("name").(string)) 89 90 log.Printf("[INFO] DB Security Group ID: %s", d.Id()) 91 92 sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 93 if err != nil { 94 return err 95 } 96 97 ingresses := d.Get("ingress").(*schema.Set) 98 for _, ing := range ingresses.List() { 99 err = resourceAwsDbSecurityGroupAuthorizeRule(ing, sg.Name, conn) 100 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.Name) 136 d.Set("description", sg.Description) 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.CidrIps { 144 rule := map[string]interface{}{"cidr": v} 145 rules.Add(rule) 146 } 147 148 for i, _ := range sg.EC2SecurityGroupOwnerIds { 149 rule := map[string]interface{}{ 150 "security_group_name": sg.EC2SecurityGroupNames[i], 151 "security_group_id": sg.EC2SecurityGroupIds[i], 152 "security_group_owner_id": sg.EC2SecurityGroupOwnerIds[i], 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.DeleteDBSecurityGroup{DBSecurityGroupName: 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.(*rds.Error) 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.DescribeDBSecurityGroups{ 187 DBSecurityGroupName: 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].Name != d.Id() { 200 if err != nil { 201 return nil, fmt.Errorf("Unable to find DB Security Group: %#v", resp.DBSecurityGroups) 202 } 203 } 204 205 v := resp.DBSecurityGroups[0] 206 207 return &v, nil 208 } 209 210 // Authorizes the ingress rule on the db security group 211 func resourceAwsDbSecurityGroupAuthorizeRule(ingress interface{}, dbSecurityGroupName string, conn *rds.Rds) error { 212 ing := ingress.(map[string]interface{}) 213 214 opts := rds.AuthorizeDBSecurityGroupIngress{ 215 DBSecurityGroupName: dbSecurityGroupName, 216 } 217 218 if attr, ok := ing["cidr"]; ok && attr != "" { 219 opts.Cidr = attr.(string) 220 } 221 222 if attr, ok := ing["security_group_name"]; ok && attr != "" { 223 opts.EC2SecurityGroupName = attr.(string) 224 } 225 226 if attr, ok := ing["security_group_id"]; ok && attr != "" { 227 opts.EC2SecurityGroupId = attr.(string) 228 } 229 230 if attr, ok := ing["security_group_owner_id"]; ok && attr != "" { 231 opts.EC2SecurityGroupOwnerId = attr.(string) 232 } 233 234 log.Printf("[DEBUG] Authorize ingress rule configuration: %#v", opts) 235 236 _, err := conn.AuthorizeDBSecurityGroupIngress(&opts) 237 238 if err != nil { 239 return fmt.Errorf("Error authorizing security group ingress: %s", err) 240 } 241 242 return nil 243 } 244 245 func resourceAwsDbSecurityGroupIngressHash(v interface{}) int { 246 var buf bytes.Buffer 247 m := v.(map[string]interface{}) 248 249 if v, ok := m["cidr"]; ok { 250 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 251 } 252 253 if v, ok := m["security_group_name"]; ok { 254 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 255 } 256 257 if v, ok := m["security_group_id"]; ok { 258 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 259 } 260 261 if v, ok := m["security_group_owner_id"]; ok { 262 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 263 } 264 265 return hashcode.String(buf.String()) 266 } 267 268 func resourceAwsDbSecurityGroupStateRefreshFunc( 269 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 270 return func() (interface{}, string, error) { 271 v, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 272 273 if err != nil { 274 log.Printf("Error on retrieving DB Security Group when waiting: %s", err) 275 return nil, "", err 276 } 277 278 statuses := append(v.EC2SecurityGroupStatuses, v.CidrStatuses...) 279 280 for _, stat := range statuses { 281 // Not done 282 if stat != "authorized" { 283 return nil, "authorizing", nil 284 } 285 } 286 287 return v, "authorized", nil 288 } 289 }