diff --git a/docs/resources/vpc_address_group.md b/docs/resources/vpc_address_group.md index 74561f37be..b3fdf34385 100644 --- a/docs/resources/vpc_address_group.md +++ b/docs/resources/vpc_address_group.md @@ -37,6 +37,29 @@ resource "huaweicloud_vpc_address_group" "ipv6" { } ``` +### Address Group with ip_extra_set + +```hcl +resource "huaweicloud_vpc_address_group" "ipv6" { + name = "group-ipv4" + ip_version = 4 + + ip_extra_set { + ip = "192.168.3.2" + remarks = "terraform test 1" + } + + ip_extra_set { + ip = "192.168.5.0/24" + remarks = "terraform test 2" + } + + ip_extra_set { + ip = "192.168.3.20-192.168.3.100" + } +} +``` + ## Argument Reference The following arguments are supported: @@ -48,8 +71,13 @@ The following arguments are supported: The value is a string of `1` to `64` characters that can contain letters, digits, underscores (_), hyphens (-) and periods (.). -* `addresses` - (Required, List) Specifies an array of one or more IP addresses. The address can be a single IP - address, IP address range or IP address CIDR. The maximum length is 20. +* `addresses` - (Optional, List) Specifies an array of one or more IP addresses. The address can be a single IP + address, IP address range or IP address CIDR. The maximum length is 20. Only one of `addresses` and `ip_extra_set` + can be specified. + +* `ip_extra_set` - (Optional, List) Specifies the IP addresses and their remarks in an IP address group. + The [ip_extra_set](#address_groups_ip_extra_set_struct) structure is documented below. + Only one of `addresses` and `ip_extra_set` can be specified. * `ip_version` - (Optional, Int, ForceNew) Specifies the IP version, either `4` (default) or `6`. Changing this creates a new address group. @@ -66,6 +94,14 @@ The following arguments are supported: * `force_destroy` - (Optional, Bool) Specifies whether to forcibly destroy the address group if it is associated with a security group rule, the address group and the associated security group rule will be deleted together. The default value is **false**. + + +The `ip_extra_set` block supports: + +* `ip` - (Required, String) Specifies the IP address, IP address range, or CIDR block. + +* `remarks` - (Optional, String) Specifies the supplementary information about the IP address, + IP address range, or CIDR block. ## Attribute Reference diff --git a/huaweicloud/services/acceptance/vpc/resource_huaweicloud_vpc_address_group_test.go b/huaweicloud/services/acceptance/vpc/resource_huaweicloud_vpc_address_group_test.go index 2b8b9c36bb..e88d26f6fb 100644 --- a/huaweicloud/services/acceptance/vpc/resource_huaweicloud_vpc_address_group_test.go +++ b/huaweicloud/services/acceptance/vpc/resource_huaweicloud_vpc_address_group_test.go @@ -76,6 +76,56 @@ func TestAccVpcAddressGroup_basic(t *testing.T) { }) } +func TestAccVpcAddressGroup_ipExtraSet(t *testing.T) { + var group vpc_model.ShowAddressGroupResponse + + rName := acceptance.RandomAccResourceName() + rNameUpdate := rName + "_updated" + resourceName := "huaweicloud_vpc_address_group.test" + + rc := acceptance.InitResourceCheck( + resourceName, + &group, + getVpcAddressGroupResourceFunc, + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + ProviderFactories: acceptance.TestAccProviderFactories, + CheckDestroy: rc.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testVpcAdressGroup_ipExtraSet(rName), + Check: resource.ComposeTestCheckFunc( + rc.CheckResourceExists(), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "description", "created by acc test"), + resource.TestCheckResourceAttr(resourceName, "ip_version", "4"), + resource.TestCheckResourceAttr(resourceName, "ip_extra_set.#", "2"), + resource.TestCheckResourceAttr(resourceName, "max_capacity", "20"), + resource.TestCheckResourceAttr(resourceName, "enterprise_project_id", "0"), + ), + }, + { + Config: testVpcAdressGroup_ipExtraSetUpdate(rNameUpdate), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", rNameUpdate), + resource.TestCheckResourceAttr(resourceName, "description", "updated by acc test"), + resource.TestCheckResourceAttr(resourceName, "ip_extra_set.#", "3"), + resource.TestCheckResourceAttr(resourceName, "max_capacity", "10"), + resource.TestCheckResourceAttr(resourceName, "enterprise_project_id", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + func TestAccVpcAddressGroup_ipv6(t *testing.T) { var group vpc_model.ShowAddressGroupResponse @@ -197,6 +247,50 @@ resource "huaweicloud_vpc_address_group" "test" { `, rName) } +func testVpcAdressGroup_ipExtraSet(rName string) string { + return fmt.Sprintf(` +resource "huaweicloud_vpc_address_group" "test" { + name = "%s" + description = "created by acc test" + + ip_extra_set { + ip = "192.168.3.2" + remarks = "terraform test 1" + } + + ip_extra_set { + ip = "192.168.3.20-192.168.3.100" + remarks = "terraform test 2" + } +} +`, rName) +} + +func testVpcAdressGroup_ipExtraSetUpdate(rName string) string { + return fmt.Sprintf(` +resource "huaweicloud_vpc_address_group" "test" { + name = "%s" + description = "updated by acc test" + + ip_extra_set { + ip = "192.168.3.2" + remarks = "terraform test 1" + } + + ip_extra_set { + ip = "192.168.5.0/24" + remarks = "terraform test 2" + } + + ip_extra_set { + ip = "192.168.3.20-192.168.3.100" + } + + max_capacity = 10 +} +`, rName) +} + func testVpcAdressGroup_ipv6(rName string) string { return fmt.Sprintf(` resource "huaweicloud_vpc_address_group" "test" { diff --git a/huaweicloud/services/vpc/resource_huaweicloud_vpc_address_group.go b/huaweicloud/services/vpc/resource_huaweicloud_vpc_address_group.go index dd5d61bb31..00f5f69018 100644 --- a/huaweicloud/services/vpc/resource_huaweicloud_vpc_address_group.go +++ b/huaweicloud/services/vpc/resource_huaweicloud_vpc_address_group.go @@ -52,7 +52,8 @@ func ResourceVpcAddressGroup() *schema.Resource { "addresses": { // the addresses will be sorted by cloud Type: schema.TypeSet, - Required: true, + Optional: true, + Computed: true, MaxItems: 20, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -63,6 +64,25 @@ func ResourceVpcAddressGroup() *schema.Resource { Default: 4, ValidateFunc: validation.IntInSlice([]int{4, 6}), }, + "ip_extra_set": { + // the addresses will be sorted by cloud + Type: schema.TypeSet, + Optional: true, + Computed: true, + MaxItems: 20, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip": { + Type: schema.TypeString, + Required: true, + }, + "remarks": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, "description": { Type: schema.TypeString, Optional: true, @@ -95,15 +115,17 @@ func resourceVpcAddressGroupCreate(ctx context.Context, d *schema.ResourceData, return diag.Errorf("error creating VPC client: %s", err) } - ipSet := utils.ExpandToStringListBySet(d.Get("addresses").(*schema.Set)) + ipSet := buildIpSet(d) + ipExtraSet := buildIpExtraSet(d) addressGroupBody := &vpc_model.CreateAddressGroupOption{ Name: d.Get("name").(string), - IpSet: &ipSet, + IpSet: ipSet, IpVersion: int32(d.Get("ip_version").(int)), Description: utils.StringIgnoreEmpty(d.Get("description").(string)), EnterpriseProjectId: utils.StringIgnoreEmpty(cfg.GetEnterpriseProjectID(d)), MaxCapacity: utils.Int32IgnoreEmpty(int32(d.Get("max_capacity").(int))), + IpExtraSet: ipExtraSet, } createOpts := &vpc_model.CreateAddressGroupRequest{ @@ -122,6 +144,34 @@ func resourceVpcAddressGroupCreate(ctx context.Context, d *schema.ResourceData, return resourceVpcAddressGroupRead(ctx, d, meta) } +func buildIpSet(d *schema.ResourceData) *[]string { + addresses := utils.ExpandToStringListBySet(d.Get("addresses").(*schema.Set)) + if len(addresses) == 0 { + return nil + } + + return &addresses +} + +func buildIpExtraSet(d *schema.ResourceData) *[]vpc_model.IpExtraSetOption { + ipExtraSet := d.Get("ip_extra_set").(*schema.Set).List() + if len(ipExtraSet) == 0 { + return nil + } + + res := make([]vpc_model.IpExtraSetOption, len(ipExtraSet)) + for i, v := range ipExtraSet { + ip := v.(map[string]interface{}) + remarks := ip["remarks"].(string) + res[i] = vpc_model.IpExtraSetOption{ + Ip: ip["ip"].(string), + Remarks: &remarks, + } + } + + return &res +} + func resourceVpcAddressGroupRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { c := meta.(*config.Config) region := c.GetRegion(d) @@ -147,11 +197,29 @@ func resourceVpcAddressGroupRead(_ context.Context, d *schema.ResourceData, meta d.Set("ip_version", response.AddressGroup.IpVersion), d.Set("max_capacity", response.AddressGroup.MaxCapacity), d.Set("enterprise_project_id", response.AddressGroup.EnterpriseProjectId), + d.Set("ip_extra_set", flattenIpExtraSet(response.AddressGroup.IpExtraSet)), ) return diag.FromErr(mErr.ErrorOrNil()) } +func flattenIpExtraSet(ipExtraSet []vpc_model.IpExtraSetRespOption) []map[string]interface{} { + if len(ipExtraSet) == 0 { + return nil + } + + res := make([]map[string]interface{}, len(ipExtraSet)) + + for i, v := range ipExtraSet { + res[i] = map[string]interface{}{ + "ip": v.Ip, + "remarks": v.Remarks, + } + } + + return res +} + func resourceVpcAddressGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { c := meta.(*config.Config) client, err := c.HcVpcV3Client(c.GetRegion(d)) @@ -180,6 +248,10 @@ func resourceVpcAddressGroupUpdate(ctx context.Context, d *schema.ResourceData, addressGroupBody.IpSet = &ipSet } + if d.HasChange("ip_extra_set") { + addressGroupBody.IpExtraSet = buildIpExtraSet(d) + } + if d.HasChange("max_capacity") { addressGroupBody.MaxCapacity = utils.Int32IgnoreEmpty(int32(d.Get("max_capacity").(int))) }