diff --git a/ibm/service/vpc/resource_ibm_is_network_acl_rule.go b/ibm/service/vpc/resource_ibm_is_network_acl_rule.go index a8377f313a..6e5c129020 100644 --- a/ibm/service/vpc/resource_ibm_is_network_acl_rule.go +++ b/ibm/service/vpc/resource_ibm_is_network_acl_rule.go @@ -607,13 +607,15 @@ func nwaclRuleUpdate(d *schema.ResourceData, meta interface{}, id, nwACLId strin updateNetworkACLOptionsPatchModel.Action = &action } } - + aclRuleBeforeNull := false if d.HasChange(isNwACLRuleBefore) { hasChanged = true - if beforeVar, ok := d.GetOk(isNwACLRuleBefore); ok { - beforeStr := beforeVar.(string) + beforeVar := d.Get(isNwACLRuleBefore).(string) + if beforeVar == "null" { + aclRuleBeforeNull = true + } else if beforeVar != "" { updateNetworkACLOptionsPatchModel.Before = &vpcv1.NetworkACLRuleBeforePatchNetworkACLRuleIdentityByID{ - ID: &beforeStr, + ID: &beforeVar, } } } @@ -744,6 +746,9 @@ func nwaclRuleUpdate(d *schema.ResourceData, meta interface{}, id, nwACLId strin if err != nil { return fmt.Errorf("[ERROR] Error calling asPatch for NetworkACLOptionsPatch : %s", err) } + if aclRuleBeforeNull { + updateNetworkACLOptionsPatch["before"] = nil + } updateNetworkACLRuleOptions.NetworkACLRulePatch = updateNetworkACLOptionsPatch _, response, err := sess.UpdateNetworkACLRule(updateNetworkACLRuleOptions) if err != nil { diff --git a/ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go b/ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go index 356cc37837..9c6fd6a00e 100644 --- a/ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go +++ b/ibm/service/vpc/resource_ibm_is_network_acl_rule_test.go @@ -163,6 +163,48 @@ func TestNetworkACLRule_basicUDP(t *testing.T) { }) } +func TestNetworkACLRule_basicBeforeRule(t *testing.T) { + var nwACLRule string + vpcName := fmt.Sprintf("tf-nacl-vpc-%d", acctest.RandIntRange(10, 100)) + ruleName := fmt.Sprintf("tf-outbound-udp-%d", acctest.RandIntRange(10, 100)) + ruleName1 := fmt.Sprintf("tf-outbound-udp1-%d", acctest.RandIntRange(10, 100)) + updatedRuleName := fmt.Sprintf("%s-update", ruleName) + updatedRule1Name := fmt.Sprintf("%s-update", ruleName1) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: checkNetworkACLRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMISNetworkACLRuleBeforeConfig(vpcName, ruleName, ruleName1), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISNetworkACLRuleExists("ibm_is_network_acl_rule.testacc_nacl", nwACLRule), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "name", ruleName), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "udp.0.source_port_max", "101"), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "udp.0.source_port_min", "1"), + ), + }, + { + Config: testAccCheckIBMISNetworkACLRuleBeforeUpdateConfig(vpcName, updatedRuleName, updatedRule1Name), + Check: resource.ComposeTestCheckFunc( + testAccCheckIBMISNetworkACLRuleExists("ibm_is_network_acl_rule.testacc_nacl", nwACLRule), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "name", updatedRuleName), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "udp.0.source_port_max", "101"), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "udp.0.source_port_min", "1"), + resource.TestCheckResourceAttr( + "ibm_is_network_acl_rule.testacc_nacl", "before", "null"), + ), + }, + }, + }) +} + func checkNetworkACLRuleDestroy(s *terraform.State) error { sess, _ := acc.TestAccProvider.Meta().(conns.ClientSession).VpcV1API() for _, rs := range s.RootModule().Resources { @@ -396,3 +438,76 @@ func testAccCheckIBMISNetworkACLRuleConfig4Update(vpcName, name string) string { } `, vpcName, name) } + +func testAccCheckIBMISNetworkACLRuleBeforeConfig(vpcName, name, name1 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_network_acl_rule" "testacc_nacl" { + network_acl = ibm_is_vpc.testacc_vpc.default_network_acl + name = "%s" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + before = ibm_is_network_acl_rule.testacc_nacl_1.rule_id + udp { + source_port_max = 101 + source_port_min = 1 + port_min = 202 + port_max = 220 + } + } + resource "ibm_is_network_acl_rule" "testacc_nacl_1" { + network_acl = ibm_is_vpc.testacc_vpc.default_network_acl + name = "%s" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + udp { + source_port_max = 101 + source_port_min = 1 + port_min = 202 + port_max = 220 + } + } + `, vpcName, name, name1) +} +func testAccCheckIBMISNetworkACLRuleBeforeUpdateConfig(vpcName, name, name1 string) string { + return fmt.Sprintf(` + resource "ibm_is_vpc" "testacc_vpc" { + name = "%s" + } + resource "ibm_is_network_acl_rule" "testacc_nacl" { + network_acl = ibm_is_vpc.testacc_vpc.default_network_acl + name = "%s" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + before = "null" + udp { + source_port_max = 101 + source_port_min = 1 + port_min = 202 + port_max = 220 + } + } + resource "ibm_is_network_acl_rule" "testacc_nacl_1" { + network_acl = ibm_is_vpc.testacc_vpc.default_network_acl + name = "%s" + action = "allow" + source = "0.0.0.0/0" + destination = "0.0.0.0/0" + direction = "outbound" + udp { + source_port_max = 101 + source_port_min = 1 + port_min = 202 + port_max = 220 + } + } + `, vpcName, name, name1) +} diff --git a/website/docs/r/is_network_acl_rule.html.markdown b/website/docs/r/is_network_acl_rule.html.markdown index d88e3b2d52..ad2bb14db6 100644 --- a/website/docs/r/is_network_acl_rule.html.markdown +++ b/website/docs/r/is_network_acl_rule.html.markdown @@ -118,7 +118,7 @@ resource "ibm_is_network_acl_rule" "example1" { Review the argument references that you can specify for your resource. - `action` - (Required, String) Whether to **allow** or **deny** matching traffic. -- `before` - (Optional, String) The unique identifier of the rule that this rule is immediately before. If **absent**, this is the last rule. If **omitted**, this rule will be inserted after all existing rules. +- `before` - (Optional, String) The unique identifier of the rule that this rule is immediately before. If unspecified, this rule will be inserted after all existing rules. While modifying the resource, specify **"null"** (within double quotes) to move this rule after all existing rules. - `destination` - (Required, String) The destination IP address or CIDR block. - `direction` - (Required, String) Whether the traffic to be matched is **inbound** or **outbound**. - `icmp` - (Optional, List) The protocol ICMP.