From c3ccbe234bf6c3f4a97816ec2594cd292cb561be Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Wed, 1 Oct 2025 22:29:28 +0300 Subject: [PATCH 1/8] Add fixed_ip block support in networking_port_v2 import Set fixed_ip in resourceNetworkingPortV2Read Remove ImportStateVerifyIgnore for fixed_ip in import test Mark subnet_id and ip_address fields as computed: true --- .../import_openstack_networking_port_v2_test.go | 12 ------------ openstack/networking_port_v2.go | 13 +++++++++++++ openstack/resource_openstack_networking_port_v2.go | 4 ++++ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/openstack/import_openstack_networking_port_v2_test.go b/openstack/import_openstack_networking_port_v2_test.go index af98ffef1..45446c345 100644 --- a/openstack/import_openstack_networking_port_v2_test.go +++ b/openstack/import_openstack_networking_port_v2_test.go @@ -25,9 +25,6 @@ func TestAccNetworkingV2Port_importBasic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "fixed_ip", - }, }, }, }) @@ -52,9 +49,6 @@ func TestAccNetworkingV2Port_importAllowedAddressPairs(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "fixed_ip", - }, }, }, }) @@ -79,9 +73,6 @@ func TestAccNetworkingV2Port_importAllowedAddressPairsNoMAC(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "fixed_ip", - }, }, }, }) @@ -106,9 +97,6 @@ func TestAccNetworkingV2Port_importDHCPOpts(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "fixed_ip", - }, }, }, }) diff --git a/openstack/networking_port_v2.go b/openstack/networking_port_v2.go index 753c1f6f6..fdd250088 100644 --- a/openstack/networking_port_v2.go +++ b/openstack/networking_port_v2.go @@ -214,6 +214,19 @@ func expandNetworkingPortFixedIPToStringSlice(fixedIPs []ports.IP) []string { return s } +func flattenNetworkingPortFixedIPs(fixedIPs []ports.IP) []map[string]any { + f := make([]map[string]any, len(fixedIPs)) + + for i, fixedIP := range fixedIPs { + f[i] = map[string]any{ + "subnet_id": fixedIP.SubnetID, + "ip_address": fixedIP.IPAddress, + } + } + + return f +} + func flattenNetworkingPortBindingV2(port portExtended) any { var portBinding []map[string]any diff --git a/openstack/resource_openstack_networking_port_v2.go b/openstack/resource_openstack_networking_port_v2.go index 9eb465e80..629010416 100644 --- a/openstack/resource_openstack_networking_port_v2.go +++ b/openstack/resource_openstack_networking_port_v2.go @@ -119,10 +119,12 @@ func resourceNetworkingPortV2() *schema.Resource { "subnet_id": { Type: schema.TypeString, Optional: true, + Computed: true, }, "ip_address": { Type: schema.TypeString, Optional: true, + Computed: true, }, }, }, @@ -465,6 +467,8 @@ func resourceNetworkingPortV2Read(ctx context.Context, d *schema.ResourceData, m // which is usually alpha-numeric. d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) + d.Set("fixed_ip", flattenNetworkingPortFixedIPs(port.FixedIPs)) + // Set all security groups. // This can be different from what the user specified since // the port can have the "default" group automatically applied. From fe31bf405e2d334838ceb5c80521328ab362e001 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Wed, 1 Oct 2025 23:33:41 +0300 Subject: [PATCH 2/8] Set fixed_ip false --- openstack/data_source_openstack_networking_subnet_v2_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/openstack/data_source_openstack_networking_subnet_v2_test.go b/openstack/data_source_openstack_networking_subnet_v2_test.go index 6dd69b5a3..ceed0eb43 100644 --- a/openstack/data_source_openstack_networking_subnet_v2_test.go +++ b/openstack/data_source_openstack_networking_subnet_v2_test.go @@ -312,6 +312,7 @@ resource "openstack_networking_port_v2" "port_1" { name = "test_port" network_id = data.openstack_networking_subnet_v2.subnet_1.network_id admin_state_up = "true" + no_fixed_ip = "true" } `, testAccOpenStackNetworkingSubnetV2DataSourceSubnet) From 91577935e30a006c7ed6af16240787e908b0a84e Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 2 Oct 2025 09:48:51 +0300 Subject: [PATCH 3/8] Refactor all_fixed_ips to be a map with ip_address and subnet_id --- docs/data-sources/networking_port_v2.md | 4 +- docs/resources/networking_port_v2.md | 6 +-- ...ata_source_openstack_networking_port_v2.go | 13 +++++- ...ource_openstack_networking_port_v2_test.go | 2 +- ...rce_openstack_networking_subnet_v2_test.go | 1 - ...e_resource_openstack_networking_port_v2.go | 36 +++++++++++++++ ...ource_openstack_networking_port_v2_test.go | 45 +++++++++++++++++++ openstack/networking_port_v2.go | 20 +++------ .../resource_openstack_networking_port_v2.go | 24 ++++++++-- ...ource_openstack_taas_tap_mirror_v2_test.go | 4 +- 10 files changed, 127 insertions(+), 28 deletions(-) create mode 100644 openstack/migrate_resource_openstack_networking_port_v2.go create mode 100644 openstack/migrate_resource_openstack_networking_port_v2_test.go diff --git a/docs/data-sources/networking_port_v2.md b/docs/data-sources/networking_port_v2.md index 0f17e645b..ff58be99e 100644 --- a/docs/data-sources/networking_port_v2.md +++ b/docs/data-sources/networking_port_v2.md @@ -83,8 +83,8 @@ are exported: addresses that can be active on this port. The structure is described below. -* `all_fixed_ips` - The collection of Fixed IP addresses on the port in the - order returned by the Network v2 API. +* `all_fixed_ips` - The collection of Fixed IP addresses and subnet IDs on the + port in the order returned by the Network v2 API. * `all_security_group_ids` - The set of security group IDs applied on the port. diff --git a/docs/resources/networking_port_v2.md b/docs/resources/networking_port_v2.md index 6b9407342..a82bc94dd 100644 --- a/docs/resources/networking_port_v2.md +++ b/docs/resources/networking_port_v2.md @@ -174,7 +174,7 @@ The following arguments are supported: * `dns_name` - (Optional) The port DNS name. Available, when Neutron DNS extension is enabled. - + * `qos_policy_id` - (Optional) Reference to the associated QoS policy. The `fixed_ip` block supports: @@ -231,8 +231,8 @@ The following attributes are exported: * `security_group_ids` - See Argument Reference above. * `device_id` - See Argument Reference above. * `fixed_ip` - See Argument Reference above. -* `all_fixed_ips` - The collection of Fixed IP addresses on the port in the - order returned by the Network v2 API. +* `all_fixed_ips` - The collection of Fixed IP addresses and sibnet IDs on the + port in the order returned by the Network v2 API. * `all_security_group_ids` - The collection of Security Group IDs on the port which have been explicitly and implicitly added. * `extra_dhcp_option` - See Argument Reference above. diff --git a/openstack/data_source_openstack_networking_port_v2.go b/openstack/data_source_openstack_networking_port_v2.go index 2a2387e7f..3d1e4d8ff 100644 --- a/openstack/data_source_openstack_networking_port_v2.go +++ b/openstack/data_source_openstack_networking_port_v2.go @@ -118,7 +118,18 @@ func dataSourceNetworkingPortV2() *schema.Resource { "all_fixed_ips": { Type: schema.TypeList, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, }, "all_security_group_ids": { diff --git a/openstack/data_source_openstack_networking_port_v2_test.go b/openstack/data_source_openstack_networking_port_v2_test.go index 43c9b266c..e79a91177 100644 --- a/openstack/data_source_openstack_networking_port_v2_test.go +++ b/openstack/data_source_openstack_networking_port_v2_test.go @@ -116,6 +116,6 @@ data "openstack_networking_port_v2" "port_2" { } data "openstack_networking_port_v2" "port_3" { - fixed_ip = openstack_networking_port_v2.port_1.all_fixed_ips.1 + fixed_ip = openstack_networking_port_v2.port_1.all_fixed_ips[1].ip_address } ` diff --git a/openstack/data_source_openstack_networking_subnet_v2_test.go b/openstack/data_source_openstack_networking_subnet_v2_test.go index ceed0eb43..6dd69b5a3 100644 --- a/openstack/data_source_openstack_networking_subnet_v2_test.go +++ b/openstack/data_source_openstack_networking_subnet_v2_test.go @@ -312,7 +312,6 @@ resource "openstack_networking_port_v2" "port_1" { name = "test_port" network_id = data.openstack_networking_subnet_v2.subnet_1.network_id admin_state_up = "true" - no_fixed_ip = "true" } `, testAccOpenStackNetworkingSubnetV2DataSourceSubnet) diff --git a/openstack/migrate_resource_openstack_networking_port_v2.go b/openstack/migrate_resource_openstack_networking_port_v2.go new file mode 100644 index 000000000..7f900fe06 --- /dev/null +++ b/openstack/migrate_resource_openstack_networking_port_v2.go @@ -0,0 +1,36 @@ +package openstack + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceNetworkingPortV2V0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "all_fixed_ips": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func upgradeNetworkingPortV2StateV0toV1(_ context.Context, rawState map[string]any, _ any) (map[string]any, error) { + if v, ok := rawState["all_fixed_ips"]; ok { + if list, ok := v.([]any); ok { + newList := make([]map[string]any, len(list)) + for i, ipRaw := range list { + ipStr, _ := ipRaw.(string) + newList[i] = map[string]any{ + "ip_address": ipStr, + "subnet_id": "", + } + } + rawState["all_fixed_ips"] = newList + } + } + return rawState, nil +} diff --git a/openstack/migrate_resource_openstack_networking_port_v2_test.go b/openstack/migrate_resource_openstack_networking_port_v2_test.go new file mode 100644 index 000000000..7ce895c5e --- /dev/null +++ b/openstack/migrate_resource_openstack_networking_port_v2_test.go @@ -0,0 +1,45 @@ +package openstack + +import ( + "reflect" + "testing" +) + +func testResourceNetworkingV2PortStateDataV0() map[string]any { + return map[string]any{ + "name": "test", + "all_fixed_ips": []any{ + "192.168.0.10", + "192.168.0.11", + }, + } +} + +func testResourceNetworkingV2PortStateDataV1() map[string]any { + return map[string]any{ + "name": "test", + "all_fixed_ips": []map[string]any{ + { + "ip_address": "192.168.0.10", + "subnet_id": "", + }, + { + "ip_address": "192.168.0.11", + "subnet_id": "", + }, + }, + } +} + +func TestAccNetworkingV2PortStateUpgradeV0(t *testing.T) { + expected := testResourceNetworkingV2PortStateDataV1() + + actual, err := upgradeNetworkingPortV2StateV0toV1(t.Context(), testResourceNetworkingV2PortStateDataV0(), nil) + if err != nil { + t.Fatalf("error migrating state: %s", err) + } + + if !reflect.DeepEqual(expected, actual) { + t.Fatalf("\n\nexpected:\n\n%#v\n\ngot:\n\n%#v\n\n", expected, actual) + } +} diff --git a/openstack/networking_port_v2.go b/openstack/networking_port_v2.go index fdd250088..6b1ada045 100644 --- a/openstack/networking_port_v2.go +++ b/openstack/networking_port_v2.go @@ -205,26 +205,16 @@ func resourceNetworkingPortV2AllowedAddressPairsHash(v any) int { return hashcode.String(buf.String()) } -func expandNetworkingPortFixedIPToStringSlice(fixedIPs []ports.IP) []string { - s := make([]string, len(fixedIPs)) +func expandNetworkingPortFixedIPToStringSlice(fixedIPs []ports.IP) []map[string]any { + s := make([]map[string]any, len(fixedIPs)) for i, fixedIP := range fixedIPs { - s[i] = fixedIP.IPAddress - } - - return s -} - -func flattenNetworkingPortFixedIPs(fixedIPs []ports.IP) []map[string]any { - f := make([]map[string]any, len(fixedIPs)) - - for i, fixedIP := range fixedIPs { - f[i] = map[string]any{ - "subnet_id": fixedIP.SubnetID, + s[i] = map[string]any{ "ip_address": fixedIP.IPAddress, + "subnet_id": fixedIP.SubnetID, } } - return f + return s } func flattenNetworkingPortBindingV2(port portExtended) any { diff --git a/openstack/resource_openstack_networking_port_v2.go b/openstack/resource_openstack_networking_port_v2.go index 629010416..9ab8c8c1e 100644 --- a/openstack/resource_openstack_networking_port_v2.go +++ b/openstack/resource_openstack_networking_port_v2.go @@ -35,6 +35,15 @@ func resourceNetworkingPortV2() *schema.Resource { Delete: schema.DefaultTimeout(10 * time.Minute), }, + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: resourceNetworkingPortV2V0().CoreConfigSchema().ImpliedType(), + Upgrade: upgradeNetworkingPortV2StateV0toV1, + Version: 0, + }, + }, + Schema: map[string]*schema.Schema{ "region": { Type: schema.TypeString, @@ -188,7 +197,18 @@ func resourceNetworkingPortV2() *schema.Resource { "all_fixed_ips": { Type: schema.TypeList, Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, }, "all_security_group_ids": { @@ -467,8 +487,6 @@ func resourceNetworkingPortV2Read(ctx context.Context, d *schema.ResourceData, m // which is usually alpha-numeric. d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) - d.Set("fixed_ip", flattenNetworkingPortFixedIPs(port.FixedIPs)) - // Set all security groups. // This can be different from what the user specified since // the port can have the "default" group automatically applied. diff --git a/openstack/resource_openstack_taas_tap_mirror_v2_test.go b/openstack/resource_openstack_taas_tap_mirror_v2_test.go index af342bb62..25a5fe062 100644 --- a/openstack/resource_openstack_taas_tap_mirror_v2_test.go +++ b/openstack/resource_openstack_taas_tap_mirror_v2_test.go @@ -166,7 +166,7 @@ resource "openstack_taas_tap_mirror_v2" "tap_mirror_1" { description = "desc" mirror_type = "erspanv1" port_id = openstack_networking_port_v2.port_1.id - remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0] + remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0].ip_address directions { in = 1000 out = 1001 @@ -200,7 +200,7 @@ resource "openstack_taas_tap_mirror_v2" "tap_mirror_1" { description = "updated desc" mirror_type = "erspanv1" port_id = openstack_networking_port_v2.port_1.id - remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0] + remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0].ip_address directions { in = 1000 out = 1001 From c45bfea89c7da25165504f69d4f1b327fac0a155 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 2 Oct 2025 10:09:48 +0300 Subject: [PATCH 4/8] Linter, revert unused changes --- ...mport_openstack_networking_port_v2_test.go | 12 ++++++++++ ...e_resource_openstack_networking_port_v2.go | 23 +++++++++++-------- openstack/provider_test.go | 2 +- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/openstack/import_openstack_networking_port_v2_test.go b/openstack/import_openstack_networking_port_v2_test.go index 45446c345..af98ffef1 100644 --- a/openstack/import_openstack_networking_port_v2_test.go +++ b/openstack/import_openstack_networking_port_v2_test.go @@ -25,6 +25,9 @@ func TestAccNetworkingV2Port_importBasic(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "fixed_ip", + }, }, }, }) @@ -49,6 +52,9 @@ func TestAccNetworkingV2Port_importAllowedAddressPairs(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "fixed_ip", + }, }, }, }) @@ -73,6 +79,9 @@ func TestAccNetworkingV2Port_importAllowedAddressPairsNoMAC(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "fixed_ip", + }, }, }, }) @@ -97,6 +106,9 @@ func TestAccNetworkingV2Port_importDHCPOpts(t *testing.T) { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "fixed_ip", + }, }, }, }) diff --git a/openstack/migrate_resource_openstack_networking_port_v2.go b/openstack/migrate_resource_openstack_networking_port_v2.go index 7f900fe06..c74c6ebec 100644 --- a/openstack/migrate_resource_openstack_networking_port_v2.go +++ b/openstack/migrate_resource_openstack_networking_port_v2.go @@ -18,19 +18,24 @@ func resourceNetworkingPortV2V0() *schema.Resource { } } +func convertFixedIPs(list []any) []map[string]any { + newList := make([]map[string]any, len(list)) + for i, ipRaw := range list { + newList[i] = map[string]any{ + "ip_address": ipRaw.(string), + "subnet_id": "", + } + } + + return newList +} + func upgradeNetworkingPortV2StateV0toV1(_ context.Context, rawState map[string]any, _ any) (map[string]any, error) { if v, ok := rawState["all_fixed_ips"]; ok { if list, ok := v.([]any); ok { - newList := make([]map[string]any, len(list)) - for i, ipRaw := range list { - ipStr, _ := ipRaw.(string) - newList[i] = map[string]any{ - "ip_address": ipStr, - "subnet_id": "", - } - } - rawState["all_fixed_ips"] = newList + rawState["all_fixed_ips"] = convertFixedIPs(list) } } + return rawState, nil } diff --git a/openstack/provider_test.go b/openstack/provider_test.go index 0c1467ea8..7d5f09183 100644 --- a/openstack/provider_test.go +++ b/openstack/provider_test.go @@ -249,7 +249,7 @@ func testAccPreCheckAdminOnly(t *testing.T) { func testAccPreCheckNonAdminOnly(t *testing.T) { v := os.Getenv("OS_USERNAME") - if v != "demo" { + if v != "eremin_terraform" { t.Skip("Skipping test because it requires the demo (non-admin) user") } } From eaff922ad10d9b5e631380147f15bed32d379963 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 2 Oct 2025 10:10:32 +0300 Subject: [PATCH 5/8] Revert test user --- openstack/provider_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/provider_test.go b/openstack/provider_test.go index 7d5f09183..0c1467ea8 100644 --- a/openstack/provider_test.go +++ b/openstack/provider_test.go @@ -249,7 +249,7 @@ func testAccPreCheckAdminOnly(t *testing.T) { func testAccPreCheckNonAdminOnly(t *testing.T) { v := os.Getenv("OS_USERNAME") - if v != "eremin_terraform" { + if v != "demo" { t.Skip("Skipping test because it requires the demo (non-admin) user") } } From c98ffc8f3e2b12c9d6d6613fca06a93e465e7f17 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 2 Oct 2025 11:20:32 +0300 Subject: [PATCH 6/8] Fix tests --- openstack/resource_openstack_networking_port_v2_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openstack/resource_openstack_networking_port_v2_test.go b/openstack/resource_openstack_networking_port_v2_test.go index 4a64fabb3..7b4f54f19 100644 --- a/openstack/resource_openstack_networking_port_v2_test.go +++ b/openstack/resource_openstack_networking_port_v2_test.go @@ -288,9 +288,9 @@ func TestAccNetworkingV2Port_fixedIPs(t *testing.T) { Config: testAccNetworkingV2PortFixedIPs, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - "openstack_networking_port_v2.port_1", "all_fixed_ips.0", "192.168.199.23"), + "openstack_networking_port_v2.port_1", "all_fixed_ips.0.ip_address", "192.168.199.23"), resource.TestCheckResourceAttr( - "openstack_networking_port_v2.port_1", "all_fixed_ips.1", "192.168.199.24"), + "openstack_networking_port_v2.port_1", "all_fixed_ips.1.ip_address", "192.168.199.24"), ), }, }, From 7c6601b4ac58210311d3c3b0d2721e45194cf559 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 2 Oct 2025 11:33:14 +0300 Subject: [PATCH 7/8] Use no_fixed_ip --- openstack/resource_openstack_networking_port_v2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/resource_openstack_networking_port_v2_test.go b/openstack/resource_openstack_networking_port_v2_test.go index 7b4f54f19..51232f8b6 100644 --- a/openstack/resource_openstack_networking_port_v2_test.go +++ b/openstack/resource_openstack_networking_port_v2_test.go @@ -2212,7 +2212,7 @@ resource "openstack_networking_port_v2" "port_1" { name = "port_1" admin_state_up = "true" network_id = openstack_networking_network_v2.network_1.id - fixed_ip {} + no_fixed_ip = true } ` From f2719685811c4a4d83e5ab9815c141e3399273ae Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Fri, 3 Oct 2025 22:50:45 +0300 Subject: [PATCH 8/8] Add fixed_ips --- docs/data-sources/networking_port_v2.md | 12 ++++- docs/resources/networking_port_v2.md | 7 +++ ...ata_source_openstack_networking_port_v2.go | 10 ++++- ...ource_openstack_networking_port_v2_test.go | 8 +++- ...e_resource_openstack_networking_port_v2.go | 41 ----------------- ...ource_openstack_networking_port_v2_test.go | 45 ------------------- openstack/networking_port_v2.go | 9 ++++ .../resource_openstack_networking_port_v2.go | 25 ++++++----- ...ource_openstack_networking_port_v2_test.go | 24 +++++++++- ...ource_openstack_taas_tap_mirror_v2_test.go | 4 +- 10 files changed, 81 insertions(+), 104 deletions(-) delete mode 100644 openstack/migrate_resource_openstack_networking_port_v2.go delete mode 100644 openstack/migrate_resource_openstack_networking_port_v2_test.go diff --git a/docs/data-sources/networking_port_v2.md b/docs/data-sources/networking_port_v2.md index ff58be99e..54db33f48 100644 --- a/docs/data-sources/networking_port_v2.md +++ b/docs/data-sources/networking_port_v2.md @@ -83,8 +83,12 @@ are exported: addresses that can be active on this port. The structure is described below. -* `all_fixed_ips` - The collection of Fixed IP addresses and subnet IDs on the - port in the order returned by the Network v2 API. +* `all_fixed_ips` - The collection of Fixed IP addresses on the port in the + order returned by the Network v2 API. + +* `fixed_ips` - The collection of objects containing both IP addresses and + their corresponding subnet IDs on the port, in the order returned by the + Network v2 API. Extends the functionality of all_fixed_ips. * `all_security_group_ids` - The set of security group IDs applied on the port. @@ -125,3 +129,7 @@ The `binding` attribute has fields below: specific binding. * `vif_type` - The VNIC type of the port binding. + +## Deprecated Attributes + +* `all_fixed_ips`: Will be removed in a future release. Use `fixed_ips` instead. diff --git a/docs/resources/networking_port_v2.md b/docs/resources/networking_port_v2.md index a82bc94dd..16b366e20 100644 --- a/docs/resources/networking_port_v2.md +++ b/docs/resources/networking_port_v2.md @@ -233,6 +233,9 @@ The following attributes are exported: * `fixed_ip` - See Argument Reference above. * `all_fixed_ips` - The collection of Fixed IP addresses and sibnet IDs on the port in the order returned by the Network v2 API. +* `fixed_ips` - The collection of objects containing both IP addresses and + their corresponding subnet IDs on the port, in the order returned by the + Network v2 API. Extends the functionality of all_fixed_ips. * `all_security_group_ids` - The collection of Security Group IDs on the port which have been explicitly and implicitly added. * `extra_dhcp_option` - See Argument Reference above. @@ -244,6 +247,10 @@ The following attributes are exported: * `dns_assignment` - The list of maps representing port DNS assignments. * `qos_policy_id` - See Argument Reference above. +## Deprecated Attributes + +* `all_fixed_ips`: Will be removed in a future release. Use `fixed_ips` instead. + ## Import Ports can be imported using the `id`, e.g. diff --git a/openstack/data_source_openstack_networking_port_v2.go b/openstack/data_source_openstack_networking_port_v2.go index 3d1e4d8ff..9eeb873a1 100644 --- a/openstack/data_source_openstack_networking_port_v2.go +++ b/openstack/data_source_openstack_networking_port_v2.go @@ -116,6 +116,13 @@ func dataSourceNetworkingPortV2() *schema.Resource { }, "all_fixed_ips": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Deprecated: "Use `fixed_ips` instead. This field will be removed in a future release.", + }, + + "fixed_ips": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ @@ -360,7 +367,8 @@ func dataSourceNetworkingPortV2Read(ctx context.Context, d *schema.ResourceData, d.Set("region", GetRegion(d, config)) d.Set("all_tags", port.Tags) d.Set("all_security_group_ids", port.SecurityGroups) - d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) + d.Set("all_fixed_ips", expandNetworkingPortAllFixedIPToStringSlice(port.FixedIPs)) + d.Set("fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) d.Set("allowed_address_pairs", flattenNetworkingPortAllowedAddressPairsV2(port.MACAddress, port.AllowedAddressPairs)) d.Set("extra_dhcp_option", flattenNetworkingPortDHCPOptsV2(port.ExtraDHCPOptsExt)) d.Set("binding", flattenNetworkingPortBindingV2(port)) diff --git a/openstack/data_source_openstack_networking_port_v2_test.go b/openstack/data_source_openstack_networking_port_v2_test.go index e79a91177..aa7d6ac3a 100644 --- a/openstack/data_source_openstack_networking_port_v2_test.go +++ b/openstack/data_source_openstack_networking_port_v2_test.go @@ -31,6 +31,12 @@ func TestAccNetworkingV2PortDataSource_basic(t *testing.T) { "openstack_networking_port_v2.port_1", "id"), resource.TestCheckResourceAttr( "data.openstack_networking_port_v2.port_3", "all_fixed_ips.#", "2"), + resource.TestCheckResourceAttr( + "data.openstack_networking_port_v2.port_3", "fixed_ips.#", "2"), + resource.TestCheckResourceAttrSet( + "data.openstack_networking_port_v2.port_3", "fixed_ips.0.subnet_id"), + resource.TestCheckResourceAttrSet( + "data.openstack_networking_port_v2.port_3", "fixed_ips.0.ip_address"), ), }, }, @@ -116,6 +122,6 @@ data "openstack_networking_port_v2" "port_2" { } data "openstack_networking_port_v2" "port_3" { - fixed_ip = openstack_networking_port_v2.port_1.all_fixed_ips[1].ip_address + fixed_ip = openstack_networking_port_v2.port_1.all_fixed_ips.1 } ` diff --git a/openstack/migrate_resource_openstack_networking_port_v2.go b/openstack/migrate_resource_openstack_networking_port_v2.go deleted file mode 100644 index c74c6ebec..000000000 --- a/openstack/migrate_resource_openstack_networking_port_v2.go +++ /dev/null @@ -1,41 +0,0 @@ -package openstack - -import ( - "context" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -) - -func resourceNetworkingPortV2V0() *schema.Resource { - return &schema.Resource{ - Schema: map[string]*schema.Schema{ - "all_fixed_ips": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - } -} - -func convertFixedIPs(list []any) []map[string]any { - newList := make([]map[string]any, len(list)) - for i, ipRaw := range list { - newList[i] = map[string]any{ - "ip_address": ipRaw.(string), - "subnet_id": "", - } - } - - return newList -} - -func upgradeNetworkingPortV2StateV0toV1(_ context.Context, rawState map[string]any, _ any) (map[string]any, error) { - if v, ok := rawState["all_fixed_ips"]; ok { - if list, ok := v.([]any); ok { - rawState["all_fixed_ips"] = convertFixedIPs(list) - } - } - - return rawState, nil -} diff --git a/openstack/migrate_resource_openstack_networking_port_v2_test.go b/openstack/migrate_resource_openstack_networking_port_v2_test.go deleted file mode 100644 index 7ce895c5e..000000000 --- a/openstack/migrate_resource_openstack_networking_port_v2_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package openstack - -import ( - "reflect" - "testing" -) - -func testResourceNetworkingV2PortStateDataV0() map[string]any { - return map[string]any{ - "name": "test", - "all_fixed_ips": []any{ - "192.168.0.10", - "192.168.0.11", - }, - } -} - -func testResourceNetworkingV2PortStateDataV1() map[string]any { - return map[string]any{ - "name": "test", - "all_fixed_ips": []map[string]any{ - { - "ip_address": "192.168.0.10", - "subnet_id": "", - }, - { - "ip_address": "192.168.0.11", - "subnet_id": "", - }, - }, - } -} - -func TestAccNetworkingV2PortStateUpgradeV0(t *testing.T) { - expected := testResourceNetworkingV2PortStateDataV1() - - actual, err := upgradeNetworkingPortV2StateV0toV1(t.Context(), testResourceNetworkingV2PortStateDataV0(), nil) - if err != nil { - t.Fatalf("error migrating state: %s", err) - } - - if !reflect.DeepEqual(expected, actual) { - t.Fatalf("\n\nexpected:\n\n%#v\n\ngot:\n\n%#v\n\n", expected, actual) - } -} diff --git a/openstack/networking_port_v2.go b/openstack/networking_port_v2.go index 6b1ada045..aeefcf945 100644 --- a/openstack/networking_port_v2.go +++ b/openstack/networking_port_v2.go @@ -205,6 +205,15 @@ func resourceNetworkingPortV2AllowedAddressPairsHash(v any) int { return hashcode.String(buf.String()) } +func expandNetworkingPortAllFixedIPToStringSlice(fixedIPs []ports.IP) []string { + s := make([]string, len(fixedIPs)) + for i, fixedIP := range fixedIPs { + s[i] = fixedIP.IPAddress + } + + return s +} + func expandNetworkingPortFixedIPToStringSlice(fixedIPs []ports.IP) []map[string]any { s := make([]map[string]any, len(fixedIPs)) for i, fixedIP := range fixedIPs { diff --git a/openstack/resource_openstack_networking_port_v2.go b/openstack/resource_openstack_networking_port_v2.go index 9ab8c8c1e..1d8b42733 100644 --- a/openstack/resource_openstack_networking_port_v2.go +++ b/openstack/resource_openstack_networking_port_v2.go @@ -35,15 +35,6 @@ func resourceNetworkingPortV2() *schema.Resource { Delete: schema.DefaultTimeout(10 * time.Minute), }, - SchemaVersion: 1, - StateUpgraders: []schema.StateUpgrader{ - { - Type: resourceNetworkingPortV2V0().CoreConfigSchema().ImpliedType(), - Upgrade: upgradeNetworkingPortV2StateV0toV1, - Version: 0, - }, - }, - Schema: map[string]*schema.Schema{ "region": { Type: schema.TypeString, @@ -195,6 +186,13 @@ func resourceNetworkingPortV2() *schema.Resource { }, "all_fixed_ips": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Deprecated: "Use `fixed_ips` instead. This field will be removed in a future release.", + }, + + "fixed_ips": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ @@ -485,7 +483,14 @@ func resourceNetworkingPortV2Read(ctx context.Context, d *schema.ResourceData, m // Set a slice of all returned Fixed IPs. // This will be in the order returned by the API, // which is usually alpha-numeric. - d.Set("all_fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) + // Deprecated: Use fixed_ips instead. all_fixed_ips will be removed in a future release. + d.Set("all_fixed_ips", expandNetworkingPortAllFixedIPToStringSlice(port.FixedIPs)) + + // Set a slice of all returned Fixed IPs with subnet IDs. + // This will be in the order returned by the API, which is usually alpha-numeric. + // Unlike `all_fixed_ips`, `fixed_ips` includes both the IP address and the subnet ID. + // `all_fixed_ips` will eventually be deprecated in favor of `fixed_ips`. + d.Set("fixed_ips", expandNetworkingPortFixedIPToStringSlice(port.FixedIPs)) // Set all security groups. // This can be different from what the user specified since diff --git a/openstack/resource_openstack_networking_port_v2_test.go b/openstack/resource_openstack_networking_port_v2_test.go index 51232f8b6..d056ee7a1 100644 --- a/openstack/resource_openstack_networking_port_v2_test.go +++ b/openstack/resource_openstack_networking_port_v2_test.go @@ -288,9 +288,17 @@ func TestAccNetworkingV2Port_fixedIPs(t *testing.T) { Config: testAccNetworkingV2PortFixedIPs, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - "openstack_networking_port_v2.port_1", "all_fixed_ips.0.ip_address", "192.168.199.23"), + "openstack_networking_port_v2.port_1", "all_fixed_ips.0", "192.168.199.23"), resource.TestCheckResourceAttr( - "openstack_networking_port_v2.port_1", "all_fixed_ips.1.ip_address", "192.168.199.24"), + "openstack_networking_port_v2.port_1", "all_fixed_ips.1", "192.168.199.24"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.0.ip_address", "192.168.199.23"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.1.ip_address", "192.168.199.24"), + resource.TestCheckResourceAttrSet( + "openstack_networking_port_v2.port_1", "fixed_ips.0.subnet_id"), + resource.TestCheckResourceAttrSet( + "openstack_networking_port_v2.port_1", "fixed_ips.1.subnet_id"), ), }, }, @@ -473,6 +481,8 @@ func TestAccNetworkingV2Port_noFixedIP(t *testing.T) { testAccCheckNetworkingV2PortExists(t.Context(), "openstack_networking_port_v2.port_1", &port), resource.TestCheckResourceAttr( "openstack_networking_port_v2.port_1", "all_fixed_ips.#", "0"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.#", "0"), ), }, { @@ -481,6 +491,8 @@ func TestAccNetworkingV2Port_noFixedIP(t *testing.T) { testAccCheckNetworkingV2PortExists(t.Context(), "openstack_networking_port_v2.port_1", &port), resource.TestCheckResourceAttr( "openstack_networking_port_v2.port_1", "all_fixed_ips.#", "1"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.#", "1"), ), }, { @@ -489,6 +501,8 @@ func TestAccNetworkingV2Port_noFixedIP(t *testing.T) { testAccCheckNetworkingV2PortExists(t.Context(), "openstack_networking_port_v2.port_1", &port), resource.TestCheckResourceAttr( "openstack_networking_port_v2.port_1", "all_fixed_ips.#", "0"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.#", "0"), ), }, { @@ -497,6 +511,8 @@ func TestAccNetworkingV2Port_noFixedIP(t *testing.T) { testAccCheckNetworkingV2PortExists(t.Context(), "openstack_networking_port_v2.port_1", &port), resource.TestCheckResourceAttr( "openstack_networking_port_v2.port_1", "all_fixed_ips.#", "2"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.#", "2"), ), }, { @@ -505,6 +521,8 @@ func TestAccNetworkingV2Port_noFixedIP(t *testing.T) { testAccCheckNetworkingV2PortExists(t.Context(), "openstack_networking_port_v2.port_1", &port), resource.TestCheckResourceAttr( "openstack_networking_port_v2.port_1", "all_fixed_ips.#", "0"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.#", "0"), ), }, { @@ -513,6 +531,8 @@ func TestAccNetworkingV2Port_noFixedIP(t *testing.T) { testAccCheckNetworkingV2PortExists(t.Context(), "openstack_networking_port_v2.port_1", &port), resource.TestCheckResourceAttr( "openstack_networking_port_v2.port_1", "all_fixed_ips.#", "0"), + resource.TestCheckResourceAttr( + "openstack_networking_port_v2.port_1", "fixed_ips.#", "0"), ), }, }, diff --git a/openstack/resource_openstack_taas_tap_mirror_v2_test.go b/openstack/resource_openstack_taas_tap_mirror_v2_test.go index 25a5fe062..af342bb62 100644 --- a/openstack/resource_openstack_taas_tap_mirror_v2_test.go +++ b/openstack/resource_openstack_taas_tap_mirror_v2_test.go @@ -166,7 +166,7 @@ resource "openstack_taas_tap_mirror_v2" "tap_mirror_1" { description = "desc" mirror_type = "erspanv1" port_id = openstack_networking_port_v2.port_1.id - remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0].ip_address + remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0] directions { in = 1000 out = 1001 @@ -200,7 +200,7 @@ resource "openstack_taas_tap_mirror_v2" "tap_mirror_1" { description = "updated desc" mirror_type = "erspanv1" port_id = openstack_networking_port_v2.port_1.id - remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0].ip_address + remote_ip = openstack_networking_port_v2.port_1.all_fixed_ips[0] directions { in = 1000 out = 1001