Skip to content

Commit

Permalink
feat: subnet supports enable IPv6 (#989)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lance52259 authored Mar 18, 2021
1 parent afe17fb commit f2818e6
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 40 deletions.
6 changes: 6 additions & 0 deletions docs/data-sources/vpc_subnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,9 @@ In addition to all arguments above, the following attributes are exported:
* `dhcp_enable` - DHCP function for the subnet.

* `subnet_id` - Specifies the subnet (Native OpenStack API) ID.

* `ipv6_enable` - Whether the IPv6 is enabled.

* `ipv6_cidr` - The IPv6 subnet CIDR block. If the subnet is an IPv4 subnet, this parameter is not returned.

* `ipv6_gateway` - The IPv6 subnet gateway. If the subnet is an IPv4 subnet, this parameter is not returned.
6 changes: 6 additions & 0 deletions docs/resources/vpc_subnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ The following arguments are supported:

* `vpc_id` (Required, String, ForceNew) - Specifies the ID of the VPC to which the subnet belongs. Changing this creates a new Subnet.

* `ipv6_enable` (Optional, Bool) - Specifies whether the IPv6 function is enabled for the subnet. Defaults to false.

* `dhcp_enable` (Optional, Bool) - Specifies whether the DHCP function is enabled for the subnet. The value can be true or false. If this parameter is left blank, it is set to true by default.

* `primary_dns` (Optional, String) - Specifies the IP address of DNS server 1 on the subnet. The value must be a valid IP address.
Expand All @@ -72,6 +74,10 @@ In addition to all arguments above, the following attributes are exported:

* `subnet_id` - Specifies the subnet (Native OpenStack API) ID.

* `ipv6_cidr` - The IPv6 subnet CIDR block. If the subnet is an IPv4 subnet, this parameter is not returned.

* `ipv6_gateway` - The IPv6 subnet gateway. If the subnet is an IPv4 subnet, this parameter is not returned.

# Import

Subnets can be imported using the `subnet id`, e.g.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/hashicorp/errwrap v1.0.0
github.com/hashicorp/terraform-plugin-sdk v1.16.0
github.com/hashicorp/terraform-plugin-test v1.3.0 // indirect
github.com/huaweicloud/golangsdk v0.0.0-20210311035428-8cfccba69a01
github.com/huaweicloud/golangsdk v0.0.0-20210316063900-e42405467f37
github.com/jen20/awspolicyequivalence v1.1.0
github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect
github.com/stretchr/testify v1.4.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ github.com/huaweicloud/golangsdk v0.0.0-20210302113304-41351a12edfc h1:CBrAHWGyq
github.com/huaweicloud/golangsdk v0.0.0-20210302113304-41351a12edfc/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/huaweicloud/golangsdk v0.0.0-20210310091354-6e2f74a11d0f h1:AFZM6Vdn8dS764DaaiRKGP26iM7ta2zlQqM+SR1svGk=
github.com/huaweicloud/golangsdk v0.0.0-20210310091354-6e2f74a11d0f/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/huaweicloud/golangsdk v0.0.0-20210311035428-8cfccba69a01 h1:NIh2E9JUKO2/4xGjcSFgzXLp/cCcyPj6mVmPZlMzo/Q=
github.com/huaweicloud/golangsdk v0.0.0-20210311035428-8cfccba69a01/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/huaweicloud/golangsdk v0.0.0-20210316063900-e42405467f37 h1:IvZLKCRqKrGbiDVJXjV9qpUF+2kl+xCODRz6Wjem8mk=
github.com/huaweicloud/golangsdk v0.0.0-20210316063900-e42405467f37/go.mod h1:fcOI5u+0f62JtJd7zkCch/Z57BNC6bhqb32TKuiF4r0=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
Expand Down
15 changes: 15 additions & 0 deletions huaweicloud/data_source_huaweicloud_vpc_subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ func DataSourceVpcSubnetV1() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"ipv6_enable": {
Type: schema.TypeBool,
Computed: true,
},
"ipv6_cidr": {
Type: schema.TypeString,
Computed: true,
},
"ipv6_gateway": {
Type: schema.TypeString,
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -117,12 +129,15 @@ func dataSourceVpcSubnetV1Read(d *schema.ResourceData, meta interface{}) error {
d.Set("dns_list", Subnets.DnsList)
d.Set("status", Subnets.Status)
d.Set("gateway_ip", Subnets.GatewayIP)
d.Set("ipv6_enable", Subnets.EnableIPv6)
d.Set("dhcp_enable", Subnets.EnableDHCP)
d.Set("primary_dns", Subnets.PRIMARY_DNS)
d.Set("secondary_dns", Subnets.SECONDARY_DNS)
d.Set("availability_zone", Subnets.AvailabilityZone)
d.Set("vpc_id", Subnets.VPC_ID)
d.Set("subnet_id", Subnets.SubnetId)
d.Set("ipv6_cidr", Subnets.IPv6CIDR)
d.Set("ipv6_gateway", Subnets.IPv6Gateway)
d.Set("region", GetRegion(d, config))

return nil
Expand Down
126 changes: 90 additions & 36 deletions huaweicloud/data_source_huaweicloud_vpc_subnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package huaweicloud

import (
"fmt"
"regexp"
"strconv"
"testing"

Expand All @@ -12,6 +13,10 @@ import (

func TestAccVpcSubnetV1DataSource_basic(t *testing.T) {
rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5))
dNameByID := "data.huaweicloud_vpc_subnet.by_id"
dNameByCIDR := "data.huaweicloud_vpc_subnet.by_cidr"
dNameByName := "data.huaweicloud_vpc_subnet.by_name"
dNameByVpcID := "data.huaweicloud_vpc_subnet.by_vpc_id"
tmp := strconv.Itoa(acctest.RandIntRange(1, 254))
cidr := fmt.Sprintf("172.16.%s.0/24", string(tmp))
gateway := fmt.Sprintf("172.16.%s.1", string(tmp))
Expand All @@ -21,59 +26,85 @@ func TestAccVpcSubnetV1DataSource_basic(t *testing.T) {
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceVpcSubnetV1Config(rName, cidr, gateway),
Config: testAccVpcSubnetV1DataSource_basic(rName, cidr, gateway),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceVpcSubnetV1Check("data.huaweicloud_vpc_subnet.by_id", rName, cidr, gateway),
testAccDataSourceVpcSubnetV1Check("data.huaweicloud_vpc_subnet.by_cidr", rName, cidr, gateway),
testAccDataSourceVpcSubnetV1Check("data.huaweicloud_vpc_subnet.by_name", rName, cidr, gateway),
testAccDataSourceVpcSubnetV1Check("data.huaweicloud_vpc_subnet.by_vpc_id", rName, cidr, gateway),
resource.TestCheckResourceAttr(
"data.huaweicloud_vpc_subnet.by_id", "status", "ACTIVE"),
resource.TestCheckResourceAttr(
"data.huaweicloud_vpc_subnet.by_id", "dhcp_enable", "true"),
testAccCheckVpcSubnetV1DataSourceID(dNameByID),
resource.TestCheckResourceAttr(dNameByID, "name", rName),
resource.TestCheckResourceAttr(dNameByID, "cidr", cidr),
resource.TestCheckResourceAttr(dNameByID, "gateway_ip", gateway),
resource.TestCheckResourceAttr(dNameByID, "status", "ACTIVE"),
resource.TestCheckResourceAttr(dNameByID, "dhcp_enable", "true"),
testAccCheckVpcSubnetV1DataSourceID(dNameByCIDR),
resource.TestCheckResourceAttr(dNameByCIDR, "name", rName),
resource.TestCheckResourceAttr(dNameByCIDR, "cidr", cidr),
resource.TestCheckResourceAttr(dNameByCIDR, "gateway_ip", gateway),
resource.TestCheckResourceAttr(dNameByCIDR, "status", "ACTIVE"),
resource.TestCheckResourceAttr(dNameByCIDR, "dhcp_enable", "true"),
testAccCheckVpcSubnetV1DataSourceID(dNameByName),
resource.TestCheckResourceAttr(dNameByName, "name", rName),
resource.TestCheckResourceAttr(dNameByName, "cidr", cidr),
resource.TestCheckResourceAttr(dNameByName, "gateway_ip", gateway),
resource.TestCheckResourceAttr(dNameByName, "status", "ACTIVE"),
resource.TestCheckResourceAttr(dNameByName, "dhcp_enable", "true"),
testAccCheckVpcSubnetV1DataSourceID(dNameByVpcID),
resource.TestCheckResourceAttr(dNameByVpcID, "name", rName),
resource.TestCheckResourceAttr(dNameByVpcID, "cidr", cidr),
resource.TestCheckResourceAttr(dNameByVpcID, "gateway_ip", gateway),
resource.TestCheckResourceAttr(dNameByVpcID, "status", "ACTIVE"),
resource.TestCheckResourceAttr(dNameByVpcID, "dhcp_enable", "true"),
),
},
},
})
}

func testAccDataSourceVpcSubnetV1Check(n, name, cidr, gateway_ip string) resource.TestCheckFunc {
func TestAccVpcSubnetV1DataSource_ipv6(t *testing.T) {
rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5))
tmp := strconv.Itoa(acctest.RandIntRange(1, 254))
cidr := fmt.Sprintf("172.16.%s.0/24", string(tmp))
gateway := fmt.Sprintf("172.16.%s.1", string(tmp))
dName := "data.huaweicloud_vpc_subnet.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccVpcSubnetV1DataSource_ipv6(rName, cidr, gateway),
Check: resource.ComposeTestCheckFunc(
testAccCheckVpcSubnetV1DataSourceID(dName),
resource.TestCheckResourceAttr(dName, "name", rName),
resource.TestCheckResourceAttr(dName, "cidr", cidr),
resource.TestCheckResourceAttr(dName, "gateway_ip", gateway),
resource.TestCheckResourceAttr(dName, "status", "ACTIVE"),
resource.TestCheckResourceAttr(dName, "dhcp_enable", "true"),
resource.TestCheckResourceAttr(dName, "ipv6_enable", "true"),
resource.TestMatchResourceAttr(dName, "ipv6_cidr",
regexp.MustCompile("([[:xdigit:]]*):([[:xdigit:]]*:){1,6}[[:xdigit:]]*/\\d{1,3}")),
resource.TestMatchResourceAttr(dName, "ipv6_gateway",
regexp.MustCompile("([[:xdigit:]]*):([[:xdigit:]]*:){1,6}([[:xdigit:]]){1,4}")),
),
},
},
})
}

func testAccCheckVpcSubnetV1DataSourceID(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("root module has no resource called %s", n)
}

subnetRs, ok := s.RootModule().Resources["huaweicloud_vpc_subnet.test"]
if !ok {
return fmt.Errorf("can't find huaweicloud_vpc_subnet.test in state")
return fmt.Errorf("Can't find %s in state", n)
}

attr := rs.Primary.Attributes

if attr["id"] != subnetRs.Primary.Attributes["id"] {
return fmt.Errorf(
"id is %s; want %s",
attr["id"],
subnetRs.Primary.Attributes["id"],
)
}

if attr["cidr"] != cidr {
return fmt.Errorf("bad subnet cidr %s, expected: %s", attr["cidr"], cidr)
}
if attr["name"] != name {
return fmt.Errorf("bad subnet name %s", attr["name"])
}
if attr["gateway_ip"] != gateway_ip {
return fmt.Errorf("bad subnet gateway_ip %s", attr["gateway_ip"])
if rs.Primary.ID == "" {
return fmt.Errorf("Vpc Subnet data source ID not set")
}

return nil
}
}

func testAccDataSourceVpcSubnetV1Config(rName, cidr, gateway string) string {
func testAccVpcSubnetV1DataSource_basic(rName, cidr, gateway string) string {
return fmt.Sprintf(`
data "huaweicloud_availability_zones" "test" {}
Expand All @@ -87,7 +118,6 @@ resource "huaweicloud_vpc_subnet" "test" {
cidr = "%s"
gateway_ip = "%s"
vpc_id = huaweicloud_vpc.test.id
availability_zone = data.huaweicloud_availability_zones.test.names[0]
}
Expand All @@ -108,3 +138,27 @@ data "huaweicloud_vpc_subnet" "by_vpc_id" {
}
`, rName, cidr, rName, cidr, gateway)
}

func testAccVpcSubnetV1DataSource_ipv6(rName, cidr, gateway string) string {
return fmt.Sprintf(`
data "huaweicloud_availability_zones" "test" {}
resource "huaweicloud_vpc" "test" {
name = "%s"
cidr = "%s"
}
resource "huaweicloud_vpc_subnet" "test" {
name = "%s"
cidr = "%s"
gateway_ip = "%s"
vpc_id = huaweicloud_vpc.test.id
ipv6_enable = true
availability_zone = data.huaweicloud_availability_zones.test.names[0]
}
data "huaweicloud_vpc_subnet" "test" {
id = huaweicloud_vpc_subnet.test.id
}
`, rName, cidr, rName, cidr, gateway)
}
25 changes: 25 additions & 0 deletions huaweicloud/resource_huaweicloud_vpc_subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ func ResourceVpcSubnetV1() *schema.Resource {
ForceNew: true,
ValidateFunc: validateIP,
},
"ipv6_enable": {
Type: schema.TypeBool,
Optional: true,
},
"dhcp_enable": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -102,6 +106,14 @@ func ResourceVpcSubnetV1() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"ipv6_cidr": {
Type: schema.TypeString,
Computed: true,
},
"ipv6_gateway": {
Type: schema.TypeString,
Computed: true,
},
"tags": tagsSchema(),
},
}
Expand All @@ -115,11 +127,13 @@ func resourceVpcSubnetV1Create(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Error creating Huaweicloud networking client: %s", err)
}

enable := d.Get("ipv6_enable").(bool)
createOpts := subnets.CreateOpts{
Name: d.Get("name").(string),
CIDR: d.Get("cidr").(string),
AvailabilityZone: d.Get("availability_zone").(string),
GatewayIP: d.Get("gateway_ip").(string),
EnableIPv6: &enable,
EnableDHCP: d.Get("dhcp_enable").(bool),
VPC_ID: d.Get("vpc_id").(string),
PRIMARY_DNS: d.Get("primary_dns").(string),
Expand Down Expand Up @@ -189,12 +203,15 @@ func resourceVpcSubnetV1Read(d *schema.ResourceData, meta interface{}) error {
d.Set("cidr", n.CIDR)
d.Set("dns_list", n.DnsList)
d.Set("gateway_ip", n.GatewayIP)
d.Set("ipv6_enable", n.EnableIPv6)
d.Set("dhcp_enable", n.EnableDHCP)
d.Set("primary_dns", n.PRIMARY_DNS)
d.Set("secondary_dns", n.SECONDARY_DNS)
d.Set("availability_zone", n.AvailabilityZone)
d.Set("vpc_id", n.VPC_ID)
d.Set("subnet_id", n.SubnetId)
d.Set("ipv6_cidr", n.IPv6CIDR)
d.Set("ipv6_gateway", n.IPv6Gateway)
d.Set("region", GetRegion(d, config))

// save VpcSubnet tags
Expand Down Expand Up @@ -226,6 +243,14 @@ func resourceVpcSubnetV1Update(d *schema.ResourceData, meta interface{}) error {
//as name is mandatory while updating subnet
updateOpts.Name = d.Get("name").(string)

if d.HasChange("ipv6_enable") {
if d.Get("ipv6_enable").(bool) {
enable := d.Get("ipv6_enable").(bool)
updateOpts.EnableIPv6 = &enable
} else {
return fmt.Errorf("Parameter cannot be disabled after IPv6 enable")
}
}
if d.HasChange("primary_dns") {
updateOpts.PRIMARY_DNS = d.Get("primary_dns").(string)
}
Expand Down
Loading

0 comments on commit f2818e6

Please sign in to comment.