diff --git a/docs/resources/nat_snat_rule_v2.md b/docs/resources/nat_snat_rule_v2.md index cfbbd19c..f832a37c 100644 --- a/docs/resources/nat_snat_rule_v2.md +++ b/docs/resources/nat_snat_rule_v2.md @@ -1,30 +1,35 @@ --- subcategory: "NAT Gateway (NAT)" -description: "" -page_title: "flexibleengine_nat_snat_rule_v2" --- # flexibleengine_nat_snat_rule_v2 -Manages a V2 SNAT rule resource within FlexibleEngine. +Manages a SNAT rule resource of the **public** NAT within FlexibleEngine. ## Example Usage ### SNAT rule in VPC scenario ```hcl -resource "flexibleengine_nat_snat_rule_v2" "snat_1" { - nat_gateway_id = flexibleengine_nat_gateway_v2.nat_1.id +variable "gateway_id" {} +variable "publicip_id" {} +variable "subent_id" {} + +resource "flexibleengine_nat_snat_rule_v2" "test" { + nat_gateway_id = var.gateway_id floating_ip_id = var.publicip_id - subnet_id = flexibleengine_vpc_subnet_v1.example_subnet.id + subnet_id = var.subent_id } ``` -### SNAT rule in Direct Connect scenario +### SNAT rule in DC (Direct Connect) scenario ```hcl -resource "flexibleengine_nat_snat_rule_v2" "snat_2" { - nat_gateway_id = flexibleengine_nat_gateway_v2.nat_1.id +variable "gateway_id" {} +variable "publicip_id" {} + +resource "flexibleengine_nat_snat_rule_v2" "test" { + nat_gateway_id = var.gateway_id floating_ip_id = var.publicip_id source_type = 1 cidr = "192.168.10.0/24" @@ -35,46 +40,50 @@ resource "flexibleengine_nat_snat_rule_v2" "snat_2" { The following arguments are supported: -* `region` - (Optional, String, ForceNew) The region in which to obtain the V2 nat client. - If omitted, the `region` argument of the provider is used. Changing this creates a new snat rule. +* `region` - (Optional, String, ForceNew) Specifies the region where the SNAT rule is located. + If omitted, the provider-level region will be used. Changing this will create a new resource. + +* `nat_gateway_id` - (Required, String, ForceNew) Specifies the ID of the gateway to which the SNAT rule belongs. + Changing this will create a new resource. -* `nat_gateway_id` - (Required, String, ForceNew) ID of the nat gateway this snat rule belongs to. - Changing this creates a new snat rule. +* `floating_ip_id` - (Required, String) Specifies the IDs of floating IPs connected by SNAT rule. + Multiple floating IPs are separated using commas (,). The number of floating IP IDs cannot exceed `20`. -* `floating_ip_id` - (Required, String, ForceNew) ID of the floating ip this snat rule connets to. - Changing this creates a new snat rule. +* `subnet_id` - (Optional, String, ForceNew) Specifies the network IDs of subnet connected by SNAT rule (VPC side). + This parameter and `cidr` are alternative. Changing this will create a new resource. -* `subnet_id` - (Optional, String, ForceNew) ID of the VPC Subnet this snat rule connects to. - This parameter and `cidr` are alternative. Changing this creates a new snat rule. +* `cidr` - (Optional, String, ForceNew) Specifies the CIDR block connected by SNAT rule (DC side). + This parameter and `subnet_id` are alternative. Changing this will create a new resource. -* `cidr` - (Optional, String, ForceNew) Specifies CIDR, which can be in the format of a network segment or a host IP - address. This parameter and `subnet_id` are alternative. Changing this creates a new snat rule. +* `source_type` - (Optional, Int, ForceNew) Specifies the resource scenario. + The valid values are **0** (VPC scenario) and **1** (Direct Connect scenario), and the default value is `0`. + Only `cidr` can be specified over a Direct Connect connection. Changing this will create a new resource. -* `source_type` - (Optional, Int, ForceNew) Specifies the scenario. The valid value is 0 (VPC scenario) and 1 - (Direct Connect scenario). Only `cidr` can be specified over a Direct Connect connection. - If no value is entered, the default value 0 (VPC scenario) is used. Changing this creates a new snat rule. +* `description` - (Optional, String) Specifies the description of the SNAT rule. + The value is a string of no more than `255` characters, and angle brackets (<>) are not allowed. ## Attribute Reference In addition to all arguments above, the following attributes are exported: -* `id` - The resource ID in UUID format. +* `id` - Specifies a resource ID in UUID format. * `floating_ip_address` - The actual floating IP address. -* `status` - The status of the snat rule. +* `status` - The status of the SNAT rule. ## Timeouts This resource provides the following timeouts configuration options: -* `create` - Default is 10 minutes. -* `delete` - Default is 10 minutes. +* `create` - Default is 5 minutes. +* `update` - Default is 5 minutes. +* `delete` - Default is 5 minutes. ## Import -SNAT rules can be imported using the following format: +SNAT rules can be imported using their `id`, e.g. ```shell -terraform import flexibleengine_nat_snat_rule_v2.snat_1 9e0713cb-0a2f-484e-8c7d-daecbb61dbe4 +terraform import flexibleengine_nat_snat_rule_v2.test 9e0713cb-0a2f-484e-8c7d-daecbb61dbe4 ``` diff --git a/flexibleengine/acceptance/resource_flexibleengine_nat_snat_rule_v2_test.go b/flexibleengine/acceptance/resource_flexibleengine_nat_snat_rule_v2_test.go new file mode 100644 index 00000000..59f87b67 --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_nat_snat_rule_v2_test.go @@ -0,0 +1,145 @@ +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk/openstack/nat/v2/snats" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func getPublicSnatRuleResourceFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) { + client, err := cfg.NatGatewayClient(OS_REGION_NAME) + if err != nil { + return nil, fmt.Errorf("error creating NAT v2 client: %s", err) + } + + return snats.Get(client, state.Primary.ID) +} + +func TestAccPublicSnatRule_basic(t *testing.T) { + var ( + obj snats.Rule + + rName = "flexibleengine_nat_snat_rule_v2.test" + name = acceptance.RandomAccResourceNameWithDash() + ) + + rc := acceptance.InitResourceCheck( + rName, + &obj, + getPublicSnatRuleResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccPublicSnatRule_basic_step_1(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "nat_gateway_id", "flexibleengine_nat_gateway_v2.test", "id"), + resource.TestCheckResourceAttrPair(rName, "subnet_id", "flexibleengine_vpc_subnet_v1.test", "id"), + resource.TestCheckResourceAttrPair(rName, "floating_ip_id", "flexibleengine_vpc_eip.test.0", "id"), + resource.TestCheckResourceAttr(rName, "description", "Created by acc test"), + resource.TestCheckResourceAttr(rName, "status", "ACTIVE"), + ), + }, + { + Config: testAccPublicSnatRule_basic_step_2(name), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName, "nat_gateway_id", "flexibleengine_nat_gateway_v2.test", "id"), + resource.TestCheckResourceAttr(rName, "description", ""), + resource.TestCheckResourceAttr(rName, "status", "ACTIVE"), + ), + }, + { + ResourceName: rName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccPublicSnatRule_base(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_vpc_eip" "test" { + count = 2 + + publicip { + type = "5_bgp" + } + + bandwidth { + name = format("%[2]s-%%d", count.index) + size = 5 + share_type = "PER" + charge_mode = "traffic" + } +} + +resource "flexibleengine_compute_instance_v2" "test" { + name = "instance_1" + security_groups = ["default"] + image_id = data.flexibleengine_images_image.test.id + flavor_id = data.flexibleengine_compute_flavors_v2.test.flavors[0] + availability_zone = data.flexibleengine_availability_zones.test.names[0] + metadata = { + foo = "bar" + } + network { + uuid = flexibleengine_vpc_subnet_v1.test.id + } + tags = { + key1 = "value1" + key2 = "value.key" + } +} + +resource "flexibleengine_nat_gateway_v2" "test" { + name = "%[2]s" + description = "test for terraform" + spec = "2" + vpc_id = flexibleengine_vpc_v1.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id +} +`, testBaseComputeResources(name), name) +} + +func testAccPublicSnatRule_basic_step_1(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_nat_snat_rule_v2" "test" { + nat_gateway_id = flexibleengine_nat_gateway_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + floating_ip_id = flexibleengine_vpc_eip.test[0].id + description = "Created by acc test" +} +`, testAccPublicSnatRule_base(name)) +} + +func testAccPublicSnatRule_basic_step_2(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_nat_snat_rule_v2" "test" { + nat_gateway_id = flexibleengine_nat_gateway_v2.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + floating_ip_id = join(",", flexibleengine_vpc_eip.test[*].id) +} +`, testAccPublicSnatRule_base(name)) +} diff --git a/flexibleengine/provider.go b/flexibleengine/provider.go index 5a861c87..9cd43661 100644 --- a/flexibleengine/provider.go +++ b/flexibleengine/provider.go @@ -488,7 +488,6 @@ func Provider() *schema.Provider { "flexibleengine_nat_dnat_rule_v2": resourceNatDnatRuleV2(), "flexibleengine_nat_gateway_v2": resourceNatGatewayV2(), - "flexibleengine_nat_snat_rule_v2": resourceNatSnatRuleV2(), "flexibleengine_vpc_eip": resourceVpcEIPV1(), "flexibleengine_vpc_flow_log_v1": resourceVpcFlowLogV1(), @@ -637,6 +636,7 @@ func Provider() *schema.Provider { "flexibleengine_nat_private_gateway": nat.ResourcePrivateGateway(), "flexibleengine_nat_private_snat_rule": nat.ResourcePrivateSnatRule(), "flexibleengine_nat_private_transit_ip": nat.ResourcePrivateTransitIp(), + "flexibleengine_nat_snat_rule_v2": nat.ResourcePublicSnatRule(), "flexibleengine_obs_bucket_acl": obs.ResourceOBSBucketAcl(), "flexibleengine_obs_bucket_object_acl": obs.ResourceOBSBucketObjectAcl(),