diff --git a/docs/resources/network_acl.md b/docs/resources/network_acl.md index 5fc63be1..e445826e 100644 --- a/docs/resources/network_acl.md +++ b/docs/resources/network_acl.md @@ -45,6 +45,9 @@ resource "flexibleengine_network_acl" "fw_acl" { The following arguments are supported: +* `region` - (Optional, String, ForceNew) The region in which to create the network acl resource. If omitted, the + provider-level region will be used. Changing this creates a new network acl resource. + * `name` - (Required, String) Specifies the network ACL name. This parameter can contain a maximum of 64 characters, which may consist of letters, digits, underscores (_), and hyphens (-). diff --git a/docs/resources/network_acl_rule.md b/docs/resources/network_acl_rule.md index b3205db1..93e05a04 100644 --- a/docs/resources/network_acl_rule.md +++ b/docs/resources/network_acl_rule.md @@ -26,6 +26,9 @@ resource "flexibleengine_network_acl_rule" "rule_1" { The following arguments are supported: +* `region` - (Optional, String, ForceNew) The region in which to create the network ACL rule resource. If omitted, the + provider-level region will be used. Changing this creates a new network ACL rule resource. + * `name` - (Optional, String) Specifies a unique name for the network ACL rule. * `description` - (Optional, String) Specifies the description for the network ACL rule. diff --git a/flexibleengine/acceptance/resource_flexibleengine_network_acl_rule_test.go b/flexibleengine/acceptance/resource_flexibleengine_network_acl_rule_test.go new file mode 100644 index 00000000..6961ff41 --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_network_acl_rule_test.go @@ -0,0 +1,203 @@ +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + "github.com/chnsz/golangsdk/openstack/networking/v2/extensions/fwaas_v2/rules" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils/fmtp" +) + +func TestAccNetworkACLRule_basic(t *testing.T) { + resourceKey := "flexibleengine_network_acl_rule.rule_1" + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: testAccCheckNetworkACLRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkACLRule_basic_1(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLRuleExists(resourceKey), + resource.TestCheckResourceAttr(resourceKey, "name", rName), + resource.TestCheckResourceAttr(resourceKey, "protocol", "udp"), + resource.TestCheckResourceAttr(resourceKey, "action", "deny"), + resource.TestCheckResourceAttr(resourceKey, "enabled", "true"), + ), + }, + { + Config: testAccNetworkACLRule_basic_2(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLRuleExists(resourceKey), + resource.TestCheckResourceAttr(resourceKey, "name", rName), + resource.TestCheckResourceAttr(resourceKey, "protocol", "udp"), + resource.TestCheckResourceAttr(resourceKey, "action", "deny"), + resource.TestCheckResourceAttr(resourceKey, "enabled", "true"), + resource.TestCheckResourceAttr(resourceKey, "source_ip_address", "1.2.3.4"), + resource.TestCheckResourceAttr(resourceKey, "destination_ip_address", "4.3.2.0/24"), + resource.TestCheckResourceAttr(resourceKey, "source_port", "444"), + resource.TestCheckResourceAttr(resourceKey, "destination_port", "555"), + ), + }, + { + Config: testAccNetworkACLRule_basic_3(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLRuleExists(resourceKey), + resource.TestCheckResourceAttr(resourceKey, "name", rName), + resource.TestCheckResourceAttr(resourceKey, "protocol", "tcp"), + resource.TestCheckResourceAttr(resourceKey, "action", "allow"), + resource.TestCheckResourceAttr(resourceKey, "enabled", "false"), + resource.TestCheckResourceAttr(resourceKey, "source_ip_address", "1.2.3.0/24"), + resource.TestCheckResourceAttr(resourceKey, "destination_ip_address", "4.3.2.8"), + resource.TestCheckResourceAttr(resourceKey, "source_port", "666"), + resource.TestCheckResourceAttr(resourceKey, "destination_port", "777"), + ), + }, + { + ResourceName: resourceKey, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccNetworkACLRule_anyProtocol(t *testing.T) { + resourceKey := "flexibleengine_network_acl_rule.rule_any" + rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: testAccCheckNetworkACLRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkACLRule_anyProtocol(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLRuleExists(resourceKey), + resource.TestCheckResourceAttr(resourceKey, "name", rName), + resource.TestCheckResourceAttr(resourceKey, "protocol", "any"), + resource.TestCheckResourceAttr(resourceKey, "action", "allow"), + resource.TestCheckResourceAttr(resourceKey, "enabled", "true"), + resource.TestCheckResourceAttr(resourceKey, "source_ip_address", "192.168.199.0/24"), + ), + }, + }, + }) +} + +func testAccCheckNetworkACLRuleDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*config.Config) + fwClient, err := config.FwV2Client(OS_REGION_NAME) + if err != nil { + return fmtp.Errorf("Error creating FlexibleEngine fw client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "flexibleengine_network_acl_rule" { + continue + } + _, err = rules.Get(fwClient, rs.Primary.ID).Extract() + if err == nil { + return fmtp.Errorf("Network ACL rule (%s) still exists.", rs.Primary.ID) + } + if _, ok := err.(golangsdk.ErrDefault404); !ok { + return err + } + } + return nil +} + +func testAccCheckNetworkACLRuleExists(key string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[key] + if !ok { + return fmtp.Errorf("Not found: %s", key) + } + + if rs.Primary.ID == "" { + return fmtp.Errorf("No ID is set in %s", key) + } + + config := testAccProvider.Meta().(*config.Config) + fwClient, err := config.FwV2Client(OS_REGION_NAME) + if err != nil { + return fmtp.Errorf("Error creating FlexibleEngine fw client: %s", err) + } + + found, err := rules.Get(fwClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmtp.Errorf("Network ACL rule not found") + } + + return nil + } +} + +func testAccNetworkACLRule_basic_1(rName string) string { + return fmt.Sprintf(` +resource "flexibleengine_network_acl_rule" "rule_1" { + name = "%s" + protocol = "udp" + action = "deny" +} +`, rName) +} + +func testAccNetworkACLRule_basic_2(rName string) string { + return fmt.Sprintf(` +resource "flexibleengine_network_acl_rule" "rule_1" { + name = "%s" + description = "Terraform accept test" + protocol = "udp" + action = "deny" + source_ip_address = "1.2.3.4" + destination_ip_address = "4.3.2.0/24" + source_port = "444" + destination_port = "555" + enabled = true +} +`, rName) +} + +func testAccNetworkACLRule_basic_3(rName string) string { + return fmt.Sprintf(` +resource "flexibleengine_network_acl_rule" "rule_1" { + name = "%s" + description = "Terraform accept test updated" + protocol = "tcp" + action = "allow" + source_ip_address = "1.2.3.0/24" + destination_ip_address = "4.3.2.8" + source_port = "666" + destination_port = "777" + enabled = false +} +`, rName) +} + +func testAccNetworkACLRule_anyProtocol(rName string) string { + return fmt.Sprintf(` +resource "flexibleengine_network_acl_rule" "rule_any" { + name = "%s" + description = "Allow any protocol" + protocol = "any" + action = "allow" + source_ip_address = "192.168.199.0/24" + enabled = true +} +`, rName) +} diff --git a/flexibleengine/acceptance/resource_flexibleengine_network_acl_test.go b/flexibleengine/acceptance/resource_flexibleengine_network_acl_test.go new file mode 100644 index 00000000..4e57efbd --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_network_acl_test.go @@ -0,0 +1,264 @@ +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + "github.com/chnsz/golangsdk/openstack/networking/v2/extensions/fwaas_v2/firewall_groups" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils/fmtp" +) + +type FirewallGroup struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Status string `json:"status"` + IngressPolicyID string `json:"ingress_firewall_policy_id"` + EgressPolicyID string `json:"egress_firewall_policy_id"` + TenantID string `json:"tenant_id"` + PortIDs []string `json:"ports"` +} + +func TestAccNetworkACL_basic(t *testing.T) { + rName := fmt.Sprintf("acc-fw-%s", acctest.RandString(5)) + resourceKey := "flexibleengine_network_acl.fw_1" + var fwGroup FirewallGroup + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: testAccCheckNetworkACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkACL_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLExists(resourceKey, &fwGroup), + resource.TestCheckResourceAttr(resourceKey, "name", rName), + resource.TestCheckResourceAttr(resourceKey, "description", "created by terraform test acc"), + resource.TestCheckResourceAttr(resourceKey, "status", "ACTIVE"), + resource.TestCheckResourceAttrSet(resourceKey, "inbound_policy_id"), + testAccCheckFWFirewallPortCount(&fwGroup, 1), + ), + }, + { + Config: testAccNetworkACL_basic_update(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLExists("flexibleengine_network_acl.fw_1", &fwGroup), + resource.TestCheckResourceAttr(resourceKey, "name", rName+"_update"), + resource.TestCheckResourceAttr(resourceKey, "description", "updated by terraform test acc"), + resource.TestCheckResourceAttr(resourceKey, "status", "ACTIVE"), + testAccCheckFWFirewallPortCount(&fwGroup, 2), + ), + }, + }, + }) +} + +func TestAccNetworkACL_no_subnets(t *testing.T) { + rName := fmt.Sprintf("acc-fw-%s", acctest.RandString(5)) + resourceKey := "flexibleengine_network_acl.fw_1" + var fwGroup FirewallGroup + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: testAccCheckNetworkACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkACL_no_subnets(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLExists(resourceKey, &fwGroup), + resource.TestCheckResourceAttr(resourceKey, "name", rName), + resource.TestCheckResourceAttr(resourceKey, "description", "network acl without subents"), + resource.TestCheckResourceAttr(resourceKey, "status", "INACTIVE"), + testAccCheckFWFirewallPortCount(&fwGroup, 0), + ), + }, + }, + }) +} + +func TestAccNetworkACL_remove(t *testing.T) { + rName := fmt.Sprintf("acc-fw-%s", acctest.RandString(5)) + resourceKey := "flexibleengine_network_acl.fw_1" + var fwGroup FirewallGroup + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: testAccCheckNetworkACLDestroy, + Steps: []resource.TestStep{ + { + Config: testAccNetworkACL_basic_update(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLExists("flexibleengine_network_acl.fw_1", &fwGroup), + resource.TestCheckResourceAttr(resourceKey, "status", "ACTIVE"), + testAccCheckFWFirewallPortCount(&fwGroup, 2), + ), + }, + { + Config: testAccNetworkACL_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLExists("flexibleengine_network_acl.fw_1", &fwGroup), + resource.TestCheckResourceAttr(resourceKey, "status", "ACTIVE"), + testAccCheckFWFirewallPortCount(&fwGroup, 1), + ), + }, + { + Config: testAccNetworkACL_no_subnets(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkACLExists(resourceKey, &fwGroup), + resource.TestCheckResourceAttr(resourceKey, "status", "INACTIVE"), + testAccCheckFWFirewallPortCount(&fwGroup, 0), + ), + }, + }, + }) +} + +func testAccCheckNetworkACLDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*config.Config) + fwClient, err := config.FwV2Client(OS_REGION_NAME) + if err != nil { + return fmtp.Errorf("Error creating FlexibleEngine fw client: %s", err) + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "flexibleengine_network_acl" { + continue + } + + _, err = firewall_groups.Get(fwClient, rs.Primary.ID).Extract() + if err == nil { + return fmtp.Errorf("Firewall group (%s) still exists.", rs.Primary.ID) + } + if _, ok := err.(golangsdk.ErrDefault404); !ok { + return err + } + } + return nil +} + +func testAccCheckNetworkACLExists(n string, fwGroup *FirewallGroup) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmtp.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmtp.Errorf("No ID is set in %s", n) + } + + config := testAccProvider.Meta().(*config.Config) + fwClient, err := config.FwV2Client(OS_REGION_NAME) + if err != nil { + return fmtp.Errorf("Error creating FlexibleEngine fw client: %s", err) + } + + var found FirewallGroup + err = firewall_groups.Get(fwClient, rs.Primary.ID).ExtractInto(&found) + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmtp.Errorf("Firewall group not found") + } + + *fwGroup = found + + return nil + } +} + +func testAccCheckFWFirewallPortCount(firewall_group *FirewallGroup, expected int) resource.TestCheckFunc { + return func(s *terraform.State) error { + if len(firewall_group.PortIDs) != expected { + return fmtp.Errorf("Expected %d Ports, got %d", expected, len(firewall_group.PortIDs)) + } + + return nil + } +} + +func testAccNetworkACLRules(name string) string { + return fmt.Sprintf(` +resource "flexibleengine_vpc_v1" "vpc_1" { + name = "%s_vpc" + cidr = "192.168.0.0/16" +} + +resource "flexibleengine_vpc_subnet_v1" "subnet_1" { + name = "%s_subnet_1" + cidr = "192.168.0.0/24" + gateway_ip = "192.168.0.1" + vpc_id = flexibleengine_vpc_v1.vpc_1.id +} + +resource "flexibleengine_vpc_subnet_v1" "subnet_2" { + name = "%s_subnet_2" + cidr = "192.168.10.0/24" + gateway_ip = "192.168.10.1" + vpc_id = flexibleengine_vpc_v1.vpc_1.id + } + +resource "flexibleengine_network_acl_rule" "rule_1" { + name = "%s-rule-1" + description = "drop TELNET traffic" + action = "deny" + protocol = "tcp" + destination_port = "23" +} + +resource "flexibleengine_network_acl_rule" "rule_2" { + name = "%s-rule-2" + description = "drop NTP traffic" + action = "deny" + protocol = "udp" + destination_port = "123" +} +`, name, name, name, name, name) +} + +func testAccNetworkACL_basic(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_network_acl" "fw_1" { + name = "%s" + description = "created by terraform test acc" + inbound_rules = [flexibleengine_network_acl_rule.rule_1.id] + subnets = [flexibleengine_vpc_subnet_v1.subnet_1.id] +} +`, testAccNetworkACLRules(name), name) +} + +func testAccNetworkACL_basic_update(name string) string { + return fmt.Sprintf(` +%s + +resource "flexibleengine_network_acl" "fw_1" { + name = "%s_update" + description = "updated by terraform test acc" + inbound_rules = [flexibleengine_network_acl_rule.rule_1.id, flexibleengine_network_acl_rule.rule_2.id] + subnets = [flexibleengine_vpc_subnet_v1.subnet_1.id, flexibleengine_vpc_subnet_v1.subnet_2.id] +} +`, testAccNetworkACLRules(name), name) +} + +func testAccNetworkACL_no_subnets(name string) string { + return fmt.Sprintf(` +resource "flexibleengine_network_acl" "fw_1" { + name = "%s" + description = "network acl without subents" +} +`, name) +} diff --git a/flexibleengine/provider.go b/flexibleengine/provider.go index 5a861c87..3d89bb9f 100644 --- a/flexibleengine/provider.go +++ b/flexibleengine/provider.go @@ -445,8 +445,6 @@ func Provider() *schema.Provider { "flexibleengine_mrs_job_v2": resourceMRSJobV2(), "flexibleengine_mls_instance_v1": resourceMlsInstanceV1(), - "flexibleengine_network_acl": resourceNetworkACL(), - "flexibleengine_network_acl_rule": resourceNetworkACLRule(), "flexibleengine_networking_port_v2": resourceNetworkingPortV2(), "flexibleengine_networking_secgroup_v2": resourceNetworkingSecGroupV2(), "flexibleengine_networking_secgroup_rule_v2": resourceNetworkingSecGroupRuleV2(), @@ -638,6 +636,9 @@ func Provider() *schema.Provider { "flexibleengine_nat_private_snat_rule": nat.ResourcePrivateSnatRule(), "flexibleengine_nat_private_transit_ip": nat.ResourcePrivateTransitIp(), + "flexibleengine_network_acl": huaweicloud.ResourceNetworkACL(), + "flexibleengine_network_acl_rule": huaweicloud.ResourceNetworkACLRule(), + "flexibleengine_obs_bucket_acl": obs.ResourceOBSBucketAcl(), "flexibleengine_obs_bucket_object_acl": obs.ResourceOBSBucketObjectAcl(), "flexibleengine_obs_bucket_policy": obs.ResourceObsBucketPolicy(),