github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/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 if err != nil { 101 errs = append(errs, err) 102 } 103 } 104 105 if len(errs) > 0 { 106 return &multierror.Error{Errors: errs} 107 } 108 109 log.Println( 110 "[INFO] Waiting for Ingress Authorizations to be authorized") 111 112 stateConf := &resource.StateChangeConf{ 113 Pending: []string{"authorizing"}, 114 Target: "authorized", 115 Refresh: resourceAwsDbSecurityGroupStateRefreshFunc(d, meta), 116 Timeout: 10 * time.Minute, 117 } 118 119 // Wait, catching any errors 120 _, err = stateConf.WaitForState() 121 if err != nil { 122 return err 123 } 124 125 return resourceAwsDbSecurityGroupRead(d, meta) 126 } 127 128 func resourceAwsDbSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { 129 sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 130 if err != nil { 131 return err 132 } 133 134 d.Set("name", sg.Name) 135 d.Set("description", sg.Description) 136 137 // Create an empty schema.Set to hold all ingress rules 138 rules := &schema.Set{ 139 F: resourceAwsDbSecurityGroupIngressHash, 140 } 141 142 for _, v := range sg.CidrIps { 143 rule := map[string]interface{}{"cidr": v} 144 rules.Add(rule) 145 } 146 147 for i, _ := range sg.EC2SecurityGroupOwnerIds { 148 rule := map[string]interface{}{ 149 "security_group_name": sg.EC2SecurityGroupNames[i], 150 "security_group_id": sg.EC2SecurityGroupIds[i], 151 "security_group_owner_id": sg.EC2SecurityGroupOwnerIds[i], 152 } 153 rules.Add(rule) 154 } 155 156 d.Set("ingress", rules) 157 158 return nil 159 } 160 161 func resourceAwsDbSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { 162 conn := meta.(*AWSClient).rdsconn 163 164 log.Printf("[DEBUG] DB Security Group destroy: %v", d.Id()) 165 166 opts := rds.DeleteDBSecurityGroup{DBSecurityGroupName: d.Id()} 167 168 log.Printf("[DEBUG] DB Security Group destroy configuration: %v", opts) 169 _, err := conn.DeleteDBSecurityGroup(&opts) 170 171 if err != nil { 172 newerr, ok := err.(*rds.Error) 173 if ok && newerr.Code == "InvalidDBSecurityGroup.NotFound" { 174 return nil 175 } 176 return err 177 } 178 179 return nil 180 } 181 182 func resourceAwsDbSecurityGroupRetrieve(d *schema.ResourceData, meta interface{}) (*rds.DBSecurityGroup, error) { 183 conn := meta.(*AWSClient).rdsconn 184 185 opts := rds.DescribeDBSecurityGroups{ 186 DBSecurityGroupName: d.Id(), 187 } 188 189 log.Printf("[DEBUG] DB Security Group describe configuration: %#v", opts) 190 191 resp, err := conn.DescribeDBSecurityGroups(&opts) 192 193 if err != nil { 194 return nil, fmt.Errorf("Error retrieving DB Security Groups: %s", err) 195 } 196 197 if len(resp.DBSecurityGroups) != 1 || 198 resp.DBSecurityGroups[0].Name != d.Id() { 199 if err != nil { 200 return nil, fmt.Errorf("Unable to find DB Security Group: %#v", resp.DBSecurityGroups) 201 } 202 } 203 204 v := resp.DBSecurityGroups[0] 205 206 return &v, nil 207 } 208 209 // Authorizes the ingress rule on the db security group 210 func resourceAwsDbSecurityGroupAuthorizeRule(ingress interface{}, dbSecurityGroupName string, conn *rds.Rds) error { 211 ing := ingress.(map[string]interface{}) 212 213 opts := rds.AuthorizeDBSecurityGroupIngress{ 214 DBSecurityGroupName: dbSecurityGroupName, 215 } 216 217 if attr, ok := ing["cidr"]; ok && attr != "" { 218 opts.Cidr = attr.(string) 219 } 220 221 if attr, ok := ing["security_group_name"]; ok && attr != "" { 222 opts.EC2SecurityGroupName = attr.(string) 223 } 224 225 if attr, ok := ing["security_group_id"]; ok && attr != "" { 226 opts.EC2SecurityGroupId = attr.(string) 227 } 228 229 if attr, ok := ing["security_group_owner_id"]; ok && attr != "" { 230 opts.EC2SecurityGroupOwnerId = attr.(string) 231 } 232 233 log.Printf("[DEBUG] Authorize ingress rule configuration: %#v", opts) 234 235 _, err := conn.AuthorizeDBSecurityGroupIngress(&opts) 236 237 if err != nil { 238 return fmt.Errorf("Error authorizing security group ingress: %s", err) 239 } 240 241 return nil 242 } 243 244 func resourceAwsDbSecurityGroupIngressHash(v interface{}) int { 245 var buf bytes.Buffer 246 m := v.(map[string]interface{}) 247 248 if v, ok := m["cidr"]; ok { 249 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 250 } 251 252 if v, ok := m["security_group_name"]; ok { 253 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 254 } 255 256 if v, ok := m["security_group_id"]; ok { 257 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 258 } 259 260 if v, ok := m["security_group_owner_id"]; ok { 261 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 262 } 263 264 return hashcode.String(buf.String()) 265 } 266 267 func resourceAwsDbSecurityGroupStateRefreshFunc( 268 d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc { 269 return func() (interface{}, string, error) { 270 v, err := resourceAwsDbSecurityGroupRetrieve(d, meta) 271 272 if err != nil { 273 log.Printf("Error on retrieving DB Security Group when waiting: %s", err) 274 return nil, "", err 275 } 276 277 statuses := append(v.EC2SecurityGroupStatuses, v.CidrStatuses...) 278 279 for _, stat := range statuses { 280 // Not done 281 if stat != "authorized" { 282 return nil, "authorizing", nil 283 } 284 } 285 286 return v, "authorized", nil 287 } 288 }