package openstack import ( "bytes" "fmt" "log" "strings" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) func computeSecGroupV2RulesCheckForErrors(d *schema.ResourceData) error { rawRules := d.Get("rule").(*schema.Set).List() for _, rawRule := range rawRules { rawRuleMap := rawRule.(map[string]interface{}) // only one of cidr, from_group_id, or self can be set cidr := rawRuleMap["cidr"].(string) groupId := rawRuleMap["from_group_id"].(string) self := rawRuleMap["self"].(bool) errorMessage := fmt.Errorf("Only one of cidr, from_group_id, or self can be set.") // if cidr is set, from_group_id and self cannot be set if cidr != "" { if groupId != "" || self { return errorMessage } } // if from_group_id is set, cidr and self cannot be set if groupId != "" { if cidr != "" || self { return errorMessage } } // if self is set, cidr and from_group_id cannot be set if self { if cidr != "" || groupId != "" { return errorMessage } } } return nil } func expandComputeSecGroupV2CreateRules(d *schema.ResourceData) []secgroups.CreateRuleOpts { rawRules := d.Get("rule").(*schema.Set).List() createRuleOptsList := make([]secgroups.CreateRuleOpts, len(rawRules)) for i, rawRule := range rawRules { createRuleOptsList[i] = expandComputeSecGroupV2CreateRule(d, rawRule) } return createRuleOptsList } func expandComputeSecGroupV2CreateRule(d *schema.ResourceData, rawRule interface{}) secgroups.CreateRuleOpts { rawRuleMap := rawRule.(map[string]interface{}) groupId := rawRuleMap["from_group_id"].(string) if rawRuleMap["self"].(bool) { groupId = d.Id() } return secgroups.CreateRuleOpts{ ParentGroupID: d.Id(), FromPort: rawRuleMap["from_port"].(int), ToPort: rawRuleMap["to_port"].(int), IPProtocol: rawRuleMap["ip_protocol"].(string), CIDR: rawRuleMap["cidr"].(string), FromGroupID: groupId, } } func expandComputeSecGroupV2Rule(d *schema.ResourceData, rawRule interface{}) secgroups.Rule { rawRuleMap := rawRule.(map[string]interface{}) return secgroups.Rule{ ID: rawRuleMap["id"].(string), ParentGroupID: d.Id(), FromPort: rawRuleMap["from_port"].(int), ToPort: rawRuleMap["to_port"].(int), IPProtocol: rawRuleMap["ip_protocol"].(string), IPRange: secgroups.IPRange{CIDR: rawRuleMap["cidr"].(string)}, } } func flattenComputeSecGroupV2Rules(computeClient *gophercloud.ServiceClient, d *schema.ResourceData, sgrs []secgroups.Rule) ([]map[string]interface{}, error) { sgrMap := make([]map[string]interface{}, len(sgrs)) for i, sgr := range sgrs { groupId := "" self := false if sgr.Group.Name != "" { if sgr.Group.Name == d.Get("name").(string) { self = true } else { // Since Nova only returns the secgroup Name (and not the ID) for the group attribute, // we need to look up all security groups and match the name. // Nevermind that Nova wants the ID when setting the Group *and* that multiple groups // with the same name can exist... allPages, err := secgroups.List(computeClient).AllPages() if err != nil { return nil, err } securityGroups, err := secgroups.ExtractSecurityGroups(allPages) if err != nil { return nil, err } for _, sg := range securityGroups { if sg.Name == sgr.Group.Name { groupId = sg.ID } } } } sgrMap[i] = map[string]interface{}{ "id": sgr.ID, "from_port": sgr.FromPort, "to_port": sgr.ToPort, "ip_protocol": sgr.IPProtocol, "cidr": sgr.IPRange.CIDR, "self": self, "from_group_id": groupId, } } return sgrMap, nil } func computeSecGroupV2RuleHash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int))) buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string))) buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["cidr"].(string)))) buf.WriteString(fmt.Sprintf("%s-", m["from_group_id"].(string))) buf.WriteString(fmt.Sprintf("%t-", m["self"].(bool))) return hashcode.String(buf.String()) } func computeSecGroupV2StateRefreshFunc(computeClient *gophercloud.ServiceClient, d *schema.ResourceData) resource.StateRefreshFunc { return func() (interface{}, string, error) { log.Printf("[DEBUG] Attempting to delete openstack_compute_secgroup_v2 %s", d.Id()) err := secgroups.Delete(computeClient, d.Id()).ExtractErr() if err != nil { return nil, "", err } s, err := secgroups.Get(computeClient, d.Id()).Extract() if err != nil { err = CheckDeleted(d, err, "Error retrieving openstack_compute_secgroup_v2") if err != nil { return s, "", err } log.Printf("[DEBUG] Successfully deleted openstack_compute_secgroup_v2 %s", d.Id()) return s, "DELETED", nil } log.Printf("[DEBUG] openstack_compute_secgroup_v2 %s still active", d.Id()) return s, "ACTIVE", nil } }