diff --git a/cloudstack/resource_cloudstack_security_group_rule.go b/cloudstack/resource_cloudstack_security_group_rule.go index a1b21dd6..074d6e75 100644 --- a/cloudstack/resource_cloudstack_security_group_rule.go +++ b/cloudstack/resource_cloudstack_security_group_rule.go @@ -247,6 +247,16 @@ func createSecurityGroupRule(d *schema.ResourceData, meta interface{}, rule map[ // Set the protocol p.SetProtocol(rule["protocol"].(string)) + if rule["protocol"].(string) == "all" { + ruleID, err := createIngressOrEgressRule(cs, p) + if err != nil { + return err + } + + uuids[uuid+"all"] = ruleID + rule["uuids"] = uuids + } + // If the protocol is ICMP set the needed ICMP parameters if rule["protocol"].(string) == "icmp" { p.SetIcmptype(rule["icmp_type"].(int)) @@ -393,6 +403,33 @@ func readSecurityGroupRule(sg *cloudstack.SecurityGroup, ruleIndex map[string]in uuids := rule["uuids"].(map[string]interface{}) sgRules := append(sg.Ingressrule, sg.Egressrule...) + if rule["protocol"].(string) == "all" { + id, ok := uuids[uuid+"all"] + if !ok { + return + } + + // Get the rule + idx, ok := ruleIndex[id.(string)] + if !ok { + delete(uuids, uuid+"all") + return + } + + r := sgRules[idx] + + // Update the values + if r.Cidr != "" { + rule["cidr_list"].(*schema.Set).Add(r.Cidr) + } + + if r.Securitygroupname != "" { + rule["user_security_group_list"].(*schema.Set).Add(r.Securitygroupname) + } + + rule["protocol"] = r.Protocol + } + if rule["protocol"].(string) == "icmp" { id, ok := uuids[uuid+"icmp"] if !ok { @@ -610,6 +647,8 @@ func verifySecurityGroupRuleParams(d *schema.ResourceData, rule map[string]inter protocol := rule["protocol"].(string) switch protocol { + case "all": + break case "icmp": if _, ok := rule["icmp_type"]; !ok { return fmt.Errorf( @@ -636,7 +675,7 @@ func verifySecurityGroupRuleParams(d *schema.ResourceData, rule map[string]inter _, err := strconv.ParseInt(protocol, 0, 0) if err != nil { return fmt.Errorf( - "%q is not a valid protocol. Valid options are 'tcp', 'udp' and 'icmp'", protocol) + "%q is not a valid protocol. Valid options are 'tcp', 'udp', 'icmp', 'all' or a protocol number", protocol) } } diff --git a/cloudstack/resource_cloudstack_security_group_rule_test.go b/cloudstack/resource_cloudstack_security_group_rule_test.go index 804a4a80..9d44b55d 100644 --- a/cloudstack/resource_cloudstack_security_group_rule_test.go +++ b/cloudstack/resource_cloudstack_security_group_rule_test.go @@ -40,27 +40,29 @@ func TestAccCloudStackSecurityGroupRule_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackSecurityGroupRulesExist("cloudstack_security_group.foo"), resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.#", "2"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.cidr_list.0", "172.18.100.0/24"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.protocol", "tcp"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.ports.#", "1"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.ports.0", "80"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.traffic_type", "ingress"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.protocol", "tcp"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.ports.1", "80"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.ports.0", "443"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.traffic_type", "egress"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.user_security_group_list.0", "terraform-security-group-bar"), + "cloudstack_security_group_rule.foo", "rule.#", "3"), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "all", + "traffic_type": "egress", + "cidr_list.#": "1", + "cidr_list.0": "172.0.0.0/8", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "tcp", + "traffic_type": "ingress", + "cidr_list.0": "172.18.100.0/24", + "ports.#": "1", + "ports.0": "80", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "tcp", + "traffic_type": "egress", + "ports.#": "2", + "user_security_group_list.0": "terraform-security-group-bar", + }), ), }, }, @@ -78,27 +80,29 @@ func TestAccCloudStackSecurityGroupRule_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackSecurityGroupRulesExist("cloudstack_security_group.foo"), resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.#", "2"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.cidr_list.0", "172.18.100.0/24"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.protocol", "tcp"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.ports.#", "1"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.ports.0", "80"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.traffic_type", "ingress"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.protocol", "tcp"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.ports.1", "80"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.ports.0", "443"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.traffic_type", "egress"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.user_security_group_list.0", "terraform-security-group-bar"), + "cloudstack_security_group_rule.foo", "rule.#", "3"), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "all", + "traffic_type": "egress", + "cidr_list.#": "1", + "cidr_list.0": "172.0.0.0/8", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "tcp", + "traffic_type": "ingress", + "cidr_list.0": "172.18.100.0/24", + "ports.#": "1", + "ports.0": "80", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "tcp", + "traffic_type": "egress", + "ports.#": "2", + "user_security_group_list.0": "terraform-security-group-bar", + }), ), }, @@ -107,35 +111,36 @@ func TestAccCloudStackSecurityGroupRule_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackSecurityGroupRulesExist("cloudstack_security_group.foo"), resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.#", "3"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.cidr_list.0", "172.18.100.0/24"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.cidr_list.1", "172.18.200.0/24"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.protocol", "tcp"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.ports.1", "80"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.0.ports.0", "443"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.cidr_list.#", "1"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.cidr_list.0", "172.18.100.0/24"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.icmp_code", "-1"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.1.icmp_type", "-1"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.2.protocol", "tcp"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.2.ports.#", "1"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.2.ports.0", "80"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.2.traffic_type", "egress"), - resource.TestCheckResourceAttr( - "cloudstack_security_group_rule.foo", "rule.2.user_security_group_list.0", "terraform-security-group-bar"), + "cloudstack_security_group_rule.foo", "rule.#", "4"), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "tcp", + "cidr_list.#": "2", + "ports.#": "2", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "icmp", + "traffic_type": "ingress", + "cidr_list.#": "1", + "cidr_list.0": "172.18.100.0/24", + "icmp_code": "-1", + "icmp_type": "-1", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "all", + "traffic_type": "ingress", + "cidr_list.#": "2", + }), + resource.TestCheckTypeSetElemNestedAttrs( + "cloudstack_security_group_rule.foo", "rule.*", map[string]string{ + "protocol": "tcp", + "traffic_type": "egress", + "ports.#": "1", + "ports.0": "80", + "user_security_group_list.0": "terraform-security-group-bar", + }), ), }, }, @@ -238,6 +243,12 @@ resource "cloudstack_security_group" "bar" { resource "cloudstack_security_group_rule" "foo" { security_group_id = cloudstack_security_group.foo.id + rule { + protocol = "all" + cidr_list = ["172.0.0.0/8"] + traffic_type = "egress" + } + rule { cidr_list = ["172.18.100.0/24"] protocol = "tcp" @@ -268,6 +279,12 @@ resource "cloudstack_security_group" "bar" { resource "cloudstack_security_group_rule" "foo" { security_group_id = cloudstack_security_group.foo.id + rule { + protocol = "all" + cidr_list = ["172.20.100.0/24", "192.168.0.0/32"] + traffic_type = "ingress" + } + rule { cidr_list = ["172.18.100.0/24", "172.18.200.0/24"] protocol = "tcp"