github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/builtin/providers/aws/resource_aws_security_group.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/flatmap" 9 "github.com/hashicorp/terraform/helper/config" 10 "github.com/hashicorp/terraform/helper/diff" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 "github.com/mitchellh/goamz/ec2" 14 ) 15 16 func resource_aws_security_group_create( 17 s *terraform.ResourceState, 18 d *terraform.ResourceDiff, 19 meta interface{}) (*terraform.ResourceState, error) { 20 p := meta.(*ResourceProvider) 21 ec2conn := p.ec2conn 22 23 // Merge the diff into the state so that we have all the attributes 24 // properly. 25 rs := s.MergeDiff(d) 26 27 securityGroupOpts := ec2.SecurityGroup{ 28 Name: rs.Attributes["name"], 29 } 30 31 if rs.Attributes["vpc_id"] != "" { 32 securityGroupOpts.VpcId = rs.Attributes["vpc_id"] 33 } 34 35 if rs.Attributes["description"] != "" { 36 securityGroupOpts.Description = rs.Attributes["description"] 37 } 38 39 log.Printf("[DEBUG] Security Group create configuration: %#v", securityGroupOpts) 40 createResp, err := ec2conn.CreateSecurityGroup(securityGroupOpts) 41 if err != nil { 42 return nil, fmt.Errorf("Error creating Security Group: %s", err) 43 } 44 45 rs.ID = createResp.Id 46 group := createResp.SecurityGroup 47 48 log.Printf("[INFO] Security Group ID: %s", rs.ID) 49 50 // Wait for the security group to truly exist 51 log.Printf( 52 "[DEBUG] Waiting for SG (%s) to exist", 53 s.ID) 54 stateConf := &resource.StateChangeConf{ 55 Pending: []string{""}, 56 Target: "exists", 57 Refresh: SGStateRefreshFunc(ec2conn, rs.ID), 58 Timeout: 1 * time.Minute, 59 } 60 if _, err := stateConf.WaitForState(); err != nil { 61 return s, fmt.Errorf( 62 "Error waiting for SG (%s) to become available: %s", 63 rs.ID, err) 64 } 65 66 // Expand the "ingress" array to goamz compat []ec2.IPPerm 67 ingressRules := []ec2.IPPerm{} 68 v, ok := flatmap.Expand(rs.Attributes, "ingress").([]interface{}) 69 if ok { 70 ingressRules, err = expandIPPerms(v) 71 if err != nil { 72 return rs, err 73 } 74 } 75 76 if len(ingressRules) > 0 { 77 _, err = ec2conn.AuthorizeSecurityGroup(group, ingressRules) 78 if err != nil { 79 return rs, fmt.Errorf("Error authorizing security group ingress rules: %s", err) 80 } 81 } 82 83 return resource_aws_security_group_refresh(rs, meta) 84 } 85 86 func resource_aws_security_group_destroy( 87 s *terraform.ResourceState, 88 meta interface{}) error { 89 p := meta.(*ResourceProvider) 90 ec2conn := p.ec2conn 91 92 log.Printf("[DEBUG] Security Group destroy: %v", s.ID) 93 94 _, err := ec2conn.DeleteSecurityGroup(ec2.SecurityGroup{Id: s.ID}) 95 if err != nil { 96 ec2err, ok := err.(*ec2.Error) 97 if ok && ec2err.Code == "InvalidGroup.NotFound" { 98 return nil 99 } 100 } 101 102 return err 103 } 104 105 func resource_aws_security_group_refresh( 106 s *terraform.ResourceState, 107 meta interface{}) (*terraform.ResourceState, error) { 108 p := meta.(*ResourceProvider) 109 ec2conn := p.ec2conn 110 111 sgRaw, _, err := SGStateRefreshFunc(ec2conn, s.ID)() 112 if err != nil { 113 return s, err 114 } 115 if sgRaw == nil { 116 return nil, nil 117 } 118 119 return resource_aws_security_group_update_state( 120 s, sgRaw.(*ec2.SecurityGroupInfo)) 121 } 122 123 func resource_aws_security_group_diff( 124 s *terraform.ResourceState, 125 c *terraform.ResourceConfig, 126 meta interface{}) (*terraform.ResourceDiff, error) { 127 128 b := &diff.ResourceBuilder{ 129 Attrs: map[string]diff.AttrType{ 130 "name": diff.AttrTypeCreate, 131 "description": diff.AttrTypeUpdate, 132 "ingress": diff.AttrTypeUpdate, 133 "vpc_id": diff.AttrTypeCreate, 134 }, 135 136 ComputedAttrs: []string{ 137 "owner_id", 138 "vpc_id", 139 }, 140 } 141 142 return b.Diff(s, c) 143 } 144 145 func resource_aws_security_group_update_state( 146 s *terraform.ResourceState, 147 sg *ec2.SecurityGroupInfo) (*terraform.ResourceState, error) { 148 149 s.Attributes["description"] = sg.Description 150 s.Attributes["name"] = sg.Name 151 s.Attributes["vpc_id"] = sg.VpcId 152 s.Attributes["owner_id"] = sg.OwnerId 153 154 // Flatten our ingress values 155 toFlatten := make(map[string]interface{}) 156 toFlatten["ingress"] = flattenIPPerms(sg.IPPerms) 157 158 for k, v := range flatmap.Flatten(toFlatten) { 159 s.Attributes[k] = v 160 } 161 162 s.Dependencies = nil 163 if s.Attributes["vpc_id"] != "" { 164 s.Dependencies = append(s.Dependencies, 165 terraform.ResourceDependency{ID: s.Attributes["vpc_id"]}, 166 ) 167 } 168 169 return s, nil 170 } 171 172 func resource_aws_security_group_validation() *config.Validator { 173 return &config.Validator{ 174 Required: []string{ 175 "name", 176 "ingress.*", 177 "ingress.*.from_port", 178 "ingress.*.to_port", 179 "ingress.*.protocol", 180 }, 181 Optional: []string{ 182 "description", 183 "vpc_id", 184 "owner_id", 185 "ingress.*.cidr_blocks.*", 186 "ingress.*.security_groups.*", 187 }, 188 } 189 } 190 191 // SGStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch 192 // a security group. 193 func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { 194 return func() (interface{}, string, error) { 195 sgs := []ec2.SecurityGroup{ec2.SecurityGroup{Id: id}} 196 resp, err := conn.SecurityGroups(sgs, nil) 197 if err != nil { 198 if ec2err, ok := err.(*ec2.Error); ok { 199 if ec2err.Code == "InvalidSecurityGroupID.NotFound" || 200 ec2err.Code == "InvalidGroup.NotFound" { 201 resp = nil 202 err = nil 203 } 204 } 205 206 if err != nil { 207 log.Printf("Error on SGStateRefresh: %s", err) 208 return nil, "", err 209 } 210 } 211 212 if resp == nil { 213 return nil, "", nil 214 } 215 216 group := &resp.Groups[0] 217 return group, "exists", nil 218 } 219 }