diff --git a/api/v1alpha1/openstackfloatingippool_types.go b/api/v1alpha1/openstackfloatingippool_types.go index b3b0ebfc2a..931f2d503e 100644 --- a/api/v1alpha1/openstackfloatingippool_types.go +++ b/api/v1alpha1/openstackfloatingippool_types.go @@ -63,7 +63,7 @@ type OpenStackFloatingIPPoolSpec struct { // FloatingIPNetwork is the external network to use for floating ips, if there's only one external network it will be used by default // +optional - FloatingIPNetwork infrav1.NetworkFilter `json:"floatingIPNetwork"` + FloatingIPNetwork infrav1.NetworkParam `json:"floatingIPNetwork"` // The stratergy to use for reclaiming floating ips when they are released from a machine // +kubebuilder:validation:Optional diff --git a/api/v1alpha5/conversion.go b/api/v1alpha5/conversion.go index 5c2516b891..b8190e088a 100644 --- a/api/v1alpha5/conversion.go +++ b/api/v1alpha5/conversion.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha5 import ( + "errors" "strings" conversion "k8s.io/apimachinery/pkg/conversion" @@ -205,8 +206,8 @@ func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha5_OpenStackClusterSpec(in *i return err } - if in.ExternalNetwork != nil && in.ExternalNetwork.ID != "" { - out.ExternalNetworkID = in.ExternalNetwork.ID + if in.ExternalNetwork != nil && in.ExternalNetwork.ID != nil { + out.ExternalNetworkID = *in.ExternalNetwork.ID } if len(in.ManagedSubnets) > 0 { @@ -246,8 +247,8 @@ func Convert_v1alpha5_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O } if in.ExternalNetworkID != "" { - out.ExternalNetwork = &infrav1.NetworkFilter{ - ID: in.ExternalNetworkID, + out.ExternalNetwork = &infrav1.NetworkParam{ + ID: &in.ExternalNetworkID, } } @@ -746,18 +747,49 @@ func Convert_v1beta1_SecurityGroupFilter_To_v1alpha5_SecurityGroupFilter(in *inf return nil } -func Convert_v1alpha5_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilter, out *infrav1.NetworkFilter, s conversion.Scope) error { - if err := autoConvert_v1alpha5_NetworkFilter_To_v1beta1_NetworkFilter(in, out, s); err != nil { +func Convert_v1alpha5_NetworkFilter_To_v1beta1_NetworkParam(in *NetworkFilter, out *infrav1.NetworkParam, s conversion.Scope) error { + if in.ID != "" { + out.ID = &in.ID + return nil + } + outFilter := &infrav1.NetworkFilter{} + if err := autoConvert_v1alpha5_NetworkFilter_To_v1beta1_NetworkFilter(in, outFilter, 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, &outFilter.FilterByNeutronTags) + if !outFilter.IsZero() { + out.Filter = outFilter + } return nil } -func Convert_v1beta1_NetworkFilter_To_v1alpha5_NetworkFilter(in *infrav1.NetworkFilter, out *NetworkFilter, s conversion.Scope) error { - if err := autoConvert_v1beta1_NetworkFilter_To_v1alpha5_NetworkFilter(in, out, s); err != nil { - return err +func Convert_v1beta1_NetworkParam_To_v1alpha5_NetworkFilter(in *infrav1.NetworkParam, out *NetworkFilter, s conversion.Scope) error { + if in.ID != nil { + out.ID = *in.ID + return nil + } + if in.Filter != nil { + if err := autoConvert_v1beta1_NetworkFilter_To_v1alpha5_NetworkFilter(in.Filter, out, s); err != nil { + return err + } + infrav1.ConvertAllTagsFrom(&in.Filter.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny) } - infrav1.ConvertAllTagsFrom(&in.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny) return nil } + +// conversion-gen registers the following functions so we have to define them, but nothing should ever call them. +func Convert_v1alpha5_NetworkFilter_To_v1beta1_NetworkFilter(_ *NetworkFilter, _ *infrav1.NetworkFilter, _ conversion.Scope) error { + return errors.New("Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter should not be called") +} + +func Convert_v1beta1_NetworkFilter_To_v1alpha5_NetworkFilter(_ *infrav1.NetworkFilter, _ *NetworkFilter, _ conversion.Scope) error { + return errors.New("Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter should not be called") +} + +func Convert_v1alpha5_NetworkParam_To_v1beta1_NetworkParam(_ *NetworkParam, _ *infrav1.NetworkParam, _ conversion.Scope) error { + return errors.New("Convert_v1alpha6_NetworkParam_To_v1beta1_NetworkParam should not be called") +} + +func Convert_v1beta1_NetworkParam_To_v1alpha5_NetworkParam(_ *infrav1.NetworkParam, _ *NetworkParam, _ conversion.Scope) error { + return errors.New("Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkParam should not be called") +} diff --git a/api/v1alpha5/zz_generated.conversion.go b/api/v1alpha5/zz_generated.conversion.go index f5d208397e..e8376912a3 100644 --- a/api/v1alpha5/zz_generated.conversion.go +++ b/api/v1alpha5/zz_generated.conversion.go @@ -252,6 +252,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*NetworkFilter)(nil), (*v1beta1.NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha5_NetworkFilter_To_v1beta1_NetworkParam(a.(*NetworkFilter), b.(*v1beta1.NetworkParam), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*NetworkParam)(nil), (*v1beta1.NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha5_NetworkParam_To_v1beta1_NetworkParam(a.(*NetworkParam), b.(*v1beta1.NetworkParam), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*Network)(nil), (*v1beta1.NetworkStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha5_Network_To_v1beta1_NetworkStatus(a.(*Network), b.(*v1beta1.NetworkStatus), scope) }); err != nil { @@ -337,6 +347,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.NetworkParam)(nil), (*NetworkFilter)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NetworkParam_To_v1alpha5_NetworkFilter(a.(*v1beta1.NetworkParam), b.(*NetworkFilter), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1beta1.NetworkParam)(nil), (*NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NetworkParam_To_v1alpha5_NetworkParam(a.(*v1beta1.NetworkParam), b.(*NetworkParam), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.NetworkStatusWithSubnets)(nil), (*Network)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_NetworkStatusWithSubnets_To_v1alpha5_Network(a.(*v1beta1.NetworkStatusWithSubnets), b.(*Network), scope) }); err != nil { @@ -570,7 +590,7 @@ func autoConvert_v1alpha5_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilt out.Name = in.Name out.Description = in.Description out.ProjectID = in.ProjectID - 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 @@ -582,11 +602,24 @@ func autoConvert_v1beta1_NetworkFilter_To_v1alpha5_NetworkFilter(in *v1beta1.Net out.Name = in.Name out.Description = in.Description out.ProjectID = in.ProjectID - out.ID = in.ID // WARNING: in.FilterByNeutronTags requires manual conversion: does not exist in peer-type return nil } +func autoConvert_v1alpha5_NetworkParam_To_v1beta1_NetworkParam(in *NetworkParam, out *v1beta1.NetworkParam, s conversion.Scope) error { + // WARNING: in.UUID requires manual conversion: does not exist in peer-type + // WARNING: in.FixedIP 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.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter) + // WARNING: in.Subnets requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_v1beta1_NetworkParam_To_v1alpha5_NetworkParam(in *v1beta1.NetworkParam, out *NetworkParam, 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.NetworkFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.NetworkFilter) + return nil +} + func autoConvert_v1alpha5_OpenStackCluster_To_v1beta1_OpenStackCluster(in *OpenStackCluster, out *v1beta1.OpenStackCluster, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha5_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(&in.Spec, &out.Spec, s); err != nil { @@ -664,7 +697,7 @@ func Convert_v1beta1_OpenStackClusterList_To_v1alpha5_OpenStackClusterList(in *v func autoConvert_v1alpha5_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *OpenStackClusterSpec, out *v1beta1.OpenStackClusterSpec, s conversion.Scope) error { // WARNING: in.CloudName requires manual conversion: does not exist in peer-type // WARNING: in.NodeCIDR requires manual conversion: does not exist in peer-type - // WARNING: in.Network requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter) + // WARNING: in.Network requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkParam) // WARNING: in.Subnet requires manual conversion: does not exist in peer-type // WARNING: in.DNSNameservers requires manual conversion: does not exist in peer-type if in.ExternalRouterIPs != nil { @@ -716,7 +749,7 @@ func autoConvert_v1alpha5_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(i func autoConvert_v1beta1_OpenStackClusterSpec_To_v1alpha5_OpenStackClusterSpec(in *v1beta1.OpenStackClusterSpec, out *OpenStackClusterSpec, s conversion.Scope) error { // WARNING: in.ManagedSubnets requires manual conversion: does not exist in peer-type // WARNING: in.Router requires manual conversion: does not exist in peer-type - // WARNING: in.Network requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.NetworkFilter) + // WARNING: in.Network requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkParam vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha5.NetworkFilter) // WARNING: in.Subnets requires manual conversion: does not exist in peer-type // WARNING: in.NetworkMTU requires manual conversion: does not exist in peer-type if in.ExternalRouterIPs != nil { @@ -1339,8 +1372,8 @@ func Convert_v1beta1_OpenStackMachineTemplateSpec_To_v1alpha5_OpenStackMachineTe func autoConvert_v1alpha5_PortOpts_To_v1beta1_PortOpts(in *PortOpts, out *v1beta1.PortOpts, s conversion.Scope) error { if in.Network != nil { in, out := &in.Network, &out.Network - *out = new(v1beta1.NetworkFilter) - if err := Convert_v1alpha5_NetworkFilter_To_v1beta1_NetworkFilter(*in, *out, s); err != nil { + *out = new(v1beta1.NetworkParam) + if err := Convert_v1alpha5_NetworkFilter_To_v1beta1_NetworkParam(*in, *out, s); err != nil { return err } } else { @@ -1383,7 +1416,7 @@ func autoConvert_v1beta1_PortOpts_To_v1alpha5_PortOpts(in *v1beta1.PortOpts, out if in.Network != nil { in, out := &in.Network, &out.Network *out = new(NetworkFilter) - if err := Convert_v1beta1_NetworkFilter_To_v1alpha5_NetworkFilter(*in, *out, s); err != nil { + if err := Convert_v1beta1_NetworkParam_To_v1alpha5_NetworkFilter(*in, *out, s); err != nil { return err } } else { diff --git a/api/v1alpha6/conversion_test.go b/api/v1alpha6/conversion_test.go index 3e5484cafd..d403145c93 100644 --- a/api/v1alpha6/conversion_test.go +++ b/api/v1alpha6/conversion_test.go @@ -68,6 +68,14 @@ func TestFuzzyConversion(t *testing.T) { return ret } + nonEmptyString := func(c fuzz.Continue) string { + for { + if s := c.RandString(); s != "" { + return s + } + } + } + fuzzerFuncs := func(_ runtimeserializer.CodecFactory) []interface{} { return []interface{}{ func(instance *Instance, c fuzz.Continue) { @@ -206,6 +214,22 @@ func TestFuzzyConversion(t *testing.T) { filter.NotTags = filterInvalidTags(filter.NotTags) filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny) }, + + // v1beta1 network param contains exactly one of ID or filter + func(param *infrav1.NetworkParam, c fuzz.Continue) { + if c.RandBool() { + id := nonEmptyString(c) + param.ID = &id + param.Filter = nil + } else { + filter := infrav1.NetworkFilter{} + for filter.IsZero() { + c.FuzzNoCustom(&filter) + } + param.Filter = &filter + param.ID = nil + } + }, } } @@ -303,8 +327,8 @@ func TestNetworksToPorts(t *testing.T) { afterMachineSpec: infrav1.OpenStackMachineSpec{ Ports: []infrav1.PortOpts{ { - Network: &infrav1.NetworkFilter{ - ID: networkuuid, + Network: &infrav1.NetworkParam{ + ID: pointer.String(networkuuid), }, }, }, @@ -330,15 +354,17 @@ func TestNetworksToPorts(t *testing.T) { afterMachineSpec: infrav1.OpenStackMachineSpec{ Ports: []infrav1.PortOpts{ { - Network: &infrav1.NetworkFilter{ - Name: "network-name", - Description: "network-description", - ProjectID: "project-id", - FilterByNeutronTags: infrav1.FilterByNeutronTags{ - Tags: []infrav1.NeutronTag{"tags"}, - TagsAny: []infrav1.NeutronTag{"tags-any"}, - NotTags: []infrav1.NeutronTag{"not-tags"}, - NotTagsAny: []infrav1.NeutronTag{"not-tags-any"}, + Network: &infrav1.NetworkParam{ + Filter: &infrav1.NetworkFilter{ + Name: "network-name", + Description: "network-description", + ProjectID: "project-id", + FilterByNeutronTags: infrav1.FilterByNeutronTags{ + Tags: []infrav1.NeutronTag{"tags"}, + TagsAny: []infrav1.NeutronTag{"tags-any"}, + NotTags: []infrav1.NeutronTag{"not-tags"}, + NotTagsAny: []infrav1.NeutronTag{"not-tags-any"}, + }, }, }, }, @@ -362,8 +388,8 @@ func TestNetworksToPorts(t *testing.T) { afterMachineSpec: infrav1.OpenStackMachineSpec{ Ports: []infrav1.PortOpts{ { - Network: &infrav1.NetworkFilter{ - ID: networkuuid, + Network: &infrav1.NetworkParam{ + ID: pointer.String(networkuuid), }, FixedIPs: []infrav1.FixedIP{ { @@ -406,8 +432,8 @@ func TestNetworksToPorts(t *testing.T) { afterMachineSpec: infrav1.OpenStackMachineSpec{ Ports: []infrav1.PortOpts{ { - Network: &infrav1.NetworkFilter{ - ID: networkuuid, + Network: &infrav1.NetworkParam{ + ID: pointer.String(networkuuid), }, FixedIPs: []infrav1.FixedIP{ { @@ -466,8 +492,8 @@ func TestNetworksToPorts(t *testing.T) { afterMachineSpec: infrav1.OpenStackMachineSpec{ Ports: []infrav1.PortOpts{ { - Network: &infrav1.NetworkFilter{ - ID: networkuuid, + Network: &infrav1.NetworkParam{ + ID: pointer.String(networkuuid), }, FixedIPs: []infrav1.FixedIP{ { @@ -478,8 +504,8 @@ func TestNetworksToPorts(t *testing.T) { }, }, { - Network: &infrav1.NetworkFilter{ - ID: networkuuid, + Network: &infrav1.NetworkParam{ + ID: pointer.String(networkuuid), }, FixedIPs: []infrav1.FixedIP{ { diff --git a/api/v1alpha6/openstackcluster_conversion.go b/api/v1alpha6/openstackcluster_conversion.go index 95131f6c3f..423adc52e3 100644 --- a/api/v1alpha6/openstackcluster_conversion.go +++ b/api/v1alpha6/openstackcluster_conversion.go @@ -164,23 +164,14 @@ func restorev1alpha6ClusterSpec(previous *OpenStackClusterSpec, dst *OpenStackCl func restorev1beta1ClusterSpec(previous *infrav1.OpenStackClusterSpec, dst *infrav1.OpenStackClusterSpec) { // Bastion is restored separately - if dst.Network.IsEmpty() { - dst.Network = previous.Network - } + restorev1beta1NetworkParam(previous.Network, dst.Network) - // Restore all fields except ID, which should have been copied over in conversion + // ExternalNetwork by filter will be been lost in down-conversion if previous.ExternalNetwork != nil { if dst.ExternalNetwork == nil { - dst.ExternalNetwork = &infrav1.NetworkFilter{} + dst.ExternalNetwork = &infrav1.NetworkParam{} } - - dst.ExternalNetwork.Name = previous.ExternalNetwork.Name - dst.ExternalNetwork.Description = previous.ExternalNetwork.Description - dst.ExternalNetwork.ProjectID = previous.ExternalNetwork.ProjectID - dst.ExternalNetwork.Tags = previous.ExternalNetwork.Tags - dst.ExternalNetwork.TagsAny = previous.ExternalNetwork.TagsAny - dst.ExternalNetwork.NotTags = previous.ExternalNetwork.NotTags - dst.ExternalNetwork.NotTagsAny = previous.ExternalNetwork.NotTagsAny + dst.ExternalNetwork.Filter = previous.ExternalNetwork.Filter } // Restore fields not present in v1alpha6 @@ -227,15 +218,15 @@ func Convert_v1alpha6_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O } if in.Network != (NetworkFilter{}) { - out.Network = &infrav1.NetworkFilter{} - if err := Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(&in.Network, out.Network, s); err != nil { + out.Network = &infrav1.NetworkParam{} + if err := Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkParam(&in.Network, out.Network, s); err != nil { return err } } if in.ExternalNetworkID != "" { - out.ExternalNetwork = &infrav1.NetworkFilter{ - ID: in.ExternalNetworkID, + out.ExternalNetwork = &infrav1.NetworkParam{ + ID: &in.ExternalNetworkID, } } @@ -294,13 +285,13 @@ func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha6_OpenStackClusterSpec(in *i } if in.Network != nil { - if err := Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(in.Network, &out.Network, s); err != nil { + if err := Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkFilter(in.Network, &out.Network, s); err != nil { return err } } - if in.ExternalNetwork != nil && in.ExternalNetwork.ID != "" { - out.ExternalNetworkID = in.ExternalNetwork.ID + if in.ExternalNetwork != nil && in.ExternalNetwork.ID != nil { + out.ExternalNetworkID = *in.ExternalNetwork.ID } if len(in.Subnets) >= 1 { diff --git a/api/v1alpha6/openstackmachine_conversion.go b/api/v1alpha6/openstackmachine_conversion.go index d0f01cac1b..1193ae0d27 100644 --- a/api/v1alpha6/openstackmachine_conversion.go +++ b/api/v1alpha6/openstackmachine_conversion.go @@ -179,7 +179,7 @@ func convertNetworksToPorts(networks []NetworkParam, s apiconversion.Scope) ([]i network := networks[i] // This will remain null if the network is not specified in NetworkParam - var networkFilter *infrav1.NetworkFilter + var networkFilter *infrav1.NetworkParam // In v1alpha6, if network.Filter resolved to multiple networks // then we would add multiple ports. It is not possible to @@ -189,12 +189,12 @@ func convertNetworksToPorts(networks []NetworkParam, s apiconversion.Scope) ([]i // create the port. switch { case network.UUID != "": - networkFilter = &infrav1.NetworkFilter{ - ID: network.UUID, + networkFilter = &infrav1.NetworkParam{ + ID: &network.UUID, } case network.Filter != (NetworkFilter{}): - networkFilter = &infrav1.NetworkFilter{} - if err := Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(&network.Filter, networkFilter, s); err != nil { + networkFilter = &infrav1.NetworkParam{} + if err := Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkParam(&network.Filter, networkFilter, s); err != nil { return nil, err } } diff --git a/api/v1alpha6/types_conversion.go b/api/v1alpha6/types_conversion.go index 6ec354ecee..bd9ad97d58 100644 --- a/api/v1alpha6/types_conversion.go +++ b/api/v1alpha6/types_conversion.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha6 import ( + "errors" "strings" apiconversion "k8s.io/apimachinery/pkg/conversion" @@ -102,27 +103,61 @@ func Convert_v1beta1_SecurityGroupFilter_To_v1alpha6_SecurityGroupFilter(in *inf /* NetworkParam, NetworkFilter */ func restorev1alpha6NetworkFilter(previous *NetworkFilter, dst *NetworkFilter) { + 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 dst.ID != "" { + dst.Name = previous.Name + dst.Description = previous.Description + dst.ProjectID = previous.ProjectID + } +} + +func restorev1beta1NetworkParam(previous *infrav1.NetworkParam, dst *infrav1.NetworkParam) { + if previous == nil || dst == nil { + return + } + + if dst.Filter != nil && previous.Filter != nil { + dst.Filter.FilterByNeutronTags = previous.Filter.FilterByNeutronTags + } } -func Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilter, out *infrav1.NetworkFilter, s apiconversion.Scope) error { - if err := autoConvert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(in, out, s); err != nil { +func Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkParam(in *NetworkFilter, out *infrav1.NetworkParam, s apiconversion.Scope) error { + if in.ID != "" { + out.ID = &in.ID + return nil + } + outFilter := &infrav1.NetworkFilter{} + if err := autoConvert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(in, outFilter, 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, &outFilter.FilterByNeutronTags) + if !outFilter.IsZero() { + out.Filter = outFilter + } return nil } -func Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(in *infrav1.NetworkFilter, out *NetworkFilter, s apiconversion.Scope) error { - if err := autoConvert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(in, out, s); err != nil { - return err +func Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkFilter(in *infrav1.NetworkParam, out *NetworkFilter, s apiconversion.Scope) error { + if in.ID != nil { + out.ID = *in.ID + return nil + } + if in.Filter != nil { + if err := autoConvert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(in.Filter, out, s); err != nil { + return err + } + infrav1.ConvertAllTagsFrom(&in.Filter.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny) } - infrav1.ConvertAllTagsFrom(&in.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny) return nil } @@ -181,9 +216,7 @@ func restorev1alpha6Port(previous *PortOpts, dst *PortOpts) { } } - if dst.Network != nil && previous.Network != nil { - restorev1alpha6NetworkFilter(previous.Network, dst.Network) - } + restorev1alpha6NetworkFilter(previous.Network, dst.Network) if len(dst.FixedIPs) == len(previous.FixedIPs) { for i := range dst.FixedIPs { @@ -392,3 +425,22 @@ func Convert_v1beta1_OpenStackIdentityReference_To_v1alpha6_OpenStackIdentityRef out.Name = in.Name return nil } + +/* Other */ + +// conversion-gen registers the following functions so we have to define them, but nothing should ever call them. +func Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(_ *NetworkFilter, _ *infrav1.NetworkFilter, _ apiconversion.Scope) error { + return errors.New("Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter should not be called") +} + +func Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(_ *infrav1.NetworkFilter, _ *NetworkFilter, _ apiconversion.Scope) error { + return errors.New("Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter should not be called") +} + +func Convert_v1alpha6_NetworkParam_To_v1beta1_NetworkParam(_ *NetworkParam, _ *infrav1.NetworkParam, _ apiconversion.Scope) error { + return errors.New("Convert_v1alpha6_NetworkParam_To_v1beta1_NetworkParam should not be called") +} + +func Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkParam(_ *infrav1.NetworkParam, _ *NetworkParam, _ apiconversion.Scope) error { + return errors.New("Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkParam should not be called") +} diff --git a/api/v1alpha6/zz_generated.conversion.go b/api/v1alpha6/zz_generated.conversion.go index b35e716ad4..34023deb82 100644 --- a/api/v1alpha6/zz_generated.conversion.go +++ b/api/v1alpha6/zz_generated.conversion.go @@ -271,6 +271,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*NetworkFilter)(nil), (*v1beta1.NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkParam(a.(*NetworkFilter), b.(*v1beta1.NetworkParam), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*NetworkParam)(nil), (*v1beta1.NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha6_NetworkParam_To_v1beta1_NetworkParam(a.(*NetworkParam), b.(*v1beta1.NetworkParam), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*Network)(nil), (*v1beta1.NetworkStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha6_Network_To_v1beta1_NetworkStatus(a.(*Network), b.(*v1beta1.NetworkStatus), scope) }); err != nil { @@ -346,6 +356,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.NetworkParam)(nil), (*NetworkFilter)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkFilter(a.(*v1beta1.NetworkParam), b.(*NetworkFilter), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1beta1.NetworkParam)(nil), (*NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkParam(a.(*v1beta1.NetworkParam), b.(*NetworkParam), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.NetworkStatusWithSubnets)(nil), (*Network)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_NetworkStatusWithSubnets_To_v1alpha6_Network(a.(*v1beta1.NetworkStatusWithSubnets), b.(*Network), scope) }); err != nil { @@ -600,7 +620,7 @@ func autoConvert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilt out.Name = in.Name out.Description = in.Description out.ProjectID = in.ProjectID - 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 @@ -612,11 +632,24 @@ func autoConvert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(in *v1beta1.Net out.Name = in.Name out.Description = in.Description out.ProjectID = in.ProjectID - out.ID = in.ID // WARNING: in.FilterByNeutronTags requires manual conversion: does not exist in peer-type return nil } +func autoConvert_v1alpha6_NetworkParam_To_v1beta1_NetworkParam(in *NetworkParam, out *v1beta1.NetworkParam, s conversion.Scope) error { + // WARNING: in.UUID requires manual conversion: does not exist in peer-type + // WARNING: in.FixedIP 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.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter) + // WARNING: in.Subnets requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_v1beta1_NetworkParam_To_v1alpha6_NetworkParam(in *v1beta1.NetworkParam, out *NetworkParam, 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.NetworkFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.NetworkFilter) + return nil +} + func autoConvert_v1alpha6_OpenStackCluster_To_v1beta1_OpenStackCluster(in *OpenStackCluster, out *v1beta1.OpenStackCluster, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha6_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(&in.Spec, &out.Spec, s); err != nil { @@ -694,7 +727,7 @@ func Convert_v1beta1_OpenStackClusterList_To_v1alpha6_OpenStackClusterList(in *v func autoConvert_v1alpha6_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *OpenStackClusterSpec, out *v1beta1.OpenStackClusterSpec, s conversion.Scope) error { // WARNING: in.CloudName requires manual conversion: does not exist in peer-type // WARNING: in.NodeCIDR requires manual conversion: does not exist in peer-type - // WARNING: in.Network requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter) + // WARNING: in.Network requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkParam) // WARNING: in.Subnet requires manual conversion: does not exist in peer-type // WARNING: in.DNSNameservers requires manual conversion: does not exist in peer-type if in.ExternalRouterIPs != nil { @@ -749,7 +782,7 @@ func autoConvert_v1alpha6_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(i func autoConvert_v1beta1_OpenStackClusterSpec_To_v1alpha6_OpenStackClusterSpec(in *v1beta1.OpenStackClusterSpec, out *OpenStackClusterSpec, s conversion.Scope) error { // WARNING: in.ManagedSubnets requires manual conversion: does not exist in peer-type // WARNING: in.Router requires manual conversion: does not exist in peer-type - // WARNING: in.Network requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.NetworkFilter) + // WARNING: in.Network requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkParam vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha6.NetworkFilter) // WARNING: in.Subnets requires manual conversion: does not exist in peer-type // WARNING: in.NetworkMTU requires manual conversion: does not exist in peer-type if in.ExternalRouterIPs != nil { @@ -1374,8 +1407,8 @@ func Convert_v1beta1_OpenStackMachineTemplateSpec_To_v1alpha6_OpenStackMachineTe func autoConvert_v1alpha6_PortOpts_To_v1beta1_PortOpts(in *PortOpts, out *v1beta1.PortOpts, s conversion.Scope) error { if in.Network != nil { in, out := &in.Network, &out.Network - *out = new(v1beta1.NetworkFilter) - if err := Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(*in, *out, s); err != nil { + *out = new(v1beta1.NetworkParam) + if err := Convert_v1alpha6_NetworkFilter_To_v1beta1_NetworkParam(*in, *out, s); err != nil { return err } } else { @@ -1419,7 +1452,7 @@ func autoConvert_v1beta1_PortOpts_To_v1alpha6_PortOpts(in *v1beta1.PortOpts, out if in.Network != nil { in, out := &in.Network, &out.Network *out = new(NetworkFilter) - if err := Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(*in, *out, s); err != nil { + if err := Convert_v1beta1_NetworkParam_To_v1alpha6_NetworkFilter(*in, *out, s); err != nil { return err } } else { diff --git a/api/v1alpha7/conversion_test.go b/api/v1alpha7/conversion_test.go index a2c770984f..ee12616e8e 100644 --- a/api/v1alpha7/conversion_test.go +++ b/api/v1alpha7/conversion_test.go @@ -68,6 +68,14 @@ func TestFuzzyConversion(t *testing.T) { return ret } + nonEmptyString := func(c fuzz.Continue) string { + for { + if s := c.RandString(); s != "" { + return s + } + } + } + fuzzerFuncs := func(_ runtimeserializer.CodecFactory) []interface{} { return []interface{}{ func(spec *infrav1.OpenStackClusterSpec, c fuzz.Continue) { @@ -194,6 +202,22 @@ func TestFuzzyConversion(t *testing.T) { filter.NotTags = filterInvalidTags(filter.NotTags) filter.NotTagsAny = filterInvalidTags(filter.NotTagsAny) }, + + // v1beta1 network param contains exactly one of ID or filter + func(param *infrav1.NetworkParam, c fuzz.Continue) { + if c.RandBool() { + id := nonEmptyString(c) + param.ID = &id + param.Filter = nil + } else { + filter := infrav1.NetworkFilter{} + for filter.IsZero() { + c.FuzzNoCustom(&filter) + } + param.Filter = &filter + param.ID = nil + } + }, } } diff --git a/api/v1alpha7/openstackcluster_conversion.go b/api/v1alpha7/openstackcluster_conversion.go index 6cbd9a5118..47b13f903b 100644 --- a/api/v1alpha7/openstackcluster_conversion.go +++ b/api/v1alpha7/openstackcluster_conversion.go @@ -169,29 +169,28 @@ func restorev1alpha7ClusterSpec(previous *OpenStackClusterSpec, dst *OpenStackCl } func restorev1beta1ClusterSpec(previous *infrav1.OpenStackClusterSpec, dst *infrav1.OpenStackClusterSpec) { + if previous == nil || dst == nil { + return + } + // Bastion is restored separately - if dst.Network.IsEmpty() { + if dst.Network == nil { dst.Network = previous.Network } - // Restore all fields except ID, which should have been copied over in conversion + // ExternalNetwork by filter will be been lost in down-conversion if previous.ExternalNetwork != nil { if dst.ExternalNetwork == nil { - dst.ExternalNetwork = &infrav1.NetworkFilter{} + dst.ExternalNetwork = &infrav1.NetworkParam{} } - - dst.ExternalNetwork.Name = previous.ExternalNetwork.Name - dst.ExternalNetwork.Description = previous.ExternalNetwork.Description - dst.ExternalNetwork.ProjectID = previous.ExternalNetwork.ProjectID - dst.ExternalNetwork.Tags = previous.ExternalNetwork.Tags - dst.ExternalNetwork.TagsAny = previous.ExternalNetwork.TagsAny - dst.ExternalNetwork.NotTags = previous.ExternalNetwork.NotTags - dst.ExternalNetwork.NotTagsAny = previous.ExternalNetwork.NotTagsAny + dst.ExternalNetwork.Filter = previous.ExternalNetwork.Filter } dst.DisableExternalNetwork = previous.DisableExternalNetwork + restorev1beta1NetworkParam(previous.Network, dst.Network) + if len(previous.Subnets) > 1 { dst.Subnets = append(dst.Subnets, previous.Subnets[1:]...) } @@ -231,15 +230,15 @@ func Convert_v1alpha7_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O } if in.Network != (NetworkFilter{}) { - out.Network = &infrav1.NetworkFilter{} - if err := Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(&in.Network, out.Network, s); err != nil { + out.Network = &infrav1.NetworkParam{} + if err := Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkParam(&in.Network, out.Network, s); err != nil { return err } } if in.ExternalNetworkID != "" { - out.ExternalNetwork = &infrav1.NetworkFilter{ - ID: in.ExternalNetworkID, + out.ExternalNetwork = &infrav1.NetworkParam{ + ID: &in.ExternalNetworkID, } } @@ -298,13 +297,13 @@ func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha7_OpenStackClusterSpec(in *i } if in.Network != nil { - if err := Convert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(in.Network, &out.Network, s); err != nil { + if err := Convert_v1beta1_NetworkParam_To_v1alpha7_NetworkFilter(in.Network, &out.Network, s); err != nil { return err } } - if in.ExternalNetwork != nil && in.ExternalNetwork.ID != "" { - out.ExternalNetworkID = in.ExternalNetwork.ID + if in.ExternalNetwork != nil && in.ExternalNetwork.ID != nil { + out.ExternalNetworkID = *in.ExternalNetwork.ID } if len(in.Subnets) >= 1 { diff --git a/api/v1alpha7/types_conversion.go b/api/v1alpha7/types_conversion.go index 98bdd6df26..dfaf2bd804 100644 --- a/api/v1alpha7/types_conversion.go +++ b/api/v1alpha7/types_conversion.go @@ -63,27 +63,63 @@ func Convert_v1beta1_SecurityGroupFilter_To_v1alpha7_SecurityGroupFilter(in *inf /* NetworkFilter */ func restorev1alpha7NetworkFilter(previous *NetworkFilter, dst *NetworkFilter) { + 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 lost all over filter params + if dst.ID != "" { + dst.Name = previous.Name + dst.Description = previous.Description + dst.ProjectID = previous.ProjectID + } +} + +func restorev1beta1NetworkParam(previous *infrav1.NetworkParam, dst *infrav1.NetworkParam) { + if previous == nil || dst == nil { + return + } + + if dst.Filter != nil && previous.Filter != nil { + dst.Filter.FilterByNeutronTags = previous.Filter.FilterByNeutronTags + } } -func Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilter, out *infrav1.NetworkFilter, s apiconversion.Scope) error { - if err := autoConvert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(in, out, s); err != nil { +func Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkParam(in *NetworkFilter, out *infrav1.NetworkParam, s apiconversion.Scope) error { + if in.ID != "" { + out.ID = &in.ID + return nil + } + outFilter := &infrav1.NetworkFilter{} + if err := autoConvert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(in, outFilter, 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, &outFilter.FilterByNeutronTags) + if !outFilter.IsZero() { + out.Filter = outFilter + } return nil } -func Convert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(in *infrav1.NetworkFilter, out *NetworkFilter, s apiconversion.Scope) error { - if err := autoConvert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(in, out, s); err != nil { - return err +func Convert_v1beta1_NetworkParam_To_v1alpha7_NetworkFilter(in *infrav1.NetworkParam, out *NetworkFilter, s apiconversion.Scope) error { + if in.ID != nil { + out.ID = *in.ID + return nil + } + + if in.Filter != nil { + if err := autoConvert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(in.Filter, out, s); err != nil { + return err + } + infrav1.ConvertAllTagsFrom(&in.Filter.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny) } - infrav1.ConvertAllTagsFrom(&in.FilterByNeutronTags, &out.Tags, &out.TagsAny, &out.NotTags, &out.NotTagsAny) return nil } @@ -167,6 +203,8 @@ func restorev1alpha7Port(previous *PortOpts, dst *PortOpts) { } func restorev1beta1Port(previous *infrav1.PortOpts, dst *infrav1.PortOpts) { + restorev1beta1NetworkParam(previous.Network, dst.Network) + optional.RestoreString(&previous.NameSuffix, &dst.NameSuffix) optional.RestoreString(&previous.Description, &dst.Description) optional.RestoreString(&previous.MACAddress, &dst.MACAddress) @@ -351,3 +389,14 @@ func Convert_v1beta1_OpenStackIdentityReference_To_v1alpha7_OpenStackIdentityRef out.Name = in.Name return nil } + +/* Other */ + +// conversion-gen registers the following functions so we have to define them, but nothing should ever call them. +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") +} + +func Convert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(_ *infrav1.NetworkFilter, _ *NetworkFilter, _ apiconversion.Scope) error { + return errors.New("Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter should not be called") +} diff --git a/api/v1alpha7/zz_generated.conversion.go b/api/v1alpha7/zz_generated.conversion.go index 5646dbe6f8..8b070e14bf 100644 --- a/api/v1alpha7/zz_generated.conversion.go +++ b/api/v1alpha7/zz_generated.conversion.go @@ -336,6 +336,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*NetworkFilter)(nil), (*v1beta1.NetworkParam)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkParam(a.(*NetworkFilter), b.(*v1beta1.NetworkParam), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*OpenStackClusterSpec)(nil), (*v1beta1.OpenStackClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha7_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(a.(*OpenStackClusterSpec), b.(*v1beta1.OpenStackClusterSpec), scope) }); err != nil { @@ -391,6 +396,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.NetworkParam)(nil), (*NetworkFilter)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_NetworkParam_To_v1alpha7_NetworkFilter(a.(*v1beta1.NetworkParam), b.(*NetworkFilter), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.OpenStackClusterSpec)(nil), (*OpenStackClusterSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_OpenStackClusterSpec_To_v1alpha7_OpenStackClusterSpec(a.(*v1beta1.OpenStackClusterSpec), b.(*OpenStackClusterSpec), scope) }); err != nil { @@ -754,7 +764,7 @@ func autoConvert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilt out.Name = in.Name out.Description = in.Description out.ProjectID = in.ProjectID - 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 @@ -766,7 +776,6 @@ func autoConvert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(in *v1beta1.Net out.Name = in.Name out.Description = in.Description out.ProjectID = in.ProjectID - out.ID = in.ID // WARNING: in.FilterByNeutronTags requires manual conversion: does not exist in peer-type return nil } @@ -907,7 +916,7 @@ func autoConvert_v1alpha7_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(i } else { out.Router = nil } - // WARNING: in.Network requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter) + // WARNING: in.Network requires manual conversion: inconvertible types (sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7.NetworkFilter vs *sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkParam) // WARNING: in.Subnet requires manual conversion: does not exist in peer-type if err := optional.Convert_int_To_optional_Int(&in.NetworkMTU, &out.NetworkMTU, s); err != nil { return err @@ -973,7 +982,7 @@ func autoConvert_v1beta1_OpenStackClusterSpec_To_v1alpha7_OpenStackClusterSpec(i } else { out.Router = nil } - // WARNING: in.Network requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkFilter vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7.NetworkFilter) + // WARNING: in.Network requires manual conversion: inconvertible types (*sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1.NetworkParam vs sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7.NetworkFilter) // WARNING: in.Subnets requires manual conversion: does not exist in peer-type if err := optional.Convert_optional_Int_To_int(&in.NetworkMTU, &out.NetworkMTU, s); err != nil { return err @@ -1574,8 +1583,8 @@ func Convert_v1beta1_OpenStackMachineTemplateSpec_To_v1alpha7_OpenStackMachineTe func autoConvert_v1alpha7_PortOpts_To_v1beta1_PortOpts(in *PortOpts, out *v1beta1.PortOpts, s conversion.Scope) error { if in.Network != nil { in, out := &in.Network, &out.Network - *out = new(v1beta1.NetworkFilter) - if err := Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(*in, *out, s); err != nil { + *out = new(v1beta1.NetworkParam) + if err := Convert_v1alpha7_NetworkFilter_To_v1beta1_NetworkParam(*in, *out, s); err != nil { return err } } else { @@ -1617,7 +1626,7 @@ func autoConvert_v1beta1_PortOpts_To_v1alpha7_PortOpts(in *v1beta1.PortOpts, out if in.Network != nil { in, out := &in.Network, &out.Network *out = new(NetworkFilter) - if err := Convert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(*in, *out, s); err != nil { + if err := Convert_v1beta1_NetworkParam_To_v1alpha7_NetworkFilter(*in, *out, s); err != nil { return err } } else { diff --git a/api/v1beta1/openstackcluster_types.go b/api/v1beta1/openstackcluster_types.go index 06d23de650..35a2bf5505 100644 --- a/api/v1beta1/openstackcluster_types.go +++ b/api/v1beta1/openstackcluster_types.go @@ -48,7 +48,7 @@ type OpenStackClusterSpec struct { // Network specifies an existing network to use if no ManagedSubnets // are specified. // +optional - Network *NetworkFilter `json:"network,omitempty"` + Network *NetworkParam `json:"network,omitempty"` // Subnets specifies existing subnets to use if not ManagedSubnets are // specified. All subnets must be in the network specified by Network. @@ -86,7 +86,7 @@ type OpenStackClusterSpec struct { // If ExternalNetwork is not defined and there are no external networks // the controller will proceed as though DisableExternalNetwork was set. // +optional - ExternalNetwork *NetworkFilter `json:"externalNetwork,omitempty"` + ExternalNetwork *NetworkParam `json:"externalNetwork,omitempty"` // DisableExternalNetwork specifies whether or not to attempt to connect the cluster // to an external network. This allows for the creation of clusters when connecting diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index a8a9288393..935f632561 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -84,6 +84,10 @@ type FilterByNeutronTags struct { NotTagsAny []NeutronTag `json:"notTagsAny,omitempty"` } +func (f *FilterByNeutronTags) IsZero() bool { + return f == nil || len(f.Tags) == 0 && len(f.TagsAny) == 0 && len(f.NotTags) == 0 && len(f.NotTagsAny) == 0 +} + type SecurityGroupFilter struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` @@ -93,27 +97,38 @@ type SecurityGroupFilter struct { FilterByNeutronTags `json:",inline"` } +// NetworkParam specifies an OpenStack network. It may be specified by either ID or Filter, but not both. +// +kubebuilder:validation:MaxProperties:=1 +// +kubebuilder:validation:MinProperties:=1 +type NetworkParam struct { + // ID is the ID of the network to use. If ID is provided, the other filters cannot be provided. Must be in UUID format. + // +kubebuilder:validation:Format:=uuid + // +optional + ID optional.String `json:"id,omitempty"` + + // Filter specifies a filter to select an OpenStack network. If provided, cannot be empty. + // +optional + Filter *NetworkFilter `json:"filter,omitempty"` +} + +// NetworkFilter specifies a query to select an OpenStack network. At least one property must be set. +// +kubebuilder:validation:MinProperties:=1 type NetworkFilter struct { Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` ProjectID string `json:"projectID,omitempty"` - ID string `json:"id,omitempty"` FilterByNeutronTags `json:",inline"` } -func (networkFilter *NetworkFilter) IsEmpty() bool { +func (networkFilter *NetworkFilter) IsZero() bool { if networkFilter == nil { return true } return networkFilter.Name == "" && networkFilter.Description == "" && networkFilter.ProjectID == "" && - networkFilter.ID == "" && - len(networkFilter.Tags) == 0 && - len(networkFilter.TagsAny) == 0 && - len(networkFilter.NotTags) == 0 && - len(networkFilter.NotTagsAny) == 0 + networkFilter.FilterByNeutronTags.IsZero() } type SubnetFilter struct { @@ -169,7 +184,7 @@ type PortOpts struct { // Network is a query for an openstack network that the port will be created or discovered on. // This will fail if the query returns more than one network. // +optional - Network *NetworkFilter `json:"network,omitempty"` + Network *NetworkParam `json:"network,omitempty"` // Description is a human-readable description for the port. // +optional diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 892e950daf..a64cad9843 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -409,6 +409,31 @@ func (in *NetworkFilter) DeepCopy() *NetworkFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkParam) DeepCopyInto(out *NetworkParam) { + *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(NetworkFilter) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkParam. +func (in *NetworkParam) DeepCopy() *NetworkParam { + if in == nil { + return nil + } + out := new(NetworkParam) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) { *out = *in @@ -528,7 +553,7 @@ func (in *OpenStackClusterSpec) DeepCopyInto(out *OpenStackClusterSpec) { } if in.Network != nil { in, out := &in.Network, &out.Network - *out = new(NetworkFilter) + *out = new(NetworkParam) (*in).DeepCopyInto(*out) } if in.Subnets != nil { @@ -552,7 +577,7 @@ func (in *OpenStackClusterSpec) DeepCopyInto(out *OpenStackClusterSpec) { } if in.ExternalNetwork != nil { in, out := &in.ExternalNetwork, &out.ExternalNetwork - *out = new(NetworkFilter) + *out = new(NetworkParam) (*in).DeepCopyInto(*out) } if in.DisableExternalNetwork != nil { @@ -1090,7 +1115,7 @@ func (in *PortOpts) DeepCopyInto(out *PortOpts) { *out = *in if in.Network != nil { in, out := &in.Network, &out.Network - *out = new(NetworkFilter) + *out = new(NetworkParam) (*in).DeepCopyInto(*out) } if in.Description != nil { 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 abdbf1c5da..ce8db36caf 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml @@ -5234,68 +5234,80 @@ spec: description: |- Network is a query for an openstack network that the port will be created or discovered on. This will fail if the query returns more than one network. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select + an OpenStack network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. + If ID is provided, the other filters cannot be + provided. Must be in UUID format. + format: uuid 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 profile: description: |- @@ -5663,68 +5675,79 @@ spec: If ExternalNetwork is not defined and there are no external networks the controller will proceed as though DisableExternalNetwork was set. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select an OpenStack + network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. If ID is provided, + the other filters cannot be provided. Must be in UUID format. + format: uuid 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 externalRouterIPs: description: |- @@ -5978,68 +6001,79 @@ spec: description: |- Network specifies an existing network to use if no ManagedSubnets are specified. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select an OpenStack + network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. If ID is provided, + the other filters cannot be provided. Must be in UUID format. + format: uuid 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 networkMTU: description: |- 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 66b4e12174..72e9aabe49 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml @@ -2665,68 +2665,81 @@ spec: description: |- Network is a query for an openstack network that the port will be created or discovered on. This will fail if the query returns more than one network. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to + select an OpenStack network. If provided, + cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network + to use. If ID is provided, the other filters + cannot be provided. Must be in UUID format. + format: uuid 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 profile: description: |- @@ -3097,68 +3110,80 @@ spec: If ExternalNetwork is not defined and there are no external networks the controller will proceed as though DisableExternalNetwork was set. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select an OpenStack + network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. If ID + is provided, the other filters cannot be provided. Must + be in UUID format. + format: uuid 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 externalRouterIPs: description: |- @@ -3414,68 +3439,80 @@ spec: description: |- Network specifies an existing network to use if no ManagedSubnets are specified. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select an OpenStack + network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. If ID + is provided, the other filters cannot be provided. Must + be in UUID format. + format: uuid 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 networkMTU: description: |- diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml index 75281a6f06..de118da2df 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackfloatingippools.yaml @@ -45,68 +45,79 @@ spec: description: FloatingIPNetwork is the external network to use for floating ips, if there's only one external network it will be used by default + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select an OpenStack + network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. If ID is provided, + the other filters cannot be provided. Must be in UUID format. + format: uuid 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 identityRef: description: IdentityRef is a reference to a identity to be used when 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 3d866edc37..bc3d9658b0 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachines.yaml @@ -2011,68 +2011,80 @@ spec: description: |- Network is a query for an openstack network that the port will be created or discovered on. This will fail if the query returns more than one network. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select an OpenStack + network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. If ID is + provided, the other filters cannot be provided. Must be + in UUID format. + format: uuid 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 profile: description: |- 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 12d3b1ea40..7c481ff2b8 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackmachinetemplates.yaml @@ -1688,68 +1688,80 @@ spec: description: |- Network is a query for an openstack network that the port will be created or discovered on. This will fail if the query returns more than one network. + maxProperties: 1 + minProperties: 1 properties: - description: - type: string + filter: + description: Filter specifies a filter to select + an OpenStack network. If provided, cannot be empty. + minProperties: 1 + properties: + description: + 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 ID of the network to use. + If ID is provided, the other filters cannot be + provided. Must be in UUID format. + format: uuid 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 profile: description: |- diff --git a/controllers/openstackcluster_controller.go b/controllers/openstackcluster_controller.go index f1ab14b09c..59d6321a59 100644 --- a/controllers/openstackcluster_controller.go +++ b/controllers/openstackcluster_controller.go @@ -51,7 +51,6 @@ import ( "sigs.k8s.io/cluster-api-provider-openstack/pkg/cloud/services/networking" "sigs.k8s.io/cluster-api-provider-openstack/pkg/scope" utils "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/controllers" - "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/filterconvert" "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/names" ) @@ -649,20 +648,13 @@ func reconcilePreExistingNetworkComponents(scope *scope.WithLogger, networkingSe openStackCluster.Status.Network = &infrav1.NetworkStatusWithSubnets{} } - if !openStackCluster.Spec.Network.IsEmpty() { - netOpts := filterconvert.NetworkFilterToListOpts(openStackCluster.Spec.Network) - networkList, err := networkingService.GetNetworksByFilter(&netOpts) + if openStackCluster.Spec.Network != nil { + network, err := networkingService.GetNetworkByParam(openStackCluster.Spec.Network) if err != nil { handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to find network: %w", err)) - return fmt.Errorf("error fetching networks: %w", err) - } - if len(networkList) == 0 { - handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to find any network")) - return fmt.Errorf("failed to find any network") - } - if len(networkList) == 1 { - setClusterNetwork(openStackCluster, &networkList[0]) + return fmt.Errorf("error fetching cluster network: %w", err) } + setClusterNetwork(openStackCluster, network) } subnets, err := getClusterSubnets(networkingService, openStackCluster) diff --git a/controllers/openstackcluster_controller_test.go b/controllers/openstackcluster_controller_test.go index b738cafe47..1de32fa013 100644 --- a/controllers/openstackcluster_controller_test.go +++ b/controllers/openstackcluster_controller_test.go @@ -26,7 +26,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" "github.com/gophercloud/gophercloud/openstack/networking/v2/ports" @@ -506,6 +505,7 @@ var _ = Describe("OpenStackCluster controller", func() { err = deleteBastion(scope, capiCluster, testCluster) Expect(err).To(BeNil()) }) + It("should implicitly filter cluster subnets by cluster network", func() { const externalNetworkID = "a42211a2-4d2c-426f-9413-830e4b4abbbc" const clusterNetworkID = "6c90b532-7ba0-418a-a276-5ae55060b5b0" @@ -519,11 +519,11 @@ var _ = Describe("OpenStackCluster controller", func() { }, DisableAPIServerFloatingIP: pointer.Bool(true), APIServerFixedIP: pointer.String("10.0.0.1"), - ExternalNetwork: &infrav1.NetworkFilter{ - ID: externalNetworkID, + ExternalNetwork: &infrav1.NetworkParam{ + ID: pointer.String(externalNetworkID), }, - Network: &infrav1.NetworkFilter{ - ID: clusterNetworkID, + Network: &infrav1.NetworkParam{ + ID: pointer.String(clusterNetworkID), }, } testCluster.Status = infrav1.OpenStackClusterStatus{ @@ -550,26 +550,15 @@ var _ = Describe("OpenStackCluster controller", func() { networkClientRecorder := mockScopeFactory.NetworkClient.EXPECT() // Fetch external network - networkClientRecorder.ListNetwork(external.ListOptsExt{ - ListOptsBuilder: networks.ListOpts{ - ID: externalNetworkID, - }, - External: pointer.Bool(true), - }).Return([]networks.Network{ - { - ID: externalNetworkID, - Name: "external-network", - }, + networkClientRecorder.GetNetwork(externalNetworkID).Return(&networks.Network{ + ID: externalNetworkID, + Name: "external-network", }, nil) // Fetch cluster network - networkClientRecorder.ListNetwork(&networks.ListOpts{ - ID: clusterNetworkID, - }).Return([]networks.Network{ - { - ID: clusterNetworkID, - Name: "cluster-network", - }, + networkClientRecorder.GetNetwork(clusterNetworkID).Return(&networks.Network{ + ID: clusterNetworkID, + Name: "cluster-network", }, nil) // Fetching cluster subnets should be filtered by cluster network id @@ -600,11 +589,11 @@ var _ = Describe("OpenStackCluster controller", func() { }, DisableAPIServerFloatingIP: pointer.Bool(true), APIServerFixedIP: pointer.String("10.0.0.1"), - ExternalNetwork: &infrav1.NetworkFilter{ - ID: externalNetworkID, + ExternalNetwork: &infrav1.NetworkParam{ + ID: pointer.String(externalNetworkID), }, - Network: &infrav1.NetworkFilter{ - ID: clusterNetworkID, + Network: &infrav1.NetworkParam{ + ID: pointer.String(clusterNetworkID), }, Subnets: []infrav1.SubnetFilter{ {ID: clusterSubnets[0]}, @@ -635,26 +624,15 @@ var _ = Describe("OpenStackCluster controller", func() { networkClientRecorder := mockScopeFactory.NetworkClient.EXPECT() // Fetch external network - networkClientRecorder.ListNetwork(external.ListOptsExt{ - ListOptsBuilder: networks.ListOpts{ - ID: externalNetworkID, - }, - External: pointer.Bool(true), - }).Return([]networks.Network{ - { - ID: externalNetworkID, - Name: "external-network", - }, + networkClientRecorder.GetNetwork(externalNetworkID).Return(&networks.Network{ + ID: externalNetworkID, + Name: "external-network", }, nil) // Fetch cluster network - networkClientRecorder.ListNetwork(&networks.ListOpts{ - ID: clusterNetworkID, - }).Return([]networks.Network{ - { - ID: clusterNetworkID, - Name: "cluster-network", - }, + networkClientRecorder.GetNetwork(clusterNetworkID).Return(&networks.Network{ + ID: clusterNetworkID, + Name: "cluster-network", }, nil) networkClientRecorder.GetSubnet(clusterSubnets[0]).Return(&subnets.Subnet{ diff --git a/controllers/openstackfloatingippool_controller.go b/controllers/openstackfloatingippool_controller.go index f002752111..01e496d636 100644 --- a/controllers/openstackfloatingippool_controller.go +++ b/controllers/openstackfloatingippool_controller.go @@ -22,7 +22,6 @@ import ( "fmt" "time" - "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -44,7 +43,6 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" "sigs.k8s.io/cluster-api-provider-openstack/pkg/cloud/services/networking" "sigs.k8s.io/cluster-api-provider-openstack/pkg/scope" - "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/filterconvert" ) const ( @@ -400,23 +398,15 @@ func (r *OpenStackFloatingIPPoolReconciler) reconcileFloatingIPNetwork(scope *sc return err } - netListOpts := external.ListOptsExt{ - ListOptsBuilder: filterconvert.NetworkFilterToListOpts(&pool.Spec.FloatingIPNetwork), - External: pointer.Bool(true), - } - - networkList, err := networkingService.GetNetworksByFilter(&netListOpts) + network, err := networkingService.GetNetworkByParam(&pool.Spec.FloatingIPNetwork) if err != nil { return fmt.Errorf("failed to find network: %w", err) } - if len(networkList) > 1 { - return fmt.Errorf("found multiple networks, expects filter to match one (result: %v)", networkList) - } pool.Status.FloatingIPNetwork = &infrav1.NetworkStatus{ - ID: networkList[0].ID, - Name: networkList[0].Name, - Tags: networkList[0].Tags, + ID: network.ID, + Name: network.Name, + Tags: network.Tags, } return nil } diff --git a/docs/book/src/api/v1beta1/api.md b/docs/book/src/api/v1beta1/api.md index fc84797f7a..4972fb0eb2 100644 --- a/docs/book/src/api/v1beta1/api.md +++ b/docs/book/src/api/v1beta1/api.md @@ -102,8 +102,8 @@ specified. If specified, no new router will be created.
network
externalNetwork
(Appears on: -OpenStackClusterSpec, -PortOpts) +NetworkParam)
+
NetworkFilter specifies a query to select an OpenStack network. At least one property must be set.
+FilterByNeutronTags + + +FilterByNeutronTags + + + |
+
+
+(Members of |
+
+(Appears on: +OpenStackClusterSpec, +PortOpts) +
++
NetworkParam specifies an OpenStack network. It may be specified by either ID or Filter, but not both.
+ +Field | +Description | +
---|---|
id string |
+(Optional)
+ ID is the ID of the network to use. If ID is provided, the other filters cannot be provided. Must be in UUID format. |
-FilterByNeutronTags + filter - -FilterByNeutronTags + +NetworkFilter |
-
-(Members of Filter specifies a filter to select an OpenStack network. If provided, cannot be empty. |
network - -NetworkFilter + +NetworkParam |
@@ -2100,8 +2136,8 @@ This is necessary if the router needs a fixed ip in a specific subnet.
externalNetwork - -NetworkFilter + +NetworkParam |
@@ -2619,8 +2655,8 @@ specified. If specified, no new router will be created.
network - -NetworkFilter + +NetworkParam |
@@ -2682,8 +2718,8 @@ This is necessary if the router needs a fixed ip in a specific subnet.
externalNetwork - -NetworkFilter + +NetworkParam |
@@ -3654,8 +3690,8 @@ OpenStackMachineTemplateResource
network - -NetworkFilter + +NetworkParam |
diff --git a/pkg/cloud/services/compute/referenced_resources_test.go b/pkg/cloud/services/compute/referenced_resources_test.go
index 1f13ce5427..5d3c3455d7 100644
--- a/pkg/cloud/services/compute/referenced_resources_test.go
+++ b/pkg/cloud/services/compute/referenced_resources_test.go
@@ -128,8 +128,8 @@ func Test_ResolveReferencedMachineResources(t *testing.T) {
Image: infrav1.ImageFilter{ID: pointer.String(imageID1)},
Ports: []infrav1.PortOpts{
{
- Network: &infrav1.NetworkFilter{
- ID: networkID2,
+ Network: &infrav1.NetworkParam{
+ ID: pointer.String(networkID2),
},
},
},
diff --git a/pkg/cloud/services/networking/network.go b/pkg/cloud/services/networking/network.go
index fbee4d4b10..4192d05e35 100644
--- a/pkg/cloud/services/networking/network.go
+++ b/pkg/cloud/services/networking/network.go
@@ -17,6 +17,7 @@ limitations under the License.
package networking
import (
+ "errors"
"fmt"
"github.com/gophercloud/gophercloud"
@@ -78,42 +79,45 @@ func (c createOpts) ToNetworkCreateMap() (map[string]interface{}, error) {
// - no external network was given in the cluster spec and no external network was found
// - the user has set OpenStackCluster.Spec.DisableExternalNetwork to true.
func (s *Service) ReconcileExternalNetwork(openStackCluster *infrav1.OpenStackCluster) error {
- var listOpts external.ListOptsExt
-
if pointer.BoolDeref(openStackCluster.Spec.DisableExternalNetwork, false) {
s.scope.Logger().Info("External network is disabled - proceeding with internal network only")
openStackCluster.Status.ExternalNetwork = nil
return nil
}
- listOpts = external.ListOptsExt{
- ListOptsBuilder: filterconvert.NetworkFilterToListOpts(openStackCluster.Spec.ExternalNetwork),
- External: pointer.Bool(true),
- }
- networkList, err := s.client.ListNetwork(listOpts)
- if err != nil {
- return err
- }
+ var network *networks.Network
+ if openStackCluster.Spec.ExternalNetwork == nil {
+ // No external network specified in the cluster spec. Default behaviour: query all external networks.
+ // * If there's only one, use that.
+ // * If there's none don't use an external network.
+ // * If there's more than one it's an error.
- switch len(networkList) {
- case 0:
- if openStackCluster.Spec.ExternalNetwork == nil {
- // Not finding an external network is fine if ExternalNetwork is not set
+ // Empty NetworkFilter will query all networks
+ var err error
+ network, err = s.getNetworkByFilter(&infrav1.NetworkFilter{}, ExternalNetworksOnly)
+ if errors.Is(err, ErrNoMatches) {
openStackCluster.Status.ExternalNetwork = nil
s.scope.Logger().Info("No external network found - proceeding with internal network only")
return nil
}
- return fmt.Errorf("no external network found")
- case 1:
- openStackCluster.Status.ExternalNetwork = &infrav1.NetworkStatus{
- ID: networkList[0].ID,
- Name: networkList[0].Name,
- Tags: networkList[0].Tags,
+ if err != nil {
+ return fmt.Errorf("failed to get external network: %w", err)
}
- s.scope.Logger().Info("External network found", "id", networkList[0].ID)
- return nil
+ } else {
+ var err error
+ network, err = s.GetNetworkByParam(openStackCluster.Spec.ExternalNetwork, ExternalNetworksOnly)
+ if err != nil {
+ return fmt.Errorf("failed to get external network: %w", err)
+ }
+ }
+
+ openStackCluster.Status.ExternalNetwork = &infrav1.NetworkStatus{
+ ID: network.ID,
+ Name: network.Name,
+ Tags: network.Tags,
}
- return fmt.Errorf("found %d external networks, which should not happen", len(networkList))
+ s.scope.Logger().Info("External network found", "id", network.ID)
+ return nil
}
func (s *Service) ReconcileNetwork(openStackCluster *infrav1.OpenStackCluster, clusterResourceName string) error {
@@ -290,32 +294,66 @@ func (s *Service) getNetworkByName(networkName string) (networks.Network, error)
return networks.Network{}, fmt.Errorf("found %d networks with the name %s, which should not happen", len(networkList), networkName)
}
-// GetNetworksByFilter retrieves networks by querying openstack with filters.
-func (s *Service) GetNetworksByFilter(opts networks.ListOptsBuilder) ([]networks.Network, error) {
- if opts == nil {
- return nil, fmt.Errorf("no Filters were passed")
+type GetNetworkOpts func(networks.ListOptsBuilder) networks.ListOptsBuilder
+
+func ExternalNetworksOnly(opts networks.ListOptsBuilder) networks.ListOptsBuilder {
+ return &external.ListOptsExt{
+ ListOptsBuilder: opts,
+ External: pointer.Bool(true),
}
- networkList, err := s.client.ListNetwork(opts)
+}
+
+// getNetworksByFilter retrieves networks by querying openstack with filters.
+func (s *Service) getNetworkByFilter(filter *infrav1.NetworkFilter, opts ...GetNetworkOpts) (*networks.Network, error) {
+ var listOpts networks.ListOptsBuilder
+ listOpts = filterconvert.NetworkFilterToListOpts(filter)
+ for _, opt := range opts {
+ listOpts = opt(listOpts)
+ }
+
+ networks, err := s.client.ListNetwork(listOpts)
if err != nil {
return nil, err
}
- if len(networkList) == 0 {
- return nil, fmt.Errorf("no networks could be found with the filters provided")
+ if len(networks) == 0 {
+ return nil, ErrNoMatches
+ }
+ if len(networks) > 1 {
+ return nil, ErrMultipleMatches
}
- return networkList, nil
+ return &networks[0], nil
}
-// GetNetworkIDsByFilter retrieves network ids by querying openstack with filters.
-func (s *Service) GetNetworkIDsByFilter(opts networks.ListOptsBuilder) ([]string, error) {
- nets, err := s.GetNetworksByFilter(opts)
- if err != nil {
- return nil, err
+// GetNetworkByParam gets the network specified by the given NetworkParam.
+func (s *Service) GetNetworkByParam(param *infrav1.NetworkParam, opts ...GetNetworkOpts) (*networks.Network, error) {
+ if param.ID != nil {
+ return s.GetNetworkByID(*param.ID)
}
- ids := []string{}
- for _, network := range nets {
- ids = append(ids, network.ID)
+
+ if param.Filter == nil {
+ return nil, errors.New("no filter or ID provided")
+ }
+
+ return s.getNetworkByFilter(param.Filter, opts...)
+}
+
+// GetNetworkIDByParam returns the ID of the network specified by the given
+// NetworkParam. It does not make an OpenStack call if the network is specified
+// by ID.
+func (s *Service) GetNetworkIDByParam(param *infrav1.NetworkParam, opts ...GetNetworkOpts) (string, error) {
+ if param.ID != nil {
+ return *param.ID, nil
+ }
+
+ if param.Filter == nil {
+ return "", errors.New("no filter or ID provided")
+ }
+
+ network, err := s.getNetworkByFilter(param.Filter, opts...)
+ if err != nil {
+ return "", err
}
- return ids, nil
+ return network.ID, nil
}
// GetSubnetsByFilter gets the id of a subnet by querying openstack with filters.
diff --git a/pkg/cloud/services/networking/network_test.go b/pkg/cloud/services/networking/network_test.go
index ff772ffe76..41fa452838 100644
--- a/pkg/cloud/services/networking/network_test.go
+++ b/pkg/cloud/services/networking/network_test.go
@@ -21,6 +21,7 @@ import (
"github.com/go-logr/logr/testr"
"github.com/golang/mock/gomock"
+ "github.com/google/go-cmp/cmp"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external"
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
@@ -205,16 +206,26 @@ func Test_ReconcileNetwork(t *testing.T) {
}
func Test_ReconcileExternalNetwork(t *testing.T) {
- mockCtrl := gomock.NewController(t)
- defer mockCtrl.Finish()
-
fakeNetworkID := "d08803fc-2fa5-4179-b9f7-8c43d0af2fe6"
fakeNetworkname := "external-network"
+ // Use gomega to match the ListOptsBuilder argument
+ getExternalNetwork := func(g Gomega, listOpts networks.ListOpts, ret []networks.Network) func(networks.ListOptsBuilder) ([]networks.Network, error) {
+ return func(opts networks.ListOptsBuilder) ([]networks.Network, error) {
+ expected := &external.ListOptsExt{
+ ListOptsBuilder: listOpts,
+ External: pointer.Bool(true),
+ }
+ g.Expect(opts).To(Equal(expected), cmp.Diff(opts, expected))
+
+ return ret, nil
+ }
+ }
+
tests := []struct {
name string
openStackCluster *infrav1.OpenStackCluster
- expect func(m *mock.MockNetworkClientMockRecorder)
+ expect func(g Gomega, m *mock.MockNetworkClientMockRecorder)
want *infrav1.OpenStackCluster
wantErr bool
}{
@@ -222,28 +233,21 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
name: "reconcile external network by ID",
openStackCluster: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
- ExternalNetwork: &infrav1.NetworkFilter{
- ID: fakeNetworkID,
+ ExternalNetwork: &infrav1.NetworkParam{
+ ID: pointer.String(fakeNetworkID),
},
},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {
- m.
- ListNetwork(external.ListOptsExt{
- ListOptsBuilder: networks.ListOpts{ID: fakeNetworkID},
- External: pointer.Bool(true),
- }).
- Return([]networks.Network{
- {
- ID: fakeNetworkID,
- Name: fakeNetworkname,
- },
- }, nil)
+ expect: func(_ Gomega, m *mock.MockNetworkClientMockRecorder) {
+ m.GetNetwork(fakeNetworkID).Return(&networks.Network{
+ ID: fakeNetworkID,
+ Name: fakeNetworkname,
+ }, nil)
},
want: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
- ExternalNetwork: &infrav1.NetworkFilter{
- ID: fakeNetworkID,
+ ExternalNetwork: &infrav1.NetworkParam{
+ ID: pointer.String(fakeNetworkID),
},
},
Status: infrav1.OpenStackClusterStatus{
@@ -259,28 +263,24 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
name: "reconcile external network by name",
openStackCluster: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
- ExternalNetwork: &infrav1.NetworkFilter{
- Name: fakeNetworkname,
+ ExternalNetwork: &infrav1.NetworkParam{
+ Filter: &infrav1.NetworkFilter{Name: fakeNetworkname},
},
},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {
- m.
- ListNetwork(external.ListOptsExt{
- ListOptsBuilder: networks.ListOpts{Name: fakeNetworkname},
- External: pointer.Bool(true),
- }).
- Return([]networks.Network{
+ expect: func(g Gomega, m *mock.MockNetworkClientMockRecorder) {
+ m.ListNetwork(gomock.Any()).
+ DoAndReturn(getExternalNetwork(g, networks.ListOpts{Name: fakeNetworkname}, []networks.Network{
{
ID: fakeNetworkID,
Name: fakeNetworkname,
},
- }, nil)
+ }))
},
want: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
- ExternalNetwork: &infrav1.NetworkFilter{
- Name: fakeNetworkname,
+ ExternalNetwork: &infrav1.NetworkParam{
+ Filter: &infrav1.NetworkFilter{Name: fakeNetworkname},
},
},
Status: infrav1.OpenStackClusterStatus{
@@ -293,26 +293,43 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
wantErr: false,
},
{
- name: "reconcile external network by ID when no external network found",
+ name: "reconcile external network by ID when external network by id not found",
openStackCluster: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
- ExternalNetwork: &infrav1.NetworkFilter{
- ID: fakeNetworkID,
+ ExternalNetwork: &infrav1.NetworkParam{
+ ID: pointer.String(fakeNetworkID),
},
},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {
- m.
- ListNetwork(external.ListOptsExt{
- ListOptsBuilder: networks.ListOpts{ID: fakeNetworkID},
- External: pointer.Bool(true),
- }).
- Return([]networks.Network{}, nil)
+ expect: func(g Gomega, m *mock.MockNetworkClientMockRecorder) {
+ m.GetNetwork(fakeNetworkID).Return(nil, gophercloud.ErrDefault404{})
},
want: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
- ExternalNetwork: &infrav1.NetworkFilter{
- ID: fakeNetworkID,
+ ExternalNetwork: &infrav1.NetworkParam{
+ ID: pointer.String(fakeNetworkID),
+ },
+ },
+ },
+ wantErr: true,
+ },
+ {
+ name: "reconcile external network by ID when external network by name not found",
+ openStackCluster: &infrav1.OpenStackCluster{
+ Spec: infrav1.OpenStackClusterSpec{
+ ExternalNetwork: &infrav1.NetworkParam{
+ Filter: &infrav1.NetworkFilter{Name: fakeNetworkname},
+ },
+ },
+ },
+ expect: func(g Gomega, m *mock.MockNetworkClientMockRecorder) {
+ m.ListNetwork(gomock.Any()).
+ DoAndReturn(getExternalNetwork(g, networks.ListOpts{Name: fakeNetworkname}, []networks.Network{}))
+ },
+ want: &infrav1.OpenStackCluster{
+ Spec: infrav1.OpenStackClusterSpec{
+ ExternalNetwork: &infrav1.NetworkParam{
+ Filter: &infrav1.NetworkFilter{Name: fakeNetworkname},
},
},
},
@@ -325,7 +342,7 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
DisableExternalNetwork: pointer.Bool(true),
},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {},
+ expect: func(_ Gomega, m *mock.MockNetworkClientMockRecorder) {},
want: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{
DisableExternalNetwork: pointer.Bool(true),
@@ -337,17 +354,13 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
wantErr: false,
},
{
- name: "reconcile external network with no filter when zero external network found",
+ name: "reconcile external network with no filter when zero external networks found",
openStackCluster: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {
- m.
- ListNetwork(external.ListOptsExt{
- ListOptsBuilder: networks.ListOpts{},
- External: pointer.Bool(true),
- }).
- Return([]networks.Network{}, nil)
+ expect: func(g Gomega, m *mock.MockNetworkClientMockRecorder) {
+ m.ListNetwork(gomock.Any()).
+ DoAndReturn(getExternalNetwork(g, networks.ListOpts{}, []networks.Network{}))
},
want: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{},
@@ -362,18 +375,14 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
openStackCluster: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {
- m.
- ListNetwork(external.ListOptsExt{
- ListOptsBuilder: networks.ListOpts{},
- External: pointer.Bool(true),
- }).
- Return([]networks.Network{
+ expect: func(g Gomega, m *mock.MockNetworkClientMockRecorder) {
+ m.ListNetwork(gomock.Any()).
+ DoAndReturn(getExternalNetwork(g, networks.ListOpts{}, []networks.Network{
{
ID: fakeNetworkID,
Name: fakeNetworkname,
},
- }, nil)
+ }))
},
want: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{},
@@ -391,22 +400,27 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
openStackCluster: &infrav1.OpenStackCluster{
Spec: infrav1.OpenStackClusterSpec{},
},
- expect: func(m *mock.MockNetworkClientMockRecorder) {
+ expect: func(g Gomega, m *mock.MockNetworkClientMockRecorder) {
m.
- ListNetwork(external.ListOptsExt{
- ListOptsBuilder: networks.ListOpts{},
- External: pointer.Bool(true),
- }).
- Return([]networks.Network{
- {
- ID: fakeNetworkID,
- Name: fakeNetworkname,
- },
- {
- ID: "d08803fc-2fa5-4179-b9f7-8c43d0af2fe7",
- Name: "external-network-2",
- },
- }, nil)
+ ListNetwork(gomock.Any()).
+ DoAndReturn(func(opts networks.ListOptsBuilder) ([]networks.Network, error) {
+ expected := &external.ListOptsExt{
+ ListOptsBuilder: networks.ListOpts{},
+ External: pointer.Bool(true),
+ }
+ g.Expect(opts).To(Equal(expected), cmp.Diff(opts, expected))
+
+ return []networks.Network{
+ {
+ ID: fakeNetworkID,
+ Name: fakeNetworkname,
+ },
+ {
+ ID: "d08803fc-2fa5-4179-b9f7-8c43d0af2fe7",
+ Name: "external-network-2",
+ },
+ }, nil
+ })
},
want: &infrav1.OpenStackCluster{},
wantErr: true,
@@ -415,9 +429,12 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
+ mockCtrl := gomock.NewController(t)
+ defer mockCtrl.Finish()
+
g := NewWithT(t)
mockClient := mock.NewMockNetworkClient(mockCtrl)
- tt.expect(mockClient.EXPECT())
+ tt.expect(g, mockClient.EXPECT())
scopeFactory := scope.NewMockScopeFactory(mockCtrl, "")
log := testr.New(t)
@@ -429,7 +446,7 @@ func Test_ReconcileExternalNetwork(t *testing.T) {
if (err != nil) != tt.wantErr {
t.Errorf("ReconcileExternalNetwork() error = %v, wantErr %v", err, tt.wantErr)
}
- g.Expect(tt.openStackCluster).To(Equal(tt.want))
+ g.Expect(tt.openStackCluster).To(Equal(tt.want), cmp.Diff(tt.openStackCluster, tt.want))
})
}
}
diff --git a/pkg/cloud/services/networking/port.go b/pkg/cloud/services/networking/port.go
index f1fbfef6ce..8677b87a04 100644
--- a/pkg/cloud/services/networking/port.go
+++ b/pkg/cloud/services/networking/port.go
@@ -35,7 +35,6 @@ import (
"sigs.k8s.io/cluster-api-provider-openstack/pkg/record"
"sigs.k8s.io/cluster-api-provider-openstack/pkg/scope"
capoerrors "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/errors"
- "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/filterconvert"
"sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/names"
)
@@ -469,8 +468,12 @@ func (s *Service) normalizePortTarget(port *infrav1.PortOpts, defaultNetwork *in
}
switch {
- case port.Network != nil && port.Network.ID != "":
- networkID = port.Network.ID
+ case port.Network != nil:
+ var err error
+ networkID, err = s.GetNetworkIDByParam(port.Network)
+ if err != nil {
+ return "", nil, err
+ }
// No network, but fixed IPs are defined(we handled the no fixed
// IPs case above): try to infer network from a subnet
@@ -513,21 +516,9 @@ func (s *Service) normalizePortTarget(port *infrav1.PortOpts, defaultNetwork *in
return "", nil, err
}
- // Network is defined by filter
default:
- networkListOpts := filterconvert.NetworkFilterToListOpts(port.Network)
- netIDs, err := s.GetNetworkIDsByFilter(networkListOpts)
- if err != nil {
- return "", nil, err
- }
-
- // TODO: These are spec errors: they should set the machine to failed
- if len(netIDs) > 1 {
- return "", nil, fmt.Errorf("network filter for port %d returns more than one result", portIdx)
- } else if len(netIDs) == 0 {
- return "", nil, fmt.Errorf("network filter for port %d returns no networks", portIdx)
- }
- networkID = netIDs[0]
+ // TODO: This is a spec errors: it should set the machine to failed
+ return "", nil, fmt.Errorf("unable to determine network for port %d", portIdx)
}
// Network ID is now known. Resolve all FixedIPs
diff --git a/pkg/cloud/services/networking/port_test.go b/pkg/cloud/services/networking/port_test.go
index 466ee35a89..8fb6e035b2 100644
--- a/pkg/cloud/services/networking/port_test.go
+++ b/pkg/cloud/services/networking/port_test.go
@@ -475,8 +475,8 @@ func TestService_ConstructPorts(t *testing.T) {
spec: infrav1.OpenStackMachineSpec{
Ports: []infrav1.PortOpts{
{
- Network: &infrav1.NetworkFilter{
- ID: networkID,
+ Network: &infrav1.NetworkParam{
+ ID: pointer.String(networkID),
},
},
},
@@ -497,8 +497,8 @@ func TestService_ConstructPorts(t *testing.T) {
spec: infrav1.OpenStackMachineSpec{
Ports: []infrav1.PortOpts{
{
- Network: &infrav1.NetworkFilter{
- Name: "test-network",
+ Network: &infrav1.NetworkParam{
+ Filter: &infrav1.NetworkFilter{Name: "test-network"},
},
},
},
@@ -858,7 +858,7 @@ func Test_getPortName(t *testing.T) {
instanceName: "test-1-instance",
spec: &infrav1.PortOpts{
NameSuffix: pointer.String("foo2"),
- Network: &infrav1.NetworkFilter{ID: "bar"},
+ Network: &infrav1.NetworkParam{ID: pointer.String("bar")},
ResolvedPortSpecFields: infrav1.ResolvedPortSpecFields{
DisablePortSecurity: pointer.Bool(true),
},
diff --git a/pkg/utils/filterconvert/convert.go b/pkg/utils/filterconvert/convert.go
index a1574cc49f..01ce2126ec 100644
--- a/pkg/utils/filterconvert/convert.go
+++ b/pkg/utils/filterconvert/convert.go
@@ -71,7 +71,6 @@ func NetworkFilterToListOpts(networkFilter *infrav1.NetworkFilter) networks.List
Name: networkFilter.Name,
Description: networkFilter.Description,
ProjectID: networkFilter.ProjectID,
- ID: networkFilter.ID,
Tags: infrav1.JoinTags(networkFilter.Tags),
TagsAny: infrav1.JoinTags(networkFilter.TagsAny),
NotTags: infrav1.JoinTags(networkFilter.NotTags),
diff --git a/test/e2e/suites/apivalidations/filters_test.go b/test/e2e/suites/apivalidations/filters_test.go
index b4e256cff8..1420ebb258 100644
--- a/test/e2e/suites/apivalidations/filters_test.go
+++ b/test/e2e/suites/apivalidations/filters_test.go
@@ -60,7 +60,7 @@ var _ = Describe("Filter API validations", func() {
ports := make([]infrav1.PortOpts, len(tags))
for i := range tags {
port := &ports[i]
- port.Network = &infrav1.NetworkFilter{FilterByNeutronTags: tags[i]}
+ port.Network = &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tags[i]}}
port.FixedIPs = []infrav1.FixedIP{{Subnet: &infrav1.SubnetFilter{FilterByNeutronTags: tags[i]}}}
port.SecurityGroups = []infrav1.SecurityGroupFilter{{FilterByNeutronTags: tags[i]}}
}
@@ -74,8 +74,8 @@ var _ = Describe("Filter API validations", func() {
}
cluster.Spec.Subnets = subnets
if len(tags) > 0 {
- cluster.Spec.Network = &infrav1.NetworkFilter{FilterByNeutronTags: tags[0]}
- cluster.Spec.ExternalNetwork = &infrav1.NetworkFilter{FilterByNeutronTags: tags[0]}
+ cluster.Spec.Network = &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tags[0]}}
+ cluster.Spec.ExternalNetwork = &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tags[0]}}
cluster.Spec.Router = &infrav1.RouterFilter{FilterByNeutronTags: tags[0]}
}
Expect(k8sClient.Create(ctx, cluster)).To(Succeed(), "OpenStackCluster creation should succeed")
@@ -107,7 +107,7 @@ var _ = Describe("Filter API validations", func() {
{
machine := machine.DeepCopy()
machine.Spec.Ports = []infrav1.PortOpts{
- {Network: &infrav1.NetworkFilter{FilterByNeutronTags: tags[i]}},
+ {Network: &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tags[i]}}},
}
Expect(k8sClient.Create(ctx, machine)).NotTo(Succeed(), "OpenStackMachine creation should fail with invalid port network neutron tags")
}
@@ -138,13 +138,13 @@ var _ = Describe("Filter API validations", func() {
{
cluster := cluster.DeepCopy()
- cluster.Spec.Network = &infrav1.NetworkFilter{FilterByNeutronTags: tag}
+ cluster.Spec.Network = &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tag}}
Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail with invalid network neutron tags")
}
{
cluster := cluster.DeepCopy()
- cluster.Spec.ExternalNetwork = &infrav1.NetworkFilter{FilterByNeutronTags: tag}
+ cluster.Spec.ExternalNetwork = &infrav1.NetworkParam{Filter: &infrav1.NetworkFilter{FilterByNeutronTags: tag}}
Expect(k8sClient.Create(ctx, cluster)).NotTo(Succeed(), "OpenStackCluster creation should fail with invalid external network neutron tags")
}