github.com/anuaimi/terraform@v0.6.4-0.20150904235404-2bf9aec61da8/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go (about) 1 package openstack 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 8 "github.com/hashicorp/terraform/helper/hashcode" 9 "github.com/hashicorp/terraform/helper/schema" 10 "github.com/rackspace/gophercloud" 11 "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" 12 ) 13 14 func resourceComputeSecGroupV2() *schema.Resource { 15 return &schema.Resource{ 16 Create: resourceComputeSecGroupV2Create, 17 Read: resourceComputeSecGroupV2Read, 18 Update: resourceComputeSecGroupV2Update, 19 Delete: resourceComputeSecGroupV2Delete, 20 21 Schema: map[string]*schema.Schema{ 22 "region": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 ForceNew: true, 26 DefaultFunc: envDefaultFuncAllowMissing("OS_REGION_NAME"), 27 }, 28 "name": &schema.Schema{ 29 Type: schema.TypeString, 30 Required: true, 31 ForceNew: false, 32 }, 33 "description": &schema.Schema{ 34 Type: schema.TypeString, 35 Required: true, 36 ForceNew: false, 37 }, 38 "rule": &schema.Schema{ 39 Type: schema.TypeList, 40 Optional: true, 41 Elem: &schema.Resource{ 42 Schema: map[string]*schema.Schema{ 43 "id": &schema.Schema{ 44 Type: schema.TypeString, 45 Computed: true, 46 }, 47 "from_port": &schema.Schema{ 48 Type: schema.TypeInt, 49 Required: true, 50 ForceNew: false, 51 }, 52 "to_port": &schema.Schema{ 53 Type: schema.TypeInt, 54 Required: true, 55 ForceNew: false, 56 }, 57 "ip_protocol": &schema.Schema{ 58 Type: schema.TypeString, 59 Required: true, 60 ForceNew: false, 61 }, 62 "cidr": &schema.Schema{ 63 Type: schema.TypeString, 64 Optional: true, 65 ForceNew: false, 66 }, 67 "from_group_id": &schema.Schema{ 68 Type: schema.TypeString, 69 Optional: true, 70 ForceNew: false, 71 }, 72 "self": &schema.Schema{ 73 Type: schema.TypeBool, 74 Optional: true, 75 Default: false, 76 ForceNew: false, 77 }, 78 }, 79 }, 80 }, 81 }, 82 } 83 } 84 85 func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) error { 86 config := meta.(*Config) 87 computeClient, err := config.computeV2Client(d.Get("region").(string)) 88 if err != nil { 89 return fmt.Errorf("Error creating OpenStack compute client: %s", err) 90 } 91 92 createOpts := secgroups.CreateOpts{ 93 Name: d.Get("name").(string), 94 Description: d.Get("description").(string), 95 } 96 97 log.Printf("[DEBUG] Create Options: %#v", createOpts) 98 sg, err := secgroups.Create(computeClient, createOpts).Extract() 99 if err != nil { 100 return fmt.Errorf("Error creating OpenStack security group: %s", err) 101 } 102 103 d.SetId(sg.ID) 104 105 createRuleOptsList := resourceSecGroupRulesV2(d) 106 for _, createRuleOpts := range createRuleOptsList { 107 _, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract() 108 if err != nil { 109 return fmt.Errorf("Error creating OpenStack security group rule: %s", err) 110 } 111 } 112 113 return resourceComputeSecGroupV2Read(d, meta) 114 } 115 116 func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) error { 117 config := meta.(*Config) 118 computeClient, err := config.computeV2Client(d.Get("region").(string)) 119 if err != nil { 120 return fmt.Errorf("Error creating OpenStack compute client: %s", err) 121 } 122 123 sg, err := secgroups.Get(computeClient, d.Id()).Extract() 124 if err != nil { 125 return CheckDeleted(d, err, "security group") 126 } 127 128 d.Set("name", sg.Name) 129 d.Set("description", sg.Description) 130 rtm := rulesToMap(sg.Rules) 131 for _, v := range rtm { 132 if v["group"] == d.Get("name") { 133 v["self"] = "1" 134 } else { 135 v["self"] = "0" 136 } 137 } 138 log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rtm) 139 d.Set("rule", rtm) 140 141 return nil 142 } 143 144 func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) error { 145 config := meta.(*Config) 146 computeClient, err := config.computeV2Client(d.Get("region").(string)) 147 if err != nil { 148 return fmt.Errorf("Error creating OpenStack compute client: %s", err) 149 } 150 151 updateOpts := secgroups.UpdateOpts{ 152 Name: d.Get("name").(string), 153 Description: d.Get("description").(string), 154 } 155 156 log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts) 157 158 _, err = secgroups.Update(computeClient, d.Id(), updateOpts).Extract() 159 if err != nil { 160 return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) 161 } 162 163 if d.HasChange("rule") { 164 oldSGRaw, newSGRaw := d.GetChange("rule") 165 oldSGRSlice, newSGRSlice := oldSGRaw.([]interface{}), newSGRaw.([]interface{}) 166 oldSGRSet := schema.NewSet(secgroupRuleV2Hash, oldSGRSlice) 167 newSGRSet := schema.NewSet(secgroupRuleV2Hash, newSGRSlice) 168 secgrouprulesToAdd := newSGRSet.Difference(oldSGRSet) 169 secgrouprulesToRemove := oldSGRSet.Difference(newSGRSet) 170 171 log.Printf("[DEBUG] Security group rules to add: %v", secgrouprulesToAdd) 172 173 log.Printf("[DEBUG] Security groups rules to remove: %v", secgrouprulesToRemove) 174 175 for _, rawRule := range secgrouprulesToAdd.List() { 176 createRuleOpts := resourceSecGroupRuleCreateOptsV2(d, rawRule) 177 rule, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract() 178 if err != nil { 179 return fmt.Errorf("Error adding rule to OpenStack security group (%s): %s", d.Id(), err) 180 } 181 log.Printf("[DEBUG] Added rule (%s) to OpenStack security group (%s) ", rule.ID, d.Id()) 182 } 183 184 for _, r := range secgrouprulesToRemove.List() { 185 rule := resourceSecGroupRuleV2(d, r) 186 err := secgroups.DeleteRule(computeClient, rule.ID).ExtractErr() 187 if err != nil { 188 errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) 189 if !ok { 190 return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) 191 } 192 if errCode.Actual == 404 { 193 continue 194 } else { 195 return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s)", rule.ID, d.Id()) 196 } 197 } else { 198 log.Printf("[DEBUG] Removed rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) 199 } 200 } 201 } 202 203 return resourceComputeSecGroupV2Read(d, meta) 204 } 205 206 func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) error { 207 config := meta.(*Config) 208 computeClient, err := config.computeV2Client(d.Get("region").(string)) 209 if err != nil { 210 return fmt.Errorf("Error creating OpenStack compute client: %s", err) 211 } 212 213 err = secgroups.Delete(computeClient, d.Id()).ExtractErr() 214 if err != nil { 215 return fmt.Errorf("Error deleting OpenStack security group: %s", err) 216 } 217 d.SetId("") 218 return nil 219 } 220 221 func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts { 222 rawRules := (d.Get("rule")).([]interface{}) 223 createRuleOptsList := make([]secgroups.CreateRuleOpts, len(rawRules)) 224 for i, raw := range rawRules { 225 rawMap := raw.(map[string]interface{}) 226 groupId := rawMap["from_group_id"].(string) 227 if rawMap["self"].(bool) { 228 groupId = d.Id() 229 } 230 createRuleOptsList[i] = secgroups.CreateRuleOpts{ 231 ParentGroupID: d.Id(), 232 FromPort: rawMap["from_port"].(int), 233 ToPort: rawMap["to_port"].(int), 234 IPProtocol: rawMap["ip_protocol"].(string), 235 CIDR: rawMap["cidr"].(string), 236 FromGroupID: groupId, 237 } 238 } 239 return createRuleOptsList 240 } 241 242 func resourceSecGroupRuleCreateOptsV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts { 243 rawMap := raw.(map[string]interface{}) 244 groupId := rawMap["from_group_id"].(string) 245 if rawMap["self"].(bool) { 246 groupId = d.Id() 247 } 248 return secgroups.CreateRuleOpts{ 249 ParentGroupID: d.Id(), 250 FromPort: rawMap["from_port"].(int), 251 ToPort: rawMap["to_port"].(int), 252 IPProtocol: rawMap["ip_protocol"].(string), 253 CIDR: rawMap["cidr"].(string), 254 FromGroupID: groupId, 255 } 256 } 257 258 func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.Rule { 259 rawMap := raw.(map[string]interface{}) 260 return secgroups.Rule{ 261 ID: rawMap["id"].(string), 262 ParentGroupID: d.Id(), 263 FromPort: rawMap["from_port"].(int), 264 ToPort: rawMap["to_port"].(int), 265 IPProtocol: rawMap["ip_protocol"].(string), 266 IPRange: secgroups.IPRange{CIDR: rawMap["cidr"].(string)}, 267 } 268 } 269 270 func rulesToMap(sgrs []secgroups.Rule) []map[string]interface{} { 271 sgrMap := make([]map[string]interface{}, len(sgrs)) 272 for i, sgr := range sgrs { 273 sgrMap[i] = map[string]interface{}{ 274 "id": sgr.ID, 275 "from_port": sgr.FromPort, 276 "to_port": sgr.ToPort, 277 "ip_protocol": sgr.IPProtocol, 278 "cidr": sgr.IPRange.CIDR, 279 "group": sgr.Group.Name, 280 } 281 } 282 return sgrMap 283 } 284 285 func secgroupRuleV2Hash(v interface{}) int { 286 var buf bytes.Buffer 287 m := v.(map[string]interface{}) 288 buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) 289 buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int))) 290 buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string))) 291 buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string))) 292 293 return hashcode.String(buf.String()) 294 }