From 4d85f6f7a4e04e9995091cfd543725f6ca979327 Mon Sep 17 00:00:00 2001
From: Matthew Booth
Date: Tue, 26 Mar 2024 10:16:22 +0000
Subject: [PATCH] SubnetFilter to SubnetParam
---
api/v1alpha5/conversion.go | 55 ++-
api/v1alpha5/zz_generated.conversion.go | 43 +-
api/v1alpha6/conversion_test.go | 68 +--
api/v1alpha6/openstackcluster_conversion.go | 19 +-
api/v1alpha6/openstackmachine_conversion.go | 8 +-
api/v1alpha6/types_conversion.go | 99 +++-
api/v1alpha6/zz_generated.conversion.go | 43 +-
api/v1alpha7/openstackcluster_conversion.go | 17 +-
api/v1alpha7/types_conversion.go | 76 ++-
api/v1alpha7/zz_generated.conversion.go | 23 +-
api/v1beta1/openstackcluster_types.go | 2 +-
api/v1beta1/types.go | 38 +-
api/v1beta1/zz_generated.deepcopy.go | 29 +-
...re.cluster.x-k8s.io_openstackclusters.yaml | 449 +++++++++--------
...er.x-k8s.io_openstackclustertemplates.yaml | 451 ++++++++++--------
...re.cluster.x-k8s.io_openstackmachines.yaml | 149 +++---
...er.x-k8s.io_openstackmachinetemplates.yaml | 150 +++---
controllers/openstackcluster_controller.go | 4 +-
.../openstackcluster_controller_test.go | 24 +-
docs/book/src/api/v1beta1/api.md | 74 ++-
pkg/cloud/services/networking/network.go | 49 +-
pkg/cloud/services/networking/port.go | 4 +-
pkg/cloud/services/networking/port_test.go | 24 +-
pkg/cloud/services/networking/router.go | 10 +-
pkg/utils/filterconvert/convert.go | 1 -
.../e2e/suites/apivalidations/filters_test.go | 56 ++-
test/helpers/fuzzerfuncs.go | 8 +-
27 files changed, 1231 insertions(+), 742 deletions(-)
diff --git a/api/v1alpha5/conversion.go b/api/v1alpha5/conversion.go
index b8190e088a..19397b6956 100644
--- a/api/v1alpha5/conversion.go
+++ b/api/v1alpha5/conversion.go
@@ -217,7 +217,7 @@ func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha5_OpenStackClusterSpec(in *i
if in.Subnets != nil {
if len(in.Subnets) >= 1 {
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetFilter(&in.Subnets[0], &out.Subnet, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetFilter(&in.Subnets[0], &out.Subnet, s); err != nil {
return err
}
}
@@ -254,11 +254,11 @@ func Convert_v1alpha5_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O
emptySubnet := SubnetFilter{}
if in.Subnet != emptySubnet {
- subnet := infrav1.SubnetFilter{}
- if err := Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetFilter(&in.Subnet, &subnet, s); err != nil {
+ subnet := infrav1.SubnetParam{}
+ if err := Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetParam(&in.Subnet, &subnet, s); err != nil {
return err
}
- out.Subnets = []infrav1.SubnetFilter{subnet}
+ out.Subnets = []infrav1.SubnetParam{subnet}
}
if len(in.NodeCIDR) > 0 {
@@ -547,25 +547,56 @@ func Convert_v1beta1_SecurityGroupFilter_To_v1alpha5_SecurityGroupParam(in *infr
return nil
}
-func Convert_v1alpha5_SubnetParam_To_v1beta1_SubnetFilter(in *SubnetParam, out *infrav1.SubnetFilter, s conversion.Scope) error {
- if err := Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetFilter(&in.Filter, out, s); err != nil {
+func Convert_v1alpha5_SubnetParam_To_v1beta1_SubnetParam(in *SubnetParam, out *infrav1.SubnetParam, s conversion.Scope) error {
+ if in.UUID != "" {
+ out.ID = &in.UUID
+ return nil
+ }
+ outFilter := &infrav1.SubnetFilter{}
+ if err := Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetFilter(&in.Filter, outFilter, s); err != nil {
return err
}
- if in.UUID != "" {
- out.ID = in.UUID
+ if !outFilter.IsZero() {
+ out.Filter = outFilter
}
return nil
}
-func Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetParam(in *infrav1.SubnetFilter, out *SubnetParam, s conversion.Scope) error {
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetFilter(in, &out.Filter, s); err != nil {
- return err
+func Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetParam(in *infrav1.SubnetParam, out *SubnetParam, s conversion.Scope) error {
+ if in.ID != nil {
+ out.UUID = *in.ID
+ return nil
+ }
+
+ if in.Filter != nil {
+ if err := Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetFilter(in.Filter, &out.Filter, s); err != nil {
+ return err
+ }
}
- out.UUID = in.ID
return nil
}
+func Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetParam(in *SubnetFilter, out *infrav1.SubnetParam, s conversion.Scope) error {
+ if in.ID != "" {
+ out.ID = &in.ID
+ return nil
+ }
+ out.Filter = &infrav1.SubnetFilter{}
+ return Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetFilter(in, out.Filter, s)
+}
+
+func Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetFilter(in *infrav1.SubnetParam, out *SubnetFilter, s conversion.Scope) error {
+ if in.ID != nil {
+ out.ID = *in.ID
+ return nil
+ }
+ if in.Filter != nil {
+ return Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetFilter(in.Filter, out, s)
+ }
+ return nil
+}
+
func Convert_Map_string_To_Interface_To_v1beta1_BindingProfile(in map[string]string, out *infrav1.BindingProfile, _ conversion.Scope) error {
for k, v := range in {
if k == "capabilities" {
diff --git a/api/v1alpha5/zz_generated.conversion.go b/api/v1alpha5/zz_generated.conversion.go
index e8376912a3..8d24ce309a 100644
--- a/api/v1alpha5/zz_generated.conversion.go
+++ b/api/v1alpha5/zz_generated.conversion.go
@@ -317,8 +317,13 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
- if err := s.AddConversionFunc((*SubnetParam)(nil), (*v1beta1.SubnetFilter)(nil), func(a, b interface{}, scope conversion.Scope) error {
- return Convert_v1alpha5_SubnetParam_To_v1beta1_SubnetFilter(a.(*SubnetParam), b.(*v1beta1.SubnetFilter), scope)
+ if err := s.AddConversionFunc((*SubnetFilter)(nil), (*v1beta1.SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetParam(a.(*SubnetFilter), b.(*v1beta1.SubnetParam), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddConversionFunc((*SubnetParam)(nil), (*v1beta1.SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha5_SubnetParam_To_v1beta1_SubnetParam(a.(*SubnetParam), b.(*v1beta1.SubnetParam), scope)
}); err != nil {
return err
}
@@ -417,8 +422,13 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
- if err := s.AddConversionFunc((*v1beta1.SubnetFilter)(nil), (*SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
- return Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetParam(a.(*v1beta1.SubnetFilter), b.(*SubnetParam), scope)
+ if err := s.AddConversionFunc((*v1beta1.SubnetParam)(nil), (*SubnetFilter)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetFilter(a.(*v1beta1.SubnetParam), b.(*SubnetFilter), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddConversionFunc((*v1beta1.SubnetParam)(nil), (*SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetParam(a.(*v1beta1.SubnetParam), b.(*SubnetParam), scope)
}); err != nil {
return err
}
@@ -496,7 +506,7 @@ func autoConvert_v1beta1_Bastion_To_v1alpha5_Bastion(in *v1beta1.Bastion, out *B
func autoConvert_v1alpha5_ExternalRouterIPParam_To_v1beta1_ExternalRouterIPParam(in *ExternalRouterIPParam, out *v1beta1.ExternalRouterIPParam, s conversion.Scope) error {
out.FixedIP = in.FixedIP
- if err := Convert_v1alpha5_SubnetParam_To_v1beta1_SubnetFilter(&in.Subnet, &out.Subnet, s); err != nil {
+ if err := Convert_v1alpha5_SubnetParam_To_v1beta1_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
return err
}
return nil
@@ -509,7 +519,7 @@ func Convert_v1alpha5_ExternalRouterIPParam_To_v1beta1_ExternalRouterIPParam(in
func autoConvert_v1beta1_ExternalRouterIPParam_To_v1alpha5_ExternalRouterIPParam(in *v1beta1.ExternalRouterIPParam, out *ExternalRouterIPParam, s conversion.Scope) error {
out.FixedIP = in.FixedIP
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
return err
}
return nil
@@ -523,8 +533,8 @@ func Convert_v1beta1_ExternalRouterIPParam_To_v1alpha5_ExternalRouterIPParam(in
func autoConvert_v1alpha5_FixedIP_To_v1beta1_FixedIP(in *FixedIP, out *v1beta1.FixedIP, s conversion.Scope) error {
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
- *out = new(v1beta1.SubnetFilter)
- if err := Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetFilter(*in, *out, s); err != nil {
+ *out = new(v1beta1.SubnetParam)
+ if err := Convert_v1alpha5_SubnetFilter_To_v1beta1_SubnetParam(*in, *out, s); err != nil {
return err
}
} else {
@@ -545,7 +555,7 @@ func autoConvert_v1beta1_FixedIP_To_v1alpha5_FixedIP(in *v1beta1.FixedIP, out *F
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
*out = new(SubnetFilter)
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha5_SubnetFilter(*in, *out, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha5_SubnetFilter(*in, *out, s); err != nil {
return err
}
} else {
@@ -1567,7 +1577,7 @@ func autoConvert_v1alpha5_SubnetFilter_To_v1beta1_SubnetFilter(in *SubnetFilter,
out.CIDR = in.CIDR
out.IPv6AddressMode = in.IPv6AddressMode
out.IPv6RAMode = in.IPv6RAMode
- out.ID = in.ID
+ // WARNING: in.ID requires manual conversion: does not exist in peer-type
// WARNING: in.Tags requires manual conversion: does not exist in peer-type
// WARNING: in.TagsAny requires manual conversion: does not exist in peer-type
// WARNING: in.NotTags requires manual conversion: does not exist in peer-type
@@ -1584,7 +1594,18 @@ func autoConvert_v1beta1_SubnetFilter_To_v1alpha5_SubnetFilter(in *v1beta1.Subne
out.CIDR = in.CIDR
out.IPv6AddressMode = in.IPv6AddressMode
out.IPv6RAMode = in.IPv6RAMode
- out.ID = in.ID
// WARNING: in.FilterByNeutronTags requires manual conversion: does not exist in peer-type
return nil
}
+
+func autoConvert_v1alpha5_SubnetParam_To_v1beta1_SubnetParam(in *SubnetParam, out *v1beta1.SubnetParam, s conversion.Scope) error {
+ // WARNING: in.UUID requires manual conversion: does not exist in peer-type
+ // WARNING: in.Filter requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.SubnetFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.SubnetFilter)
+ return nil
+}
+
+func autoConvert_v1beta1_SubnetParam_To_v1alpha5_SubnetParam(in *v1beta1.SubnetParam, out *SubnetParam, s conversion.Scope) error {
+ // WARNING: in.ID requires manual conversion: does not exist in peer-type
+ // WARNING: in.Filter requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.SubnetFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.SubnetFilter)
+ return nil
+}
diff --git a/api/v1alpha6/conversion_test.go b/api/v1alpha6/conversion_test.go
index 0c1352767d..1456680359 100644
--- a/api/v1alpha6/conversion_test.go
+++ b/api/v1alpha6/conversion_test.go
@@ -286,8 +286,8 @@ func TestNetworksToPorts(t *testing.T) {
},
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- ID: subnetuuid,
+ Subnet: &infrav1.SubnetParam{
+ ID: pointer.String(subnetuuid),
},
},
},
@@ -330,20 +330,22 @@ func TestNetworksToPorts(t *testing.T) {
},
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- Name: "subnet-name",
- Description: "subnet-description",
- ProjectID: "project-id",
- IPVersion: 6,
- GatewayIP: "x.x.x.x",
- CIDR: "y.y.y.y",
- IPv6AddressMode: "address-mode",
- IPv6RAMode: "ra-mode",
- FilterByNeutronTags: infrav1.FilterByNeutronTags{
- Tags: []infrav1.NeutronTag{"tags"},
- TagsAny: []infrav1.NeutronTag{"tags-any"},
- NotTags: []infrav1.NeutronTag{"not-tags"},
- NotTagsAny: []infrav1.NeutronTag{"not-tags-any"},
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{
+ Name: "subnet-name",
+ Description: "subnet-description",
+ ProjectID: "project-id",
+ IPVersion: 6,
+ GatewayIP: "x.x.x.x",
+ CIDR: "y.y.y.y",
+ IPv6AddressMode: "address-mode",
+ IPv6RAMode: "ra-mode",
+ FilterByNeutronTags: infrav1.FilterByNeutronTags{
+ Tags: []infrav1.NeutronTag{"tags"},
+ TagsAny: []infrav1.NeutronTag{"tags-any"},
+ NotTags: []infrav1.NeutronTag{"not-tags"},
+ NotTagsAny: []infrav1.NeutronTag{"not-tags-any"},
+ },
},
},
},
@@ -390,8 +392,8 @@ func TestNetworksToPorts(t *testing.T) {
},
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- ID: subnetuuid,
+ Subnet: &infrav1.SubnetParam{
+ ID: pointer.String(subnetuuid),
},
},
},
@@ -402,20 +404,22 @@ func TestNetworksToPorts(t *testing.T) {
},
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- Name: "subnet-name",
- Description: "subnet-description",
- ProjectID: "project-id",
- IPVersion: 6,
- GatewayIP: "x.x.x.x",
- CIDR: "y.y.y.y",
- IPv6AddressMode: "address-mode",
- IPv6RAMode: "ra-mode",
- FilterByNeutronTags: infrav1.FilterByNeutronTags{
- Tags: []infrav1.NeutronTag{"tags"},
- TagsAny: []infrav1.NeutronTag{"tags-any"},
- NotTags: []infrav1.NeutronTag{"not-tags"},
- NotTagsAny: []infrav1.NeutronTag{"not-tags-any"},
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{
+ Name: "subnet-name",
+ Description: "subnet-description",
+ ProjectID: "project-id",
+ IPVersion: 6,
+ GatewayIP: "x.x.x.x",
+ CIDR: "y.y.y.y",
+ IPv6AddressMode: "address-mode",
+ IPv6RAMode: "ra-mode",
+ FilterByNeutronTags: infrav1.FilterByNeutronTags{
+ Tags: []infrav1.NeutronTag{"tags"},
+ TagsAny: []infrav1.NeutronTag{"tags-any"},
+ NotTags: []infrav1.NeutronTag{"not-tags"},
+ NotTagsAny: []infrav1.NeutronTag{"not-tags-any"},
+ },
},
},
},
diff --git a/api/v1alpha6/openstackcluster_conversion.go b/api/v1alpha6/openstackcluster_conversion.go
index 68242edd8c..66fd5896bb 100644
--- a/api/v1alpha6/openstackcluster_conversion.go
+++ b/api/v1alpha6/openstackcluster_conversion.go
@@ -152,7 +152,7 @@ func restorev1alpha6ClusterSpec(previous *OpenStackClusterSpec, dst *OpenStackCl
if len(dst.ExternalRouterIPs) == len(previous.ExternalRouterIPs) {
for i := range dst.ExternalRouterIPs {
- restorev1alpha6SubnetFilter(&previous.ExternalRouterIPs[i].Subnet.Filter, &dst.ExternalRouterIPs[i].Subnet.Filter)
+ restorev1alpha6SubnetParam(&previous.ExternalRouterIPs[i].Subnet, &dst.ExternalRouterIPs[i].Subnet)
}
}
@@ -179,10 +179,19 @@ func restorev1beta1ClusterSpec(previous *infrav1.OpenStackClusterSpec, dst *infr
dst.NetworkMTU = previous.NetworkMTU
dst.DisableExternalNetwork = previous.DisableExternalNetwork
+ if len(previous.Subnets) > 0 && len(dst.Subnets) > 0 {
+ restorev1beta1SubnetParam(&previous.Subnets[0], &dst.Subnets[0])
+ }
if len(previous.Subnets) > 1 {
dst.Subnets = append(dst.Subnets, previous.Subnets[1:]...)
}
+ if len(previous.ExternalRouterIPs) == len(dst.ExternalRouterIPs) {
+ for i := range dst.ExternalRouterIPs {
+ restorev1beta1SubnetParam(&previous.ExternalRouterIPs[i].Subnet, &dst.ExternalRouterIPs[i].Subnet)
+ }
+ }
+
dst.ManagedSubnets = previous.ManagedSubnets
if previous.ManagedSecurityGroups != nil {
@@ -232,11 +241,11 @@ func Convert_v1alpha6_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O
emptySubnet := SubnetFilter{}
if in.Subnet != emptySubnet {
- subnet := infrav1.SubnetFilter{}
- if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(&in.Subnet, &subnet, s); err != nil {
+ subnet := infrav1.SubnetParam{}
+ if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetParam(&in.Subnet, &subnet, s); err != nil {
return err
}
- out.Subnets = []infrav1.SubnetFilter{subnet}
+ out.Subnets = []infrav1.SubnetParam{subnet}
}
// DNSNameservers without NodeCIDR doesn't make sense, so we drop that.
@@ -295,7 +304,7 @@ func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha6_OpenStackClusterSpec(in *i
}
if len(in.Subnets) >= 1 {
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(&in.Subnets[0], &out.Subnet, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetFilter(&in.Subnets[0], &out.Subnet, s); err != nil {
return err
}
}
diff --git a/api/v1alpha6/openstackmachine_conversion.go b/api/v1alpha6/openstackmachine_conversion.go
index 9ab01741ea..d13eb5c124 100644
--- a/api/v1alpha6/openstackmachine_conversion.go
+++ b/api/v1alpha6/openstackmachine_conversion.go
@@ -223,18 +223,18 @@ func convertNetworksToPorts(networks []NetworkParam, s apiconversion.Scope) ([]i
ports = append(ports, infrav1.PortOpts{
Network: networkFilter,
FixedIPs: []infrav1.FixedIP{
- {Subnet: &infrav1.SubnetFilter{ID: subnet.UUID}},
+ {Subnet: &infrav1.SubnetParam{ID: &subnet.UUID}},
},
})
} else {
- subnetFilter := &infrav1.SubnetFilter{}
- if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(&subnet.Filter, subnetFilter, s); err != nil {
+ subnetParam := &infrav1.SubnetParam{}
+ if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetParam(&subnet.Filter, subnetParam, s); err != nil {
return nil, err
}
ports = append(ports, infrav1.PortOpts{
Network: networkFilter,
FixedIPs: []infrav1.FixedIP{
- {Subnet: subnetFilter},
+ {Subnet: subnetParam},
},
})
}
diff --git a/api/v1alpha6/types_conversion.go b/api/v1alpha6/types_conversion.go
index 80cefb86fc..1b2a642f34 100644
--- a/api/v1alpha6/types_conversion.go
+++ b/api/v1alpha6/types_conversion.go
@@ -24,6 +24,7 @@ import (
"k8s.io/utils/pointer"
infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
+ optional "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/optional"
)
const trueString = "true"
@@ -164,29 +165,81 @@ func Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkFilter(in *infrav1.NetworkP
/* SubnetParam, SubnetFilter */
func restorev1alpha6SubnetFilter(previous *SubnetFilter, dst *SubnetFilter) {
+ if previous == nil || dst == nil {
+ return
+ }
+
// The edge cases with multiple commas are too tricky in this direction,
// so we just restore the whole thing.
dst.Tags = previous.Tags
dst.TagsAny = previous.TagsAny
dst.NotTags = previous.NotTags
dst.NotTagsAny = previous.NotTagsAny
+
+ // We didn't convert other fields if ID was set
+ if previous.ID != "" {
+ dst.Name = previous.Name
+ dst.Description = previous.Description
+ dst.ProjectID = previous.ProjectID
+ dst.IPVersion = previous.IPVersion
+ dst.GatewayIP = previous.GatewayIP
+ dst.CIDR = previous.CIDR
+ dst.IPv6AddressMode = previous.IPv6AddressMode
+ dst.IPv6RAMode = previous.IPv6RAMode
+ }
}
-func Convert_v1alpha6_SubnetParam_To_v1beta1_SubnetFilter(in *SubnetParam, out *infrav1.SubnetFilter, s apiconversion.Scope) error {
- if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(&in.Filter, out, s); err != nil {
- return err
+func restorev1alpha6SubnetParam(previous *SubnetParam, dst *SubnetParam) {
+ if previous == nil || dst == nil {
+ return
+ }
+
+ if previous.UUID != "" {
+ dst.Filter = previous.Filter
+ } else {
+ restorev1alpha6SubnetFilter(&previous.Filter, &dst.Filter)
}
+}
+
+func restorev1beta1SubnetParam(previous *infrav1.SubnetParam, dst *infrav1.SubnetParam) {
+ if previous == nil || dst == nil {
+ return
+ }
+
+ optional.RestoreString(&previous.ID, &dst.ID)
+
+ if dst.Filter != nil {
+ dst.Filter.FilterByNeutronTags = previous.Filter.FilterByNeutronTags
+ }
+}
+
+func Convert_v1alpha6_SubnetParam_To_v1beta1_SubnetParam(in *SubnetParam, out *infrav1.SubnetParam, s apiconversion.Scope) error {
if in.UUID != "" {
- out.ID = in.UUID
+ out.ID = &in.UUID
+ return nil
+ }
+
+ outFilter := &infrav1.SubnetFilter{}
+ if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(&in.Filter, outFilter, s); err != nil {
+ return err
+ }
+ if !outFilter.IsZero() {
+ out.Filter = outFilter
}
return nil
}
-func Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetParam(in *infrav1.SubnetFilter, out *SubnetParam, s apiconversion.Scope) error {
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(in, &out.Filter, s); err != nil {
- return err
+func Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetParam(in *infrav1.SubnetParam, out *SubnetParam, s apiconversion.Scope) error {
+ if in.ID != nil {
+ out.UUID = *in.ID
+ return nil
+ }
+
+ if in.Filter != nil {
+ if err := Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(in.Filter, &out.Filter, s); err != nil {
+ return err
+ }
}
- out.UUID = in.ID
return nil
}
@@ -207,6 +260,36 @@ func Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(in *infrav1.SubnetFil
return nil
}
+func Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetParam(in *SubnetFilter, out *infrav1.SubnetParam, s apiconversion.Scope) error {
+ if in.ID != "" {
+ out.ID = &in.ID
+ return nil
+ }
+
+ outFilter := &infrav1.SubnetFilter{}
+ if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(in, outFilter, s); err != nil {
+ return err
+ }
+ if !outFilter.IsZero() {
+ out.Filter = outFilter
+ }
+ return nil
+}
+
+func Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetFilter(in *infrav1.SubnetParam, out *SubnetFilter, s apiconversion.Scope) error {
+ if in.ID != nil {
+ out.ID = *in.ID
+ return nil
+ }
+
+ if in.Filter != nil {
+ if err := Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(in.Filter, out, s); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
/* PortOpts, BindingProfile */
func restorev1alpha6Port(previous *PortOpts, dst *PortOpts) {
diff --git a/api/v1alpha6/zz_generated.conversion.go b/api/v1alpha6/zz_generated.conversion.go
index 34023deb82..9862d40792 100644
--- a/api/v1alpha6/zz_generated.conversion.go
+++ b/api/v1alpha6/zz_generated.conversion.go
@@ -336,8 +336,13 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
- if err := s.AddConversionFunc((*SubnetParam)(nil), (*v1beta1.SubnetFilter)(nil), func(a, b interface{}, scope conversion.Scope) error {
- return Convert_v1alpha6_SubnetParam_To_v1beta1_SubnetFilter(a.(*SubnetParam), b.(*v1beta1.SubnetFilter), scope)
+ if err := s.AddConversionFunc((*SubnetFilter)(nil), (*v1beta1.SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetParam(a.(*SubnetFilter), b.(*v1beta1.SubnetParam), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddConversionFunc((*SubnetParam)(nil), (*v1beta1.SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha6_SubnetParam_To_v1beta1_SubnetParam(a.(*SubnetParam), b.(*v1beta1.SubnetParam), scope)
}); err != nil {
return err
}
@@ -431,8 +436,13 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
- if err := s.AddConversionFunc((*v1beta1.SubnetFilter)(nil), (*SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
- return Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetParam(a.(*v1beta1.SubnetFilter), b.(*SubnetParam), scope)
+ if err := s.AddConversionFunc((*v1beta1.SubnetParam)(nil), (*SubnetFilter)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetFilter(a.(*v1beta1.SubnetParam), b.(*SubnetFilter), scope)
+ }); err != nil {
+ return err
+ }
+ if err := s.AddConversionFunc((*v1beta1.SubnetParam)(nil), (*SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetParam(a.(*v1beta1.SubnetParam), b.(*SubnetParam), scope)
}); err != nil {
return err
}
@@ -520,7 +530,7 @@ func autoConvert_v1beta1_Bastion_To_v1alpha6_Bastion(in *v1beta1.Bastion, out *B
func autoConvert_v1alpha6_ExternalRouterIPParam_To_v1beta1_ExternalRouterIPParam(in *ExternalRouterIPParam, out *v1beta1.ExternalRouterIPParam, s conversion.Scope) error {
out.FixedIP = in.FixedIP
- if err := Convert_v1alpha6_SubnetParam_To_v1beta1_SubnetFilter(&in.Subnet, &out.Subnet, s); err != nil {
+ if err := Convert_v1alpha6_SubnetParam_To_v1beta1_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
return err
}
return nil
@@ -533,7 +543,7 @@ func Convert_v1alpha6_ExternalRouterIPParam_To_v1beta1_ExternalRouterIPParam(in
func autoConvert_v1beta1_ExternalRouterIPParam_To_v1alpha6_ExternalRouterIPParam(in *v1beta1.ExternalRouterIPParam, out *ExternalRouterIPParam, s conversion.Scope) error {
out.FixedIP = in.FixedIP
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
return err
}
return nil
@@ -547,8 +557,8 @@ func Convert_v1beta1_ExternalRouterIPParam_To_v1alpha6_ExternalRouterIPParam(in
func autoConvert_v1alpha6_FixedIP_To_v1beta1_FixedIP(in *FixedIP, out *v1beta1.FixedIP, s conversion.Scope) error {
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
- *out = new(v1beta1.SubnetFilter)
- if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(*in, *out, s); err != nil {
+ *out = new(v1beta1.SubnetParam)
+ if err := Convert_v1alpha6_SubnetFilter_To_v1beta1_SubnetParam(*in, *out, s); err != nil {
return err
}
} else {
@@ -569,7 +579,7 @@ func autoConvert_v1beta1_FixedIP_To_v1alpha6_FixedIP(in *v1beta1.FixedIP, out *F
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
*out = new(SubnetFilter)
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(*in, *out, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha6_SubnetFilter(*in, *out, s); err != nil {
return err
}
} else {
@@ -1603,7 +1613,7 @@ func autoConvert_v1alpha6_SubnetFilter_To_v1beta1_SubnetFilter(in *SubnetFilter,
out.CIDR = in.CIDR
out.IPv6AddressMode = in.IPv6AddressMode
out.IPv6RAMode = in.IPv6RAMode
- out.ID = in.ID
+ // WARNING: in.ID requires manual conversion: does not exist in peer-type
// WARNING: in.Tags requires manual conversion: does not exist in peer-type
// WARNING: in.TagsAny requires manual conversion: does not exist in peer-type
// WARNING: in.NotTags requires manual conversion: does not exist in peer-type
@@ -1620,11 +1630,22 @@ func autoConvert_v1beta1_SubnetFilter_To_v1alpha6_SubnetFilter(in *v1beta1.Subne
out.CIDR = in.CIDR
out.IPv6AddressMode = in.IPv6AddressMode
out.IPv6RAMode = in.IPv6RAMode
- out.ID = in.ID
// WARNING: in.FilterByNeutronTags requires manual conversion: does not exist in peer-type
return nil
}
+func autoConvert_v1alpha6_SubnetParam_To_v1beta1_SubnetParam(in *SubnetParam, out *v1beta1.SubnetParam, s conversion.Scope) error {
+ // WARNING: in.UUID requires manual conversion: does not exist in peer-type
+ // WARNING: in.Filter requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.SubnetFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.SubnetFilter)
+ return nil
+}
+
+func autoConvert_v1beta1_SubnetParam_To_v1alpha6_SubnetParam(in *v1beta1.SubnetParam, out *SubnetParam, s conversion.Scope) error {
+ // WARNING: in.ID requires manual conversion: does not exist in peer-type
+ // WARNING: in.Filter requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.SubnetFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.SubnetFilter)
+ return nil
+}
+
func autoConvert_v1alpha6_ValueSpec_To_v1beta1_ValueSpec(in *ValueSpec, out *v1beta1.ValueSpec, s conversion.Scope) error {
out.Name = in.Name
out.Key = in.Key
diff --git a/api/v1alpha7/openstackcluster_conversion.go b/api/v1alpha7/openstackcluster_conversion.go
index 7ff49ecdcf..75e92032d1 100644
--- a/api/v1alpha7/openstackcluster_conversion.go
+++ b/api/v1alpha7/openstackcluster_conversion.go
@@ -191,10 +191,19 @@ func restorev1beta1ClusterSpec(previous *infrav1.OpenStackClusterSpec, dst *infr
restorev1beta1NetworkParam(previous.Network, dst.Network)
+ if len(previous.Subnets) > 0 && len(dst.Subnets) > 0 {
+ restorev1beta1SubnetParam(&previous.Subnets[0], &dst.Subnets[0])
+ }
if len(previous.Subnets) > 1 {
dst.Subnets = append(dst.Subnets, previous.Subnets[1:]...)
}
+ if len(previous.ExternalRouterIPs) == len(dst.ExternalRouterIPs) {
+ for i := range dst.ExternalRouterIPs {
+ restorev1beta1SubnetParam(&previous.ExternalRouterIPs[i].Subnet, &dst.ExternalRouterIPs[i].Subnet)
+ }
+ }
+
dst.ManagedSubnets = previous.ManagedSubnets
if previous.ManagedSecurityGroups != nil {
@@ -244,11 +253,11 @@ func Convert_v1alpha7_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O
emptySubnet := SubnetFilter{}
if in.Subnet != emptySubnet {
- subnet := infrav1.SubnetFilter{}
- if err := Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(&in.Subnet, &subnet, s); err != nil {
+ subnet := infrav1.SubnetParam{}
+ if err := Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetParam(&in.Subnet, &subnet, s); err != nil {
return err
}
- out.Subnets = []infrav1.SubnetFilter{subnet}
+ out.Subnets = []infrav1.SubnetParam{subnet}
}
// DNSNameservers without NodeCIDR doesn't make sense, so we drop that.
@@ -307,7 +316,7 @@ func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha7_OpenStackClusterSpec(in *i
}
if len(in.Subnets) >= 1 {
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(&in.Subnets[0], &out.Subnet, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha7_SubnetFilter(&in.Subnets[0], &out.Subnet, s); err != nil {
return err
}
}
diff --git a/api/v1alpha7/types_conversion.go b/api/v1alpha7/types_conversion.go
index 1139ebe05a..a63cd212ed 100644
--- a/api/v1alpha7/types_conversion.go
+++ b/api/v1alpha7/types_conversion.go
@@ -126,27 +126,74 @@ func Convert_v1beta1_NetworkParam_To_v1alpha7_NetworkFilter(in *infrav1.NetworkP
/* SubnetFilter */
func restorev1alpha7SubnetFilter(previous *SubnetFilter, dst *SubnetFilter) {
+ if previous == nil || dst == nil {
+ return
+ }
+
// The edge cases with multiple commas are too tricky in this direction,
// so we just restore the whole thing.
dst.Tags = previous.Tags
dst.TagsAny = previous.TagsAny
dst.NotTags = previous.NotTags
dst.NotTagsAny = previous.NotTagsAny
+
+ // If ID was set we will have lost all other fields in up-conversion
+ if previous.ID != "" {
+ dst.Name = previous.Name
+ dst.Description = previous.Description
+ dst.ProjectID = previous.ProjectID
+ dst.IPVersion = previous.IPVersion
+ dst.GatewayIP = previous.GatewayIP
+ dst.CIDR = previous.CIDR
+ dst.IPv6AddressMode = previous.IPv6AddressMode
+ dst.IPv6RAMode = previous.IPv6RAMode
+ }
}
-func Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(in *SubnetFilter, out *infrav1.SubnetFilter, s apiconversion.Scope) error {
- if err := autoConvert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(in, out, s); err != nil {
+func restorev1beta1SubnetParam(previous *infrav1.SubnetParam, dst *infrav1.SubnetParam) {
+ if previous == nil || dst == nil {
+ return
+ }
+
+ optional.RestoreString(&previous.ID, &dst.ID)
+
+ if dst.Filter != nil {
+ dst.Filter.FilterByNeutronTags = previous.Filter.FilterByNeutronTags
+ }
+}
+
+func Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetParam(in *SubnetFilter, out *infrav1.SubnetParam, s apiconversion.Scope) error {
+ if in.ID != "" {
+ out.ID = &in.ID
+ return nil
+ }
+
+ filter := &infrav1.SubnetFilter{}
+ if err := autoConvert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(in, filter, s); err != nil {
return err
}
- infrav1.ConvertAllTagsTo(in.Tags, in.TagsAny, in.NotTags, in.NotTagsAny, &out.FilterByNeutronTags)
+ infrav1.ConvertAllTagsTo(in.Tags, in.TagsAny, in.NotTags, in.NotTagsAny, &filter.FilterByNeutronTags)
+
+ if !filter.IsZero() {
+ out.Filter = filter
+ }
return nil
}
-func Convert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(in *infrav1.SubnetFilter, out *SubnetFilter, s apiconversion.Scope) error {
- if err := autoConvert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(in, out, s); err != nil {
+func Convert_v1beta1_SubnetParam_To_v1alpha7_SubnetFilter(in *infrav1.SubnetParam, out *SubnetFilter, s apiconversion.Scope) error {
+ if in.ID != nil {
+ out.ID = *in.ID
+ return nil
+ }
+
+ if in.Filter == nil {
+ return nil
+ }
+
+ if err := autoConvert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(in.Filter, out, s); err != nil {
return err
}
- infrav1.ConvertAllTagsFrom(&in.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny)
+ infrav1.ConvertAllTagsFrom(&in.Filter.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny)
return nil
}
@@ -214,9 +261,8 @@ func restorev1beta1Port(previous *infrav1.PortOpts, dst *infrav1.PortOpts) {
prevFixedIP := &previous.FixedIPs[j]
dstFixedIP := &dst.FixedIPs[j]
- if dstFixedIP.IPAddress == nil || *dstFixedIP.IPAddress == "" {
- dstFixedIP.IPAddress = prevFixedIP.IPAddress
- }
+ optional.RestoreString(&prevFixedIP.IPAddress, &dstFixedIP.IPAddress)
+ restorev1beta1SubnetParam(prevFixedIP.Subnet, dstFixedIP.Subnet)
}
}
@@ -225,9 +271,7 @@ func restorev1beta1Port(previous *infrav1.PortOpts, dst *infrav1.PortOpts) {
prevAAP := &previous.AllowedAddressPairs[j]
dstAAP := &dst.AllowedAddressPairs[j]
- if dstAAP.MACAddress == nil || *dstAAP.MACAddress == "" {
- dstAAP.MACAddress = prevAAP.MACAddress
- }
+ optional.RestoreString(&prevAAP.MACAddress, &dstAAP.MACAddress)
}
}
@@ -395,6 +439,14 @@ func Convert_v1beta1_OpenStackIdentityReference_To_v1alpha7_OpenStackIdentityRef
// conversion-gen registers these functions so we must provider stubs, but
// nothing should ever call them
+func Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(_ *SubnetFilter, _ *infrav1.SubnetFilter, _ apiconversion.Scope) error {
+ return errors.New("Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter should not be called")
+}
+
+func Convert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(_ *infrav1.SubnetFilter, _ *SubnetFilter, _ apiconversion.Scope) error {
+ return errors.New("Convert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter should not be called")
+}
+
func Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(_ *NetworkFilter, _ *infrav1.NetworkFilter, _ apiconversion.Scope) error {
return errors.New("Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter should not be called")
}
diff --git a/api/v1alpha7/zz_generated.conversion.go b/api/v1alpha7/zz_generated.conversion.go
index 8b070e14bf..e2ae6041c7 100644
--- a/api/v1alpha7/zz_generated.conversion.go
+++ b/api/v1alpha7/zz_generated.conversion.go
@@ -381,6 +381,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
+ if err := s.AddConversionFunc((*SubnetFilter)(nil), (*v1beta1.SubnetParam)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetParam(a.(*SubnetFilter), b.(*v1beta1.SubnetParam), scope)
+ }); err != nil {
+ return err
+ }
if err := s.AddConversionFunc((*v1beta1.BastionStatus)(nil), (*BastionStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1beta1_BastionStatus_To_v1alpha7_BastionStatus(a.(*v1beta1.BastionStatus), b.(*BastionStatus), scope)
}); err != nil {
@@ -451,6 +456,11 @@ func RegisterConversions(s *runtime.Scheme) error {
}); err != nil {
return err
}
+ if err := s.AddConversionFunc((*v1beta1.SubnetParam)(nil), (*SubnetFilter)(nil), func(a, b interface{}, scope conversion.Scope) error {
+ return Convert_v1beta1_SubnetParam_To_v1alpha7_SubnetFilter(a.(*v1beta1.SubnetParam), b.(*SubnetFilter), scope)
+ }); err != nil {
+ return err
+ }
return nil
}
@@ -664,7 +674,7 @@ func Convert_v1beta1_BlockDeviceVolume_To_v1alpha7_BlockDeviceVolume(in *v1beta1
func autoConvert_v1alpha7_ExternalRouterIPParam_To_v1beta1_ExternalRouterIPParam(in *ExternalRouterIPParam, out *v1beta1.ExternalRouterIPParam, s conversion.Scope) error {
out.FixedIP = in.FixedIP
- if err := Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(&in.Subnet, &out.Subnet, s); err != nil {
+ if err := Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetParam(&in.Subnet, &out.Subnet, s); err != nil {
return err
}
return nil
@@ -677,7 +687,7 @@ func Convert_v1alpha7_ExternalRouterIPParam_To_v1beta1_ExternalRouterIPParam(in
func autoConvert_v1beta1_ExternalRouterIPParam_To_v1alpha7_ExternalRouterIPParam(in *v1beta1.ExternalRouterIPParam, out *ExternalRouterIPParam, s conversion.Scope) error {
out.FixedIP = in.FixedIP
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(&in.Subnet, &out.Subnet, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha7_SubnetFilter(&in.Subnet, &out.Subnet, s); err != nil {
return err
}
return nil
@@ -691,8 +701,8 @@ func Convert_v1beta1_ExternalRouterIPParam_To_v1alpha7_ExternalRouterIPParam(in
func autoConvert_v1alpha7_FixedIP_To_v1beta1_FixedIP(in *FixedIP, out *v1beta1.FixedIP, s conversion.Scope) error {
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
- *out = new(v1beta1.SubnetFilter)
- if err := Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(*in, *out, s); err != nil {
+ *out = new(v1beta1.SubnetParam)
+ if err := Convert_v1alpha7_SubnetFilter_To_v1beta1_SubnetParam(*in, *out, s); err != nil {
return err
}
} else {
@@ -713,7 +723,7 @@ func autoConvert_v1beta1_FixedIP_To_v1alpha7_FixedIP(in *v1beta1.FixedIP, out *F
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
*out = new(SubnetFilter)
- if err := Convert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(*in, *out, s); err != nil {
+ if err := Convert_v1beta1_SubnetParam_To_v1alpha7_SubnetFilter(*in, *out, s); err != nil {
return err
}
} else {
@@ -1783,7 +1793,7 @@ func autoConvert_v1alpha7_SubnetFilter_To_v1beta1_SubnetFilter(in *SubnetFilter,
out.CIDR = in.CIDR
out.IPv6AddressMode = in.IPv6AddressMode
out.IPv6RAMode = in.IPv6RAMode
- out.ID = in.ID
+ // WARNING: in.ID requires manual conversion: does not exist in peer-type
// WARNING: in.Tags requires manual conversion: does not exist in peer-type
// WARNING: in.TagsAny requires manual conversion: does not exist in peer-type
// WARNING: in.NotTags requires manual conversion: does not exist in peer-type
@@ -1800,7 +1810,6 @@ func autoConvert_v1beta1_SubnetFilter_To_v1alpha7_SubnetFilter(in *v1beta1.Subne
out.CIDR = in.CIDR
out.IPv6AddressMode = in.IPv6AddressMode
out.IPv6RAMode = in.IPv6RAMode
- out.ID = in.ID
// WARNING: in.FilterByNeutronTags requires manual conversion: does not exist in peer-type
return nil
}
diff --git a/api/v1beta1/openstackcluster_types.go b/api/v1beta1/openstackcluster_types.go
index 35a2bf5505..b1566c01ac 100644
--- a/api/v1beta1/openstackcluster_types.go
+++ b/api/v1beta1/openstackcluster_types.go
@@ -58,7 +58,7 @@ type OpenStackClusterSpec struct {
// +kubebuilder:validation:MaxItems=2
// +listType=atomic
// +optional
- Subnets []SubnetFilter `json:"subnets,omitempty"`
+ Subnets []SubnetParam `json:"subnets,omitempty"`
// NetworkMTU sets the maximum transmission unit (MTU) value to address fragmentation for the private network ID.
// This value will be used only if the Cluster actuator creates the network.
diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go
index 34633a9261..0fe2f4a1f7 100644
--- a/api/v1beta1/types.go
+++ b/api/v1beta1/types.go
@@ -48,7 +48,7 @@ type ExternalRouterIPParam struct {
// The FixedIP in the corresponding subnet
FixedIP string `json:"fixedIP,omitempty"`
// The subnet in which the FixedIP is used for the Gateway of this router
- Subnet SubnetFilter `json:"subnet"`
+ Subnet SubnetParam `json:"subnet"`
}
// NeutronTag represents a tag on a Neutron resource.
@@ -85,7 +85,7 @@ type FilterByNeutronTags struct {
}
func (f *FilterByNeutronTags) IsZero() bool {
- return f == nil || len(f.Tags) == 0 && len(f.TagsAny) == 0 && len(f.NotTags) == 0 && len(f.NotTagsAny) == 0
+ return f == nil || (len(f.Tags) == 0 && len(f.TagsAny) == 0 && len(f.NotTags) == 0 && len(f.NotTagsAny) == 0)
}
type SecurityGroupFilter struct {
@@ -131,6 +131,22 @@ func (networkFilter *NetworkFilter) IsZero() bool {
networkFilter.FilterByNeutronTags.IsZero()
}
+// SubnetParam specifies an OpenStack subnet to use. It may be specified by either ID or filter, but not both.
+// +kubebuilder:validation:MaxProperties:=1
+// +kubebuilder:validation:MinProperties:=1
+type SubnetParam struct {
+ // ID is the uuid of the subnet. It will not be validated.
+ // +kubebuilder:validation:Format:=uuid
+ // +optional
+ ID optional.String `json:"id,omitempty"`
+
+ // Filter specifies a filter to select the subnet. It must match exactly one subnet.
+ // +optional
+ Filter *SubnetFilter `json:"filter,omitempty"`
+}
+
+// SubnetFilter specifies a filter to select a subnet. At least one parameter must be specified.
+// +kubebuilder:validation:MinProperties:=1
type SubnetFilter struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
@@ -140,11 +156,25 @@ type SubnetFilter struct {
CIDR string `json:"cidr,omitempty"`
IPv6AddressMode string `json:"ipv6AddressMode,omitempty"`
IPv6RAMode string `json:"ipv6RAMode,omitempty"`
- ID string `json:"id,omitempty"`
FilterByNeutronTags `json:",inline"`
}
+func (subnetFilter *SubnetFilter) IsZero() bool {
+ if subnetFilter == nil {
+ return true
+ }
+ return subnetFilter.Name == "" &&
+ subnetFilter.Description == "" &&
+ subnetFilter.ProjectID == "" &&
+ subnetFilter.IPVersion == 0 &&
+ subnetFilter.GatewayIP == "" &&
+ subnetFilter.CIDR == "" &&
+ subnetFilter.IPv6AddressMode == "" &&
+ subnetFilter.IPv6RAMode == "" &&
+ subnetFilter.FilterByNeutronTags.IsZero()
+}
+
type RouterFilter struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
@@ -335,7 +365,7 @@ type FixedIP struct {
// Subnet is an openstack subnet query that will return the id of a subnet to create
// the fixed IP of a port in. This query must not return more than one subnet.
// +optional
- Subnet *SubnetFilter `json:"subnet,omitempty"`
+ Subnet *SubnetParam `json:"subnet,omitempty"`
// IPAddress is a specific IP address to assign to the port. If Subnet
// is also specified, IPAddress must be a valid IP address in the
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index bc21785a3b..6255ef3438 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -284,7 +284,7 @@ func (in *FixedIP) DeepCopyInto(out *FixedIP) {
*out = *in
if in.Subnet != nil {
in, out := &in.Subnet, &out.Subnet
- *out = new(SubnetFilter)
+ *out = new(SubnetParam)
(*in).DeepCopyInto(*out)
}
if in.IPAddress != nil {
@@ -566,7 +566,7 @@ func (in *OpenStackClusterSpec) DeepCopyInto(out *OpenStackClusterSpec) {
}
if in.Subnets != nil {
in, out := &in.Subnets, &out.Subnets
- *out = make([]SubnetFilter, len(*in))
+ *out = make([]SubnetParam, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -1551,6 +1551,31 @@ func (in *SubnetFilter) DeepCopy() *SubnetFilter {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SubnetParam) DeepCopyInto(out *SubnetParam) {
+ *out = *in
+ if in.ID != nil {
+ in, out := &in.ID, &out.ID
+ *out = new(string)
+ **out = **in
+ }
+ if in.Filter != nil {
+ in, out := &in.Filter, &out.Filter
+ *out = new(SubnetFilter)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SubnetParam.
+func (in *SubnetParam) DeepCopy() *SubnetParam {
+ if in == nil {
+ return nil
+ }
+ out := new(SubnetParam)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) {
*out = *in
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml
index f8146a4dc0..2a0546bb8c 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml
@@ -5140,78 +5140,90 @@ spec:
description: |-
Subnet is an openstack subnet query that will return the id of a subnet to create
the fixed IP of a port in. This query must not return more than one subnet.
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to
+ select the subnet. It must match exactly
+ one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet.
+ It will not be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
type: object
type: array
@@ -5761,78 +5773,89 @@ spec:
subnet:
description: The subnet in which the FixedIP is used for the
Gateway of this router
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to select the subnet.
+ It must match exactly one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet. It will not be
+ validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
required:
- subnet
@@ -6157,78 +6180,90 @@ spec:
all subnets in Network will be used. If 2 subnets are specified, one
must be IPv4 and the other IPv6.
items:
+ description: SubnetParam specifies an OpenStack subnet to use. It
+ may be specified by either ID or filter, but not both.
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to select the subnet.
+ It must match exactly one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet. It will not be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
maxItems: 2
type: array
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml
index 72e9aabe49..1eaba9daf1 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml
@@ -2570,78 +2570,90 @@ spec:
description: |-
Subnet is an openstack subnet query that will return the id of a subnet to create
the fixed IP of a port in. This query must not return more than one subnet.
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter
+ to select the subnet. It must match
+ exactly one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the
+ subnet. It will not be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
type: object
type: array
@@ -3197,78 +3209,89 @@ spec:
subnet:
description: The subnet in which the FixedIP is used
for the Gateway of this router
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to select
+ the subnet. It must match exactly one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet. It will
+ not be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
required:
- subnet
@@ -3596,78 +3619,92 @@ spec:
all subnets in Network will be used. If 2 subnets are specified, one
must be IPv4 and the other IPv6.
items:
+ description: SubnetParam specifies an OpenStack subnet to
+ use. It may be specified by either ID or filter, but not
+ both.
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to select the
+ subnet. It must match exactly one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet. It will not
+ be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
maxItems: 2
type: array
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml
index bc3d9658b0..c0463608c0 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml
@@ -1918,78 +1918,89 @@ spec:
description: |-
Subnet is an openstack subnet query that will return the id of a subnet to create
the fixed IP of a port in. This query must not return more than one subnet.
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to select the
+ subnet. It must match exactly one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet. It will
+ not be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
type: object
type: array
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml
index 7c481ff2b8..2407fa4a06 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml
@@ -1594,78 +1594,90 @@ spec:
description: |-
Subnet is an openstack subnet query that will return the id of a subnet to create
the fixed IP of a port in. This query must not return more than one subnet.
+ maxProperties: 1
+ minProperties: 1
properties:
- cidr:
- type: string
- description:
- type: string
- gatewayIP:
- type: string
+ filter:
+ description: Filter specifies a filter to
+ select the subnet. It must match exactly
+ one subnet.
+ minProperties: 1
+ properties:
+ cidr:
+ type: string
+ description:
+ type: string
+ gatewayIP:
+ type: string
+ ipVersion:
+ type: integer
+ ipv6AddressMode:
+ type: string
+ ipv6RAMode:
+ type: string
+ name:
+ type: string
+ notTags:
+ description: |-
+ NotTags is a list of tags to filter by. If specified, resources which
+ contain all of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ notTagsAny:
+ description: |-
+ NotTagsAny is a list of tags to filter by. If specified, resources
+ which contain any of the given tags will be excluded from the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ projectID:
+ type: string
+ tags:
+ description: |-
+ Tags is a list of tags to filter by. If specified, the resource must
+ have all of the tags specified to be included in the result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ tagsAny:
+ description: |-
+ TagsAny is a list of tags to filter by. If specified, the resource
+ must have at least one of the tags specified to be included in the
+ result.
+ items:
+ description: |-
+ NeutronTag represents a tag on a Neutron resource.
+ It may not be empty and may not contain commas.
+ minLength: 1
+ pattern: ^[^,]+$
+ type: string
+ type: array
+ x-kubernetes-list-type: set
+ type: object
id:
+ description: ID is the uuid of the subnet.
+ It will not be validated.
+ format: uuid
type: string
- ipVersion:
- type: integer
- ipv6AddressMode:
- type: string
- ipv6RAMode:
- type: string
- name:
- type: string
- notTags:
- description: |-
- NotTags is a list of tags to filter by. If specified, resources which
- contain all of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- notTagsAny:
- description: |-
- NotTagsAny is a list of tags to filter by. If specified, resources
- which contain any of the given tags will be excluded from the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- projectID:
- type: string
- tags:
- description: |-
- Tags is a list of tags to filter by. If specified, the resource must
- have all of the tags specified to be included in the result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
- tagsAny:
- description: |-
- TagsAny is a list of tags to filter by. If specified, the resource
- must have at least one of the tags specified to be included in the
- result.
- items:
- description: |-
- NeutronTag represents a tag on a Neutron resource.
- It may not be empty and may not contain commas.
- minLength: 1
- pattern: ^[^,]+$
- type: string
- type: array
- x-kubernetes-list-type: set
type: object
type: object
type: array
diff --git a/controllers/openstackcluster_controller.go b/controllers/openstackcluster_controller.go
index 9c6e091254..c9283f11b7 100644
--- a/controllers/openstackcluster_controller.go
+++ b/controllers/openstackcluster_controller.go
@@ -885,9 +885,9 @@ func getClusterSubnets(networkingService *networking.Service, openStackCluster *
}
} else {
for subnet := range openStackClusterSubnets {
- filteredSubnet, err := networkingService.GetNetworkSubnetByFilter(networkID, &openStackClusterSubnets[subnet])
+ filteredSubnet, err := networkingService.GetNetworkSubnetByParam(networkID, &openStackClusterSubnets[subnet])
if err != nil {
- err = fmt.Errorf("failed to find subnet: %w", err)
+ err = fmt.Errorf("failed to find subnet %d in network %s: %w", subnet, networkID, err)
if errors.Is(err, networking.ErrFilterMatch) {
handleUpdateOSCError(openStackCluster, err)
}
diff --git a/controllers/openstackcluster_controller_test.go b/controllers/openstackcluster_controller_test.go
index 7f2aa20f1b..0b6fe63784 100644
--- a/controllers/openstackcluster_controller_test.go
+++ b/controllers/openstackcluster_controller_test.go
@@ -595,9 +595,9 @@ var _ = Describe("OpenStackCluster controller", func() {
Network: &infrav1.NetworkParam{
ID: pointer.String(clusterNetworkID),
},
- Subnets: []infrav1.SubnetFilter{
- {ID: clusterSubnets[0]},
- {ID: clusterSubnets[1]},
+ Subnets: []infrav1.SubnetParam{
+ {ID: &clusterSubnets[0]},
+ {ID: &clusterSubnets[1]},
},
}
testCluster.Status = infrav1.OpenStackClusterStatus{
@@ -636,15 +636,17 @@ var _ = Describe("OpenStackCluster controller", func() {
}, nil)
networkClientRecorder.GetSubnet(clusterSubnets[0]).Return(&subnets.Subnet{
- ID: clusterSubnets[0],
- Name: "cluster-subnet",
- CIDR: "192.168.0.0/24",
+ ID: clusterSubnets[0],
+ NetworkID: clusterNetworkID,
+ Name: "cluster-subnet",
+ CIDR: "192.168.0.0/24",
}, nil)
networkClientRecorder.GetSubnet(clusterSubnets[1]).Return(&subnets.Subnet{
- ID: clusterSubnets[1],
- Name: "cluster-subnet-v6",
- CIDR: "2001:db8:2222:5555::/64",
+ ID: clusterSubnets[1],
+ NetworkID: clusterNetworkID,
+ Name: "cluster-subnet-v6",
+ CIDR: "2001:db8:2222:5555::/64",
}, nil)
err = reconcileNetworkComponents(scope, capiCluster, testCluster)
@@ -661,8 +663,8 @@ var _ = Describe("OpenStackCluster controller", func() {
DisableAPIServerFloatingIP: pointer.Bool(true),
APIServerFixedIP: pointer.String("10.0.0.1"),
DisableExternalNetwork: pointer.Bool(true),
- Subnets: []infrav1.SubnetFilter{
- {ID: clusterSubnetID},
+ Subnets: []infrav1.SubnetParam{
+ {ID: pointer.String(clusterSubnetID)},
},
}
err := k8sClient.Create(ctx, testCluster)
diff --git a/docs/book/src/api/v1beta1/api.md b/docs/book/src/api/v1beta1/api.md
index 527bf24ed0..24c303f15e 100644
--- a/docs/book/src/api/v1beta1/api.md
+++ b/docs/book/src/api/v1beta1/api.md
@@ -117,8 +117,8 @@ are specified.
subnets
-
-[]SubnetFilter
+
+[]SubnetParam
|
@@ -1435,8 +1435,8 @@ string
subnet
-
-SubnetFilter
+
+SubnetParam
|
@@ -1548,8 +1548,8 @@ which contain any of the given tags will be excluded from the result.
subnet
-
-SubnetFilter
+
+SubnetParam
|
@@ -2093,8 +2093,8 @@ are specified.
subnets
-
-[]SubnetFilter
+
+[]SubnetParam
|
@@ -2675,8 +2675,8 @@ are specified.
subnets
-
-[]SubnetFilter
+
+[]SubnetParam
|
@@ -4804,11 +4804,10 @@ string
(Appears on:
-ExternalRouterIPParam,
-FixedIP,
-OpenStackClusterSpec)
+SubnetParam)
+
SubnetFilter specifies a filter to select a subnet. At least one parameter must be specified.
@@ -4900,27 +4899,64 @@ string
+FilterByNeutronTags
+
+
+FilterByNeutronTags
+
+
+ |
+
+
+(Members of FilterByNeutronTags are embedded into this type.)
+
+ |
+
+
+
+SubnetParam
+
+
+(Appears on:
+ExternalRouterIPParam,
+FixedIP,
+OpenStackClusterSpec)
+
+
+
SubnetParam specifies an OpenStack subnet to use. It may be specified by either ID or filter, but not both.
+
+
+
+
+Field |
+Description |
+
+
+
+
+
id
string
|
+(Optional)
+ ID is the uuid of the subnet. It will not be validated.
|
-FilterByNeutronTags
+filter
-
-FilterByNeutronTags
+
+SubnetFilter
|
-
-(Members of FilterByNeutronTags are embedded into this type.)
-
+(Optional)
+Filter specifies a filter to select the subnet. It must match exactly one subnet.
|
diff --git a/pkg/cloud/services/networking/network.go b/pkg/cloud/services/networking/network.go
index 4192d05e35..716750e026 100644
--- a/pkg/cloud/services/networking/network.go
+++ b/pkg/cloud/services/networking/network.go
@@ -371,34 +371,51 @@ func (s *Service) GetSubnetsByFilter(opts subnets.ListOptsBuilder) ([]subnets.Su
return subnetList, nil
}
-// GetSubnetByFilter gets a single subnet specified by the given SubnetFilter.
-// It returns an ErrFilterMatch if no or multiple subnets are found.
-func (s *Service) GetSubnetByFilter(filter *infrav1.SubnetFilter) (*subnets.Subnet, error) {
- listOpts := filterconvert.SubnetFilterToListOpts(filter)
- return s.getSubnetByFilter(listOpts)
+// GetSubnetIDByParam gets the id of a subnet from the given SubnetParam. It
+// does not make any OpenStack API calls if the subnet is specified by ID.
+func (s *Service) GetSubnetIDByParam(param *infrav1.SubnetParam) (string, error) {
+ if param.ID != nil {
+ return *param.ID, nil
+ }
+ subnet, err := s.GetSubnetByParam(param)
+ if err != nil {
+ return "", err
+ }
+ return subnet.ID, nil
}
-// GetNetworkSubnetByFilter gets a single subnet of the given network, specified by the given SubnetFilter.
+// GetSubnetByParam gets a single subnet specified by the given SubnetParam
// It returns an ErrFilterMatch if no or multiple subnets are found.
-func (s *Service) GetNetworkSubnetByFilter(networkID string, filter *infrav1.SubnetFilter) (*subnets.Subnet, error) {
- listOpts := filterconvert.SubnetFilterToListOpts(filter)
- listOpts.NetworkID = networkID
-
- return s.getSubnetByFilter(listOpts)
+func (s *Service) GetSubnetByParam(param *infrav1.SubnetParam) (*subnets.Subnet, error) {
+ return s.GetNetworkSubnetByParam("", param)
}
-// getSubnetByFilter gets a single subnet specified by the given gophercloud ListOpts.
+// GetNetworkSubnetByParam gets a single subnet of the given network, specified by the given SubnetParam.
// It returns an ErrFilterMatch if no or multiple subnets are found.
-func (s *Service) getSubnetByFilter(listOpts subnets.ListOpts) (*subnets.Subnet, error) {
- // If the ID is set, we can just get the subnet by ID.
- if listOpts.ID != "" {
- subnet, err := s.client.GetSubnet(listOpts.ID)
+func (s *Service) GetNetworkSubnetByParam(networkID string, param *infrav1.SubnetParam) (*subnets.Subnet, error) {
+ if param.ID != nil {
+ subnet, err := s.client.GetSubnet(*param.ID)
if capoerrors.IsNotFound(err) {
return nil, ErrNoMatches
}
+
+ if networkID != "" && subnet.NetworkID != networkID {
+ s.scope.Logger().V(4).Info("Subnet specified by ID does not belong to the given network", "subnetID", subnet.ID, "networkID", networkID)
+ return nil, ErrNoMatches
+ }
return subnet, err
}
+ if param.Filter == nil {
+ // Should have been caught by validation
+ return nil, errors.New("subnet filter: both id and filter are nil")
+ }
+
+ listOpts := filterconvert.SubnetFilterToListOpts(param.Filter)
+ if networkID != "" {
+ listOpts.NetworkID = networkID
+ }
+
subnets, err := s.GetSubnetsByFilter(listOpts)
if err != nil {
return nil, err
diff --git a/pkg/cloud/services/networking/port.go b/pkg/cloud/services/networking/port.go
index 8677b87a04..e75a650265 100644
--- a/pkg/cloud/services/networking/port.go
+++ b/pkg/cloud/services/networking/port.go
@@ -493,7 +493,7 @@ func (s *Service) normalizePortTarget(port *infrav1.PortOpts, defaultNetwork *in
continue
}
- subnet, err := s.GetSubnetByFilter(fixedIP.Subnet)
+ subnet, err := s.GetSubnetByParam(fixedIP.Subnet)
if err != nil {
// Multiple matches might be ok later when we restrict matches to a single network
if errors.Is(err, ErrMultipleMatches) {
@@ -526,7 +526,7 @@ func (s *Service) normalizePortTarget(port *infrav1.PortOpts, defaultNetwork *in
resolvedFixedIP := &resolvedFixedIPs[i]
resolvedFixedIP.IPAddress = fixedIP.IPAddress
if fixedIP.Subnet != nil && resolvedFixedIP.SubnetID == nil {
- subnet, err := s.GetNetworkSubnetByFilter(networkID, fixedIP.Subnet)
+ subnet, err := s.GetNetworkSubnetByParam(networkID, fixedIP.Subnet)
if err != nil {
return "", nil, err
}
diff --git a/pkg/cloud/services/networking/port_test.go b/pkg/cloud/services/networking/port_test.go
index 8fb6e035b2..ea0b6f3816 100644
--- a/pkg/cloud/services/networking/port_test.go
+++ b/pkg/cloud/services/networking/port_test.go
@@ -526,8 +526,8 @@ func TestService_ConstructPorts(t *testing.T) {
{
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- ID: subnetID1,
+ Subnet: &infrav1.SubnetParam{
+ ID: pointer.String(subnetID1),
},
},
},
@@ -558,8 +558,8 @@ func TestService_ConstructPorts(t *testing.T) {
{
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- Name: "test-subnet",
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{Name: "test-subnet"},
},
},
},
@@ -594,8 +594,8 @@ func TestService_ConstructPorts(t *testing.T) {
{
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- Name: "test-subnet",
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{Name: "test-subnet"},
},
},
},
@@ -614,8 +614,8 @@ func TestService_ConstructPorts(t *testing.T) {
{
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- Name: "test-subnet",
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{Name: "test-subnet"},
},
},
},
@@ -637,13 +637,13 @@ func TestService_ConstructPorts(t *testing.T) {
{
FixedIPs: []infrav1.FixedIP{
{
- Subnet: &infrav1.SubnetFilter{
- Name: "test-subnet1",
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{Name: "test-subnet1"},
},
},
{
- Subnet: &infrav1.SubnetFilter{
- Name: "test-subnet2",
+ Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{Name: "test-subnet2"},
},
},
},
diff --git a/pkg/cloud/services/networking/router.go b/pkg/cloud/services/networking/router.go
index e6267fdb30..7940222f74 100644
--- a/pkg/cloud/services/networking/router.go
+++ b/pkg/cloud/services/networking/router.go
@@ -168,13 +168,9 @@ func (s *Service) setRouterExternalIPs(openStackCluster *infrav1.OpenStackCluste
for i := range openStackCluster.Spec.ExternalRouterIPs {
externalRouterIP := openStackCluster.Spec.ExternalRouterIPs[i]
- subnetID := externalRouterIP.Subnet.ID
- if subnetID == "" {
- subnet, err := s.GetSubnetByFilter(&externalRouterIP.Subnet)
- if err != nil {
- return fmt.Errorf("failed to get subnet for external router: %w", err)
- }
- subnetID = subnet.ID
+ subnetID, err := s.GetSubnetIDByParam(&externalRouterIP.Subnet)
+ if err != nil {
+ return fmt.Errorf("failed to get subnet for external router: %w", err)
}
updateOpts.GatewayInfo.ExternalFixedIPs = append(updateOpts.GatewayInfo.ExternalFixedIPs, routers.ExternalFixedIP{
IPAddress: externalRouterIP.FixedIP,
diff --git a/pkg/utils/filterconvert/convert.go b/pkg/utils/filterconvert/convert.go
index 01ce2126ec..c1194b7880 100644
--- a/pkg/utils/filterconvert/convert.go
+++ b/pkg/utils/filterconvert/convert.go
@@ -55,7 +55,6 @@ func SubnetFilterToListOpts(subnetFilter *infrav1.SubnetFilter) subnets.ListOpts
CIDR: subnetFilter.CIDR,
IPv6AddressMode: subnetFilter.IPv6AddressMode,
IPv6RAMode: subnetFilter.IPv6RAMode,
- ID: subnetFilter.ID,
Tags: infrav1.JoinTags(subnetFilter.Tags),
TagsAny: infrav1.JoinTags(subnetFilter.TagsAny),
NotTags: infrav1.JoinTags(subnetFilter.NotTags),
diff --git a/test/e2e/suites/apivalidations/filters_test.go b/test/e2e/suites/apivalidations/filters_test.go
index aa8691df0e..ce0b38637b 100644
--- a/test/e2e/suites/apivalidations/filters_test.go
+++ b/test/e2e/suites/apivalidations/filters_test.go
@@ -61,16 +61,18 @@ var _ = Describe("Filter API validations", func() {
for i := range tags {
port := &ports[i]
port.Network = &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tags[i]}}
- port.FixedIPs = []infrav1.FixedIP{{Subnet: &infrav1.SubnetFilter{FilterByNeutronTags: tags[i]}}}
+ port.FixedIPs = []infrav1.FixedIP{{Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{FilterByNeutronTags: tags[i]},
+ }}}
port.SecurityGroups = []infrav1.SecurityGroupFilter{{FilterByNeutronTags: tags[i]}}
}
Expect(k8sClient.Create(ctx, machine)).To(Succeed(), "OpenStackMachine creation should succeed")
// Maximum of 2 subnets are supported
nSubnets := min(len(tags), 2)
- subnets := make([]infrav1.SubnetFilter, nSubnets)
+ subnets := make([]infrav1.SubnetParam, nSubnets)
for i := 0; i < nSubnets; i++ {
- subnets[i].FilterByNeutronTags = tags[i]
+ subnets[i].Filter = &infrav1.SubnetFilter{FilterByNeutronTags: tags[i]}
}
cluster.Spec.Subnets = subnets
if len(tags) > 0 {
@@ -114,7 +116,9 @@ var _ = Describe("Filter API validations", func() {
{
machine := machine.DeepCopy()
machine.Spec.Ports = []infrav1.PortOpts{
- {FixedIPs: []infrav1.FixedIP{{Subnet: &infrav1.SubnetFilter{FilterByNeutronTags: tags[i]}}}},
+ {FixedIPs: []infrav1.FixedIP{{Subnet: &infrav1.SubnetParam{
+ Filter: &infrav1.SubnetFilter{FilterByNeutronTags: tags[i]},
+ }}}},
}
Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail with invalid port subnet neutron tags")
}
@@ -132,7 +136,7 @@ var _ = Describe("Filter API validations", func() {
{
cluster := cluster.DeepCopy()
- cluster.Spec.Subnets = []infrav1.SubnetFilter{{FilterByNeutronTags: tag}}
+ cluster.Spec.Subnets = []infrav1.SubnetParam{{Filter: &infrav1.SubnetFilter{FilterByNeutronTags: tag}}}
Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail with invalid subnet neutron tags")
}
@@ -261,4 +265,46 @@ var _ = Describe("Filter API validations", func() {
Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail")
})
})
+
+ Context("SubnetParam", func() {
+ It("should allow setting ID", func() {
+ cluster.Spec.Subnets = []infrav1.SubnetParam{
+ {ID: pointer.String("06c32c52-f207-4f6a-a769-bbcbe5a43f5c")},
+ }
+ Expect(k8sClient.Create(ctx, cluster)).To(Succeed(), "OpenStackCluster creation should succeed")
+ })
+
+ It("should allow setting non-empty Filter", func() {
+ cluster.Spec.Subnets = []infrav1.SubnetParam{
+ {Filter: &infrav1.SubnetFilter{Name: "foo"}},
+ }
+ Expect(k8sClient.Create(ctx, cluster)).To(Succeed(), "OpenStackCluster creation should succeed")
+ })
+
+ It("should not allow setting empty SubnetParam", func() {
+ cluster.Spec.Subnets = []infrav1.SubnetParam{{}}
+ Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail")
+ })
+
+ It("should not allow setting invalid id", func() {
+ cluster.Spec.Subnets = []infrav1.SubnetParam{
+ {ID: pointer.String("foo")},
+ }
+ Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail")
+ })
+
+ It("should not allow setting empty Filter", func() {
+ cluster.Spec.Subnets = []infrav1.SubnetParam{
+ {Filter: &infrav1.SubnetFilter{}},
+ }
+ Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail")
+ })
+
+ It("should not allow setting both ID and Filter", func() {
+ cluster.Spec.Subnets = []infrav1.SubnetParam{
+ {ID: pointer.String("06c32c52-f207-4f6a-a769-bbcbe5a43f5c"), Filter: &infrav1.SubnetFilter{Name: "foo"}},
+ }
+ Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail")
+ })
+ })
})
diff --git a/test/helpers/fuzzerfuncs.go b/test/helpers/fuzzerfuncs.go
index da35973632..35720fcdd1 100644
--- a/test/helpers/fuzzerfuncs.go
+++ b/test/helpers/fuzzerfuncs.go
@@ -75,7 +75,7 @@ func InfraV1FuzzerFuncs() []interface{} {
// length 1, but we need to also test length 2.
// Ensure it is occasionally generated.
if len(spec.Subnets) == 1 && c.RandBool() {
- subnet := infrav1.SubnetFilter{}
+ subnet := infrav1.SubnetParam{}
c.Fuzz(&subnet)
spec.Subnets = append(spec.Subnets, subnet)
}
@@ -129,9 +129,13 @@ func InfraV1FuzzerFuncs() []interface{} {
filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny)
},
- // v1beta1 network param contains exactly one of ID or filter
+ // v1beta1 filter params contain exactly one of ID or filter
func(param *infrav1.NetworkParam, c fuzz.Continue) {
fuzzFilterParam(¶m.ID, ¶m.Filter, c)
},
+
+ func(param *infrav1.SubnetParam, c fuzz.Continue) {
+ fuzzFilterParam(¶m.ID, ¶m.Filter, c)
+ },
}
}