diff --git a/api/v1alpha5/zz_generated.conversion.go b/api/v1alpha5/zz_generated.conversion.go index 44dbc571e2..47c0c4d6ad 100644 --- a/api/v1alpha5/zz_generated.conversion.go +++ b/api/v1alpha5/zz_generated.conversion.go @@ -426,6 +426,8 @@ func autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha5_APIServerLoadBalancer out.AdditionalPorts = *(*[]int)(unsafe.Pointer(&in.AdditionalPorts)) out.AllowedCIDRs = *(*[]string)(unsafe.Pointer(&in.AllowedCIDRs)) // WARNING: in.Provider requires manual conversion: does not exist in peer-type + // WARNING: in.Network requires manual conversion: does not exist in peer-type + // WARNING: in.Subnets requires manual conversion: does not exist in peer-type return nil } @@ -563,6 +565,7 @@ func autoConvert_v1beta1_LoadBalancer_To_v1alpha5_LoadBalancer(in *v1beta1.LoadB out.InternalIP = in.InternalIP out.AllowedCIDRs = *(*[]string)(unsafe.Pointer(&in.AllowedCIDRs)) // WARNING: in.Tags requires manual conversion: does not exist in peer-type + // WARNING: in.LoadBalancerNetwork requires manual conversion: does not exist in peer-type return nil } diff --git a/api/v1alpha6/openstackcluster_conversion.go b/api/v1alpha6/openstackcluster_conversion.go index 1241469587..694db897f5 100644 --- a/api/v1alpha6/openstackcluster_conversion.go +++ b/api/v1alpha6/openstackcluster_conversion.go @@ -203,6 +203,13 @@ func restorev1beta1ClusterSpec(previous *infrav1.OpenStackClusterSpec, dst *infr dst.APIServerLoadBalancer.Enabled = previous.APIServerLoadBalancer.Enabled } optional.RestoreString(&previous.APIServerLoadBalancer.Provider, &dst.APIServerLoadBalancer.Provider) + + if previous.APIServerLoadBalancer.Network != nil { + dst.APIServerLoadBalancer.Network = previous.APIServerLoadBalancer.Network + } + if previous.APIServerLoadBalancer.Subnets != nil { + dst.APIServerLoadBalancer.Subnets = previous.APIServerLoadBalancer.Subnets + } } if dst.APIServerLoadBalancer.IsZero() { dst.APIServerLoadBalancer = previous.APIServerLoadBalancer @@ -287,6 +294,21 @@ func Convert_v1alpha6_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O return nil } +func Convert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(in *infrav1.APIServerLoadBalancer, out *APIServerLoadBalancer, s apiconversion.Scope) error { + return autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(in, out, s) +} + +func Convert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(in *infrav1.LoadBalancer, out *LoadBalancer, s apiconversion.Scope) error { + return autoConvert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(in, out, s) +} + +func Convert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in *APIServerLoadBalancer, out *infrav1.APIServerLoadBalancer, s apiconversion.Scope) error { + err := autoConvert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in, out, s) + out.Subnets = nil + out.Network = nil + return err +} + func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha6_OpenStackClusterSpec(in *infrav1.OpenStackClusterSpec, out *OpenStackClusterSpec, s apiconversion.Scope) error { err := autoConvert_v1beta1_OpenStackClusterSpec_To_v1alpha6_OpenStackClusterSpec(in, out, s) if err != nil { @@ -373,6 +395,9 @@ func restorev1beta1ClusterStatus(previous *infrav1.OpenStackClusterStatus, dst * if previous.Bastion != nil && previous.Bastion.DependentResources.Ports != nil { dst.Bastion.DependentResources.Ports = previous.Bastion.DependentResources.Ports } + if previous.APIServerLoadBalancer != nil && previous.APIServerLoadBalancer.LoadBalancerNetwork != nil { + dst.APIServerLoadBalancer.LoadBalancerNetwork = previous.APIServerLoadBalancer.LoadBalancerNetwork + } } func Convert_v1beta1_OpenStackClusterStatus_To_v1alpha6_OpenStackClusterStatus(in *infrav1.OpenStackClusterStatus, out *OpenStackClusterStatus, s apiconversion.Scope) error { @@ -388,7 +413,16 @@ func Convert_v1beta1_OpenStackClusterStatus_To_v1alpha6_OpenStackClusterStatus(i } out.Network.Router = (*Router)(in.Router) - out.Network.APIServerLoadBalancer = (*LoadBalancer)(in.APIServerLoadBalancer) + if in.APIServerLoadBalancer != nil { + out.Network.APIServerLoadBalancer = &LoadBalancer{ + Name: in.APIServerLoadBalancer.Name, + ID: in.APIServerLoadBalancer.ID, + IP: in.APIServerLoadBalancer.IP, + InternalIP: in.APIServerLoadBalancer.InternalIP, + AllowedCIDRs: in.APIServerLoadBalancer.AllowedCIDRs, + Tags: in.APIServerLoadBalancer.Tags, + } + } } return nil @@ -403,7 +437,16 @@ func Convert_v1alpha6_OpenStackClusterStatus_To_v1beta1_OpenStackClusterStatus(i // Router and APIServerLoadBalancer have been moved out of Network in v1beta1 if in.Network != nil { out.Router = (*infrav1.Router)(in.Network.Router) - out.APIServerLoadBalancer = (*infrav1.LoadBalancer)(in.Network.APIServerLoadBalancer) + if in.Network.APIServerLoadBalancer != nil { + out.APIServerLoadBalancer = &infrav1.LoadBalancer{ + Name: in.Network.APIServerLoadBalancer.Name, + ID: in.Network.APIServerLoadBalancer.ID, + IP: in.Network.APIServerLoadBalancer.IP, + InternalIP: in.Network.APIServerLoadBalancer.InternalIP, + AllowedCIDRs: in.Network.APIServerLoadBalancer.AllowedCIDRs, + Tags: in.Network.APIServerLoadBalancer.Tags, + } + } } return nil diff --git a/api/v1alpha6/zz_generated.conversion.go b/api/v1alpha6/zz_generated.conversion.go index e3d5251fae..6f1df69678 100644 --- a/api/v1alpha6/zz_generated.conversion.go +++ b/api/v1alpha6/zz_generated.conversion.go @@ -41,16 +41,6 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*APIServerLoadBalancer)(nil), (*v1beta1.APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(a.(*APIServerLoadBalancer), b.(*v1beta1.APIServerLoadBalancer), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta1.APIServerLoadBalancer)(nil), (*APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(a.(*v1beta1.APIServerLoadBalancer), b.(*APIServerLoadBalancer), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*AddressPair)(nil), (*v1beta1.AddressPair)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha6_AddressPair_To_v1beta1_AddressPair(a.(*AddressPair), b.(*v1beta1.AddressPair), scope) }); err != nil { @@ -86,11 +76,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta1.LoadBalancer)(nil), (*LoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(a.(*v1beta1.LoadBalancer), b.(*LoadBalancer), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*OpenStackCluster)(nil), (*v1beta1.OpenStackCluster)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha6_OpenStackCluster_To_v1beta1_OpenStackCluster(a.(*OpenStackCluster), b.(*v1beta1.OpenStackCluster), scope) }); err != nil { @@ -256,6 +241,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*APIServerLoadBalancer)(nil), (*v1beta1.APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(a.(*APIServerLoadBalancer), b.(*v1beta1.APIServerLoadBalancer), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*Bastion)(nil), (*v1beta1.Bastion)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha6_Bastion_To_v1beta1_Bastion(a.(*Bastion), b.(*v1beta1.Bastion), scope) }); err != nil { @@ -331,6 +321,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.APIServerLoadBalancer)(nil), (*APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(a.(*v1beta1.APIServerLoadBalancer), b.(*APIServerLoadBalancer), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.BastionStatus)(nil), (*Instance)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_BastionStatus_To_v1alpha6_Instance(a.(*v1beta1.BastionStatus), b.(*Instance), scope) }); err != nil { @@ -341,6 +336,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.LoadBalancer)(nil), (*LoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(a.(*v1beta1.LoadBalancer), b.(*LoadBalancer), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.NetworkFilter)(nil), (*NetworkFilter)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_NetworkFilter_To_v1alpha6_NetworkFilter(a.(*v1beta1.NetworkFilter), b.(*NetworkFilter), scope) }); err != nil { @@ -431,11 +431,6 @@ func autoConvert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer return nil } -// Convert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer is an autogenerated conversion function. -func Convert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in *APIServerLoadBalancer, out *v1beta1.APIServerLoadBalancer, s conversion.Scope) error { - return autoConvert_v1alpha6_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in, out, s) -} - func autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(in *v1beta1.APIServerLoadBalancer, out *APIServerLoadBalancer, s conversion.Scope) error { if err := v1.Convert_Pointer_bool_To_bool(&in.Enabled, &out.Enabled, s); err != nil { return err @@ -445,14 +440,11 @@ func autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer if err := optional.Convert_optional_String_To_string(&in.Provider, &out.Provider, s); err != nil { return err } + // WARNING: in.Network requires manual conversion: does not exist in peer-type + // WARNING: in.Subnets requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer is an autogenerated conversion function. -func Convert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(in *v1beta1.APIServerLoadBalancer, out *APIServerLoadBalancer, s conversion.Scope) error { - return autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha6_APIServerLoadBalancer(in, out, s) -} - func autoConvert_v1alpha6_AddressPair_To_v1beta1_AddressPair(in *AddressPair, out *v1beta1.AddressPair, s conversion.Scope) error { out.IPAddress = in.IPAddress if err := optional.Convert_string_To_optional_String(&in.MACAddress, &out.MACAddress, s); err != nil { @@ -588,14 +580,10 @@ func autoConvert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(in *v1beta1.LoadB out.InternalIP = in.InternalIP out.AllowedCIDRs = *(*[]string)(unsafe.Pointer(&in.AllowedCIDRs)) out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) + // WARNING: in.LoadBalancerNetwork requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer is an autogenerated conversion function. -func Convert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(in *v1beta1.LoadBalancer, out *LoadBalancer, s conversion.Scope) error { - return autoConvert_v1beta1_LoadBalancer_To_v1alpha6_LoadBalancer(in, out, s) -} - func autoConvert_v1alpha6_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilter, out *v1beta1.NetworkFilter, s conversion.Scope) error { out.Name = in.Name out.Description = in.Description diff --git a/api/v1alpha7/openstackcluster_conversion.go b/api/v1alpha7/openstackcluster_conversion.go index cd31d29f7f..0059b3b707 100644 --- a/api/v1alpha7/openstackcluster_conversion.go +++ b/api/v1alpha7/openstackcluster_conversion.go @@ -205,6 +205,14 @@ func restorev1beta1ClusterSpec(previous *infrav1.OpenStackClusterSpec, dst *infr dst.APIServerLoadBalancer.Enabled = previous.APIServerLoadBalancer.Enabled } optional.RestoreString(&previous.APIServerLoadBalancer.Provider, &dst.APIServerLoadBalancer.Provider) + + if previous.APIServerLoadBalancer.Network != nil { + dst.APIServerLoadBalancer.Network = previous.APIServerLoadBalancer.Network + } + + if previous.APIServerLoadBalancer.Subnets != nil { + dst.APIServerLoadBalancer.Subnets = previous.APIServerLoadBalancer.Subnets + } } if dst.APIServerLoadBalancer.IsZero() { dst.APIServerLoadBalancer = previous.APIServerLoadBalancer @@ -289,6 +297,21 @@ func Convert_v1alpha7_OpenStackClusterSpec_To_v1beta1_OpenStackClusterSpec(in *O return nil } +func Convert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(in *infrav1.LoadBalancer, out *LoadBalancer, s apiconversion.Scope) error { + return autoConvert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(in, out, s) +} + +func Convert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(in *infrav1.APIServerLoadBalancer, out *APIServerLoadBalancer, s apiconversion.Scope) error { + return autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(in, out, s) +} + +func Convert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in *APIServerLoadBalancer, out *infrav1.APIServerLoadBalancer, s apiconversion.Scope) error { + err := autoConvert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in, out, s) + out.Subnets = nil + out.Network = nil + return err +} + func Convert_v1beta1_OpenStackClusterSpec_To_v1alpha7_OpenStackClusterSpec(in *infrav1.OpenStackClusterSpec, out *OpenStackClusterSpec, s apiconversion.Scope) error { err := autoConvert_v1beta1_OpenStackClusterSpec_To_v1alpha7_OpenStackClusterSpec(in, out, s) if err != nil { @@ -358,6 +381,10 @@ func restorev1beta1ClusterStatus(previous *infrav1.OpenStackClusterStatus, dst * if previous.Bastion != nil && previous.Bastion.DependentResources.Ports != nil { dst.Bastion.DependentResources.Ports = previous.Bastion.DependentResources.Ports } + + if previous.APIServerLoadBalancer != nil && previous.APIServerLoadBalancer.LoadBalancerNetwork != nil { + dst.APIServerLoadBalancer.LoadBalancerNetwork = previous.APIServerLoadBalancer.LoadBalancerNetwork + } } func Convert_v1beta1_OpenStackClusterStatus_To_v1alpha7_OpenStackClusterStatus(in *infrav1.OpenStackClusterStatus, out *OpenStackClusterStatus, s apiconversion.Scope) error { diff --git a/api/v1alpha7/zz_generated.conversion.go b/api/v1alpha7/zz_generated.conversion.go index 5f364226bb..361892fb99 100644 --- a/api/v1alpha7/zz_generated.conversion.go +++ b/api/v1alpha7/zz_generated.conversion.go @@ -41,16 +41,6 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { - if err := s.AddGeneratedConversionFunc((*APIServerLoadBalancer)(nil), (*v1beta1.APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(a.(*APIServerLoadBalancer), b.(*v1beta1.APIServerLoadBalancer), scope) - }); err != nil { - return err - } - if err := s.AddGeneratedConversionFunc((*v1beta1.APIServerLoadBalancer)(nil), (*APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(a.(*v1beta1.APIServerLoadBalancer), b.(*APIServerLoadBalancer), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*AdditionalBlockDevice)(nil), (*v1beta1.AdditionalBlockDevice)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha7_AdditionalBlockDevice_To_v1beta1_AdditionalBlockDevice(a.(*AdditionalBlockDevice), b.(*v1beta1.AdditionalBlockDevice), scope) }); err != nil { @@ -131,11 +121,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta1.LoadBalancer)(nil), (*LoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(a.(*v1beta1.LoadBalancer), b.(*LoadBalancer), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*NetworkStatus)(nil), (*v1beta1.NetworkStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha7_NetworkStatus_To_v1beta1_NetworkStatus(a.(*NetworkStatus), b.(*v1beta1.NetworkStatus), scope) }); err != nil { @@ -326,6 +311,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*APIServerLoadBalancer)(nil), (*v1beta1.APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(a.(*APIServerLoadBalancer), b.(*v1beta1.APIServerLoadBalancer), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*Bastion)(nil), (*v1beta1.Bastion)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha7_Bastion_To_v1beta1_Bastion(a.(*Bastion), b.(*v1beta1.Bastion), scope) }); err != nil { @@ -376,6 +366,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.APIServerLoadBalancer)(nil), (*APIServerLoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(a.(*v1beta1.APIServerLoadBalancer), b.(*APIServerLoadBalancer), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.BastionStatus)(nil), (*BastionStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_BastionStatus_To_v1alpha7_BastionStatus(a.(*v1beta1.BastionStatus), b.(*BastionStatus), scope) }); err != nil { @@ -386,6 +381,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.LoadBalancer)(nil), (*LoadBalancer)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(a.(*v1beta1.LoadBalancer), b.(*LoadBalancer), scope) + }); err != nil { + return err + } if err := s.AddConversionFunc((*v1beta1.NetworkFilter)(nil), (*NetworkFilter)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_NetworkFilter_To_v1alpha7_NetworkFilter(a.(*v1beta1.NetworkFilter), b.(*NetworkFilter), scope) }); err != nil { @@ -456,11 +456,6 @@ func autoConvert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer return nil } -// Convert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer is an autogenerated conversion function. -func Convert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in *APIServerLoadBalancer, out *v1beta1.APIServerLoadBalancer, s conversion.Scope) error { - return autoConvert_v1alpha7_APIServerLoadBalancer_To_v1beta1_APIServerLoadBalancer(in, out, s) -} - func autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(in *v1beta1.APIServerLoadBalancer, out *APIServerLoadBalancer, s conversion.Scope) error { if err := v1.Convert_Pointer_bool_To_bool(&in.Enabled, &out.Enabled, s); err != nil { return err @@ -470,14 +465,11 @@ func autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer if err := optional.Convert_optional_String_To_string(&in.Provider, &out.Provider, s); err != nil { return err } + // WARNING: in.Network requires manual conversion: does not exist in peer-type + // WARNING: in.Subnets requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer is an autogenerated conversion function. -func Convert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(in *v1beta1.APIServerLoadBalancer, out *APIServerLoadBalancer, s conversion.Scope) error { - return autoConvert_v1beta1_APIServerLoadBalancer_To_v1alpha7_APIServerLoadBalancer(in, out, s) -} - func autoConvert_v1alpha7_AdditionalBlockDevice_To_v1beta1_AdditionalBlockDevice(in *AdditionalBlockDevice, out *v1beta1.AdditionalBlockDevice, s conversion.Scope) error { out.Name = in.Name out.SizeGiB = in.SizeGiB @@ -742,14 +734,10 @@ func autoConvert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(in *v1beta1.LoadB out.InternalIP = in.InternalIP out.AllowedCIDRs = *(*[]string)(unsafe.Pointer(&in.AllowedCIDRs)) out.Tags = *(*[]string)(unsafe.Pointer(&in.Tags)) + // WARNING: in.LoadBalancerNetwork requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer is an autogenerated conversion function. -func Convert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(in *v1beta1.LoadBalancer, out *LoadBalancer, s conversion.Scope) error { - return autoConvert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(in, out, s) -} - func autoConvert_v1alpha7_NetworkFilter_To_v1beta1_NetworkFilter(in *NetworkFilter, out *v1beta1.NetworkFilter, s conversion.Scope) error { out.Name = in.Name out.Description = in.Description @@ -1032,7 +1020,15 @@ func autoConvert_v1alpha7_OpenStackClusterStatus_To_v1beta1_OpenStackClusterStat out.Network = (*v1beta1.NetworkStatusWithSubnets)(unsafe.Pointer(in.Network)) out.ExternalNetwork = (*v1beta1.NetworkStatus)(unsafe.Pointer(in.ExternalNetwork)) out.Router = (*v1beta1.Router)(unsafe.Pointer(in.Router)) - out.APIServerLoadBalancer = (*v1beta1.LoadBalancer)(unsafe.Pointer(in.APIServerLoadBalancer)) + if in.APIServerLoadBalancer != nil { + in, out := &in.APIServerLoadBalancer, &out.APIServerLoadBalancer + *out = new(v1beta1.LoadBalancer) + if err := Convert_v1alpha7_LoadBalancer_To_v1beta1_LoadBalancer(*in, *out, s); err != nil { + return err + } + } else { + out.APIServerLoadBalancer = nil + } out.FailureDomains = *(*apiv1beta1.FailureDomains)(unsafe.Pointer(&in.FailureDomains)) if in.ControlPlaneSecurityGroup != nil { in, out := &in.ControlPlaneSecurityGroup, &out.ControlPlaneSecurityGroup @@ -1085,7 +1081,15 @@ func autoConvert_v1beta1_OpenStackClusterStatus_To_v1alpha7_OpenStackClusterStat out.Network = (*NetworkStatusWithSubnets)(unsafe.Pointer(in.Network)) out.ExternalNetwork = (*NetworkStatus)(unsafe.Pointer(in.ExternalNetwork)) out.Router = (*Router)(unsafe.Pointer(in.Router)) - out.APIServerLoadBalancer = (*LoadBalancer)(unsafe.Pointer(in.APIServerLoadBalancer)) + if in.APIServerLoadBalancer != nil { + in, out := &in.APIServerLoadBalancer, &out.APIServerLoadBalancer + *out = new(LoadBalancer) + if err := Convert_v1beta1_LoadBalancer_To_v1alpha7_LoadBalancer(*in, *out, s); err != nil { + return err + } + } else { + out.APIServerLoadBalancer = nil + } out.FailureDomains = *(*apiv1beta1.FailureDomains)(unsafe.Pointer(&in.FailureDomains)) if in.ControlPlaneSecurityGroup != nil { in, out := &in.ControlPlaneSecurityGroup, &out.ControlPlaneSecurityGroup diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index 4dccc85c7a..48b4eafa5b 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -429,6 +429,12 @@ type LoadBalancer struct { AllowedCIDRs []string `json:"allowedCIDRs,omitempty"` //+optional Tags []string `json:"tags,omitempty"` + // LoadBalancerNetwork contains information about network and/or subnets which the + // loadbalancer is allocated on. + // If subnets are specified within the LoadBalancerNetwork currently only the first + // subnet in the list is taken into account. + // +optional + LoadBalancerNetwork *NetworkStatusWithSubnets `json:"loadBalancerNetwork,omitempty"` } // SecurityGroupStatus represents the basic information of the associated @@ -633,6 +639,16 @@ type APIServerLoadBalancer struct { // specified. // +optional Provider optional.String `json:"provider,omitempty"` + + // Network defines which network should the load balancer be allocated on. + //+optional + Network *NetworkFilter `json:"network,omitempty"` + // Subnets define which subnets should the load balancer be allocated on. + // It is expected that subnets are located on the network specified in this resource. + // +optional + // +listType=atomic + // kubebuilder:validation:MaxLength:=2 + Subnets []SubnetFilter `json:"subnets,omitempty"` } func (s *APIServerLoadBalancer) IsZero() bool { diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index abd378418e..25f3e7e3da 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -50,6 +50,18 @@ func (in *APIServerLoadBalancer) DeepCopyInto(out *APIServerLoadBalancer) { *out = new(string) **out = **in } + if in.Network != nil { + in, out := &in.Network, &out.Network + *out = new(NetworkFilter) + (*in).DeepCopyInto(*out) + } + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make([]SubnetFilter, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new APIServerLoadBalancer. @@ -335,6 +347,11 @@ func (in *LoadBalancer) DeepCopyInto(out *LoadBalancer) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.LoadBalancerNetwork != nil { + in, out := &in.LoadBalancerNetwork, &out.LoadBalancerNetwork + *out = new(NetworkStatusWithSubnets) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancer. 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 2e31f55442..4b20b4cef8 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclusters.yaml @@ -4893,12 +4893,159 @@ spec: API server loadbalancer, omit the APIServerLoadBalancer field in the cluster spec instead. type: boolean + network: + description: Network defines which network should the load balancer + be allocated on. + properties: + description: + type: string + id: + 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 provider: description: |- Provider specifies name of a specific Octavia provider to use for the API load balancer. The Octavia default will be used if it is not specified. type: string + subnets: + description: |- + Subnets define which subnets should the load balancer be allocated on. + It is expected that subnets are located on the network specified in this resource. + kubebuilder:validation:MaxLength:=2 + items: + properties: + cidr: + type: string + description: + type: string + gatewayIP: + type: string + id: + type: string + ipVersion: + type: integer + ipv6AddressMode: + type: string + ipv6RAMode: + type: string + name: + type: string + notTags: + description: |- + NotTags is a list of tags to filter by. If specified, resources which + contain all of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + notTagsAny: + description: |- + NotTagsAny is a list of tags to filter by. If specified, resources + which contain any of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + projectID: + type: string + tags: + description: |- + Tags is a list of tags to filter by. If specified, the resource must + have all of the tags specified to be included in the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + tagsAny: + description: |- + TagsAny is a list of tags to filter by. If specified, the resource + must have at least one of the tags specified to be included in the + result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + type: object + type: array + x-kubernetes-list-type: atomic required: - enabled type: object @@ -6183,6 +6330,49 @@ spec: type: string ip: type: string + loadBalancerNetwork: + description: |- + LoadBalancerNetwork contains information about network and/or subnets which the + loadbalancer is allocated on. + If subnets are specified within the LoadBalancerNetwork currently only the first + subnet in the list is taken into account. + properties: + id: + type: string + name: + type: string + subnets: + description: Subnets is a list of subnets associated with + the default cluster network. Machines which use the default + cluster network will get an address from all of these subnets. + items: + description: Subnet represents basic information about the + associated OpenStack Neutron Subnet. + properties: + cidr: + type: string + id: + type: string + name: + type: string + tags: + items: + type: string + type: array + required: + - cidr + - id + - name + type: object + type: array + tags: + items: + type: string + type: array + required: + - id + - name + type: object name: type: string tags: 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 5dc38e4098..3ad820f733 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_openstackclustertemplates.yaml @@ -2317,12 +2317,159 @@ spec: API server loadbalancer, omit the APIServerLoadBalancer field in the cluster spec instead. type: boolean + network: + description: Network defines which network should the + load balancer be allocated on. + properties: + description: + type: string + id: + 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 provider: description: |- Provider specifies name of a specific Octavia provider to use for the API load balancer. The Octavia default will be used if it is not specified. type: string + subnets: + description: |- + Subnets define which subnets should the load balancer be allocated on. + It is expected that subnets are located on the network specified in this resource. + kubebuilder:validation:MaxLength:=2 + items: + properties: + cidr: + type: string + description: + type: string + gatewayIP: + type: string + id: + type: string + ipVersion: + type: integer + ipv6AddressMode: + type: string + ipv6RAMode: + type: string + name: + type: string + notTags: + description: |- + NotTags is a list of tags to filter by. If specified, resources which + contain all of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + notTagsAny: + description: |- + NotTagsAny is a list of tags to filter by. If specified, resources + which contain any of the given tags will be excluded from the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + projectID: + type: string + tags: + description: |- + Tags is a list of tags to filter by. If specified, the resource must + have all of the tags specified to be included in the result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + tagsAny: + description: |- + TagsAny is a list of tags to filter by. If specified, the resource + must have at least one of the tags specified to be included in the + result. + items: + description: |- + NeutronTag represents a tag on a Neutron resource. + It may not be empty and may not contain commas. + minLength: 1 + pattern: ^[^,]+$ + type: string + type: array + x-kubernetes-list-type: set + type: object + type: array + x-kubernetes-list-type: atomic required: - enabled type: object diff --git a/controllers/openstackcluster_controller.go b/controllers/openstackcluster_controller.go index 11e318ff31..c097394dd3 100644 --- a/controllers/openstackcluster_controller.go +++ b/controllers/openstackcluster_controller.go @@ -590,6 +590,60 @@ func bastionHashHasChanged(computeHash string, clusterAnnotations map[string]str return latestHash != computeHash } +func reconcileLoadBalancerNetwork(openStackCluster *infrav1.OpenStackCluster, networkingService *networking.Service) error { + if openStackCluster.Spec.APIServerLoadBalancer != nil && openStackCluster.Spec.APIServerLoadBalancer.Network != nil { + lbNetOpts := filterconvert.NetworkFilterToListOpts(openStackCluster.Spec.APIServerLoadBalancer.Network) + lbNetList, err := networkingService.GetNetworksByFilter(&lbNetOpts) + if err != nil { + handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to find loadbalancer network: %w", err)) + return fmt.Errorf("failed to find network: %w", err) + } + if len(lbNetList) == 0 { + handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to find loadbalancer network")) + return fmt.Errorf("failed to find any network") + } + if len(lbNetList) > 1 { + handleUpdateOSCError(openStackCluster, fmt.Errorf("found multiple loadbalancer networks (result: %v)", lbNetList)) + return fmt.Errorf("found multiple loadbalancer networks (result: %v)", lbNetList) + } + + // Filter out only relevant subnets specified by the spec + if openStackCluster.Status.APIServerLoadBalancer == nil { + openStackCluster.Status.APIServerLoadBalancer = &infrav1.LoadBalancer{ + LoadBalancerNetwork: &infrav1.NetworkStatusWithSubnets{ + NetworkStatus: infrav1.NetworkStatus{ + Name: lbNetList[0].Name, + ID: lbNetList[0].ID, + Tags: lbNetList[0].Tags, + }, + }, + } + } + + openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.Subnets = []infrav1.Subnet{} + for _, s := range openStackCluster.Spec.APIServerLoadBalancer.Subnets { + matchFound := false + for _, subnetID := range lbNetList[0].Subnets { + if subnetID == s.ID { + matchFound = true + openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.Subnets = append( + openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.Subnets, infrav1.Subnet{ + ID: s.ID, + Name: s.Name, + CIDR: s.CIDR, + }) + } + } + if !matchFound { + handleUpdateOSCError(openStackCluster, fmt.Errorf("no subnet match was found in the specified network (specified subnet: %v, available subnets: %v)", s, lbNetList[0].Subnets)) + return fmt.Errorf("no subnet match was found in the specified network (specified subnet: %v, available subnets: %v)", s, lbNetList[0].Subnets) + } + } + } + + return nil +} + func reconcileNetworkComponents(scope *scope.WithLogger, cluster *clusterv1.Cluster, openStackCluster *infrav1.OpenStackCluster) error { clusterName := fmt.Sprintf("%s-%s", cluster.Namespace, cluster.Name) @@ -618,6 +672,12 @@ func reconcileNetworkComponents(scope *scope.WithLogger, cluster *clusterv1.Clus return fmt.Errorf("failed to reconcile network: ManagedSubnets only supports one element, %d provided", len(openStackCluster.Spec.ManagedSubnets)) } + err = reconcileLoadBalancerNetwork(openStackCluster, networkingService) + if err != nil { + handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to reconcile loadbalancer network: %w", err)) + return fmt.Errorf("failed to reconcile loadbalancer network: %w", err) + } + err = networkingService.ReconcileSecurityGroups(openStackCluster, clusterName) if err != nil { handleUpdateOSCError(openStackCluster, fmt.Errorf("failed to reconcile security groups: %w", err)) diff --git a/docs/book/src/api/v1beta1/api.md b/docs/book/src/api/v1beta1/api.md index ce660d5e0d..e16bc9ca92 100644 --- a/docs/book/src/api/v1beta1/api.md +++ b/docs/book/src/api/v1beta1/api.md @@ -897,6 +897,36 @@ API load balancer. The Octavia default will be used if it is not specified.
+network
Network defines which network should the load balancer be allocated on.
+subnets
Subnets define which subnets should the load balancer be allocated on. +It is expected that subnets are located on the network specified in this resource. +kubebuilder:validation:MaxLength:=2
+loadBalancerNetwork
LoadBalancerNetwork contains information about network and/or subnets which the +loadbalancer is allocated on. +If subnets are specified within the LoadBalancerNetwork currently only the first +subnet in the list is taken into account.
+(Appears on: +APIServerLoadBalancer, OpenStackClusterSpec, PortOpts)
@@ -1905,6 +1953,7 @@ string(Appears on: +LoadBalancer, OpenStackClusterStatus)
@@ -4652,6 +4701,7 @@ string
(Appears on: +APIServerLoadBalancer, ExternalRouterIPParam, FixedIP, OpenStackClusterSpec) diff --git a/go.mod b/go.mod index 50ebe0a6a8..4da2f804a2 100644 --- a/go.mod +++ b/go.mod @@ -8,14 +8,14 @@ require ( github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 github.com/google/gofuzz v1.2.0 - github.com/gophercloud/gophercloud v1.7.0 + github.com/gophercloud/gophercloud v1.11.0 github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 github.com/hashicorp/go-version v1.4.0 github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/gomega v1.30.0 github.com/prometheus/client_golang v1.17.0 github.com/spf13/pflag v1.0.5 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.18.0 golang.org/x/text v0.14.0 gopkg.in/ini.v1 v1.67.0 k8s.io/api v0.28.4 @@ -139,8 +139,8 @@ require ( golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.14.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.16.1 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 3da2fa64fd..310f8aaa69 100644 --- a/go.sum +++ b/go.sum @@ -259,8 +259,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= -github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= -github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/gophercloud v1.11.0 h1:ls0O747DIq1D8SUHc7r2vI8BFbMLeLFuENaAIfEx7OM= +github.com/gophercloud/gophercloud v1.11.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 h1:sH7xkTfYzxIEgzq1tDHIMKRh1vThOEOGNsettdEeLbE= github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56/go.mod h1:VSalo4adEk+3sNkmVJLnhHoOyOYYS8sTWLG4mv5BKto= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -491,8 +491,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -640,13 +640,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/cloud/services/loadbalancer/loadbalancer.go b/pkg/cloud/services/loadbalancer/loadbalancer.go index 993a1dfb22..ffda35d904 100644 --- a/pkg/cloud/services/loadbalancer/loadbalancer.go +++ b/pkg/cloud/services/loadbalancer/loadbalancer.go @@ -270,9 +270,26 @@ func (s *Service) getOrCreateAPILoadBalancer(openStackCluster *infrav1.OpenStack return nil, fmt.Errorf("network is not yet available in OpenStackCluster.Status") } - // Create the VIP on the first cluster subnet - subnetID := openStackCluster.Status.Network.Subnets[0].ID - s.scope.Logger().Info("Creating load balancer in subnet", "subnetID", subnetID, "name", loadBalancerName) + var vipNetworkID, vipSubnetID string + if openStackCluster.Status.APIServerLoadBalancer != nil { + if openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork != nil { + if openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.ID != "" { + vipNetworkID = openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.ID + } + if len(openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.Subnets) > 0 { + // Currently only the first subnet is taken into account. + // This can be fixed as soon as we switch over to gophercloud release that + // contains AdditionalVips field. + vipSubnetID = openStackCluster.Status.APIServerLoadBalancer.LoadBalancerNetwork.Subnets[0].ID + } + } + } + if vipNetworkID == "" && vipSubnetID == "" { + // keep the default and create the VIP on the first cluster subnet + vipSubnetID = openStackCluster.Status.Network.Subnets[0].ID + } + + s.scope.Logger().Info("Creating load balancer in subnet", "subnetID", vipSubnetID, "name", loadBalancerName) providers, err := s.loadbalancerClient.ListLoadBalancerProviders() if err != nil { @@ -300,11 +317,12 @@ func (s *Service) getOrCreateAPILoadBalancer(openStackCluster *infrav1.OpenStack } lbCreateOpts := loadbalancers.CreateOpts{ - Name: loadBalancerName, - VipSubnetID: subnetID, - Description: names.GetDescription(clusterName), - Provider: lbProvider, - Tags: openStackCluster.Spec.Tags, + Name: loadBalancerName, + VipSubnetID: vipSubnetID, + VipNetworkID: vipNetworkID, + Description: names.GetDescription(clusterName), + Provider: lbProvider, + Tags: openStackCluster.Spec.Tags, } if vipAddress != nil { lbCreateOpts.VipAddress = *vipAddress diff --git a/pkg/cloud/services/loadbalancer/loadbalancer_test.go b/pkg/cloud/services/loadbalancer/loadbalancer_test.go index ce46235d82..751257b807 100644 --- a/pkg/cloud/services/loadbalancer/loadbalancer_test.go +++ b/pkg/cloud/services/loadbalancer/loadbalancer_test.go @@ -481,11 +481,54 @@ func Test_getOrCreateAPILoadBalancer(t *testing.T) { m.ListLoadBalancers(gomock.Any()).Return([]loadbalancers.LoadBalancer{}, nil) m.ListLoadBalancerProviders().Return(octaviaProviders, nil) m.CreateLoadBalancer(gomock.Any()).Return(&loadbalancers.LoadBalancer{ - ID: "AAAAA", + ID: "AAAAA", + VipSubnetID: "aaaaaaaa-bbbb-cccc-dddd-222222222222", }, nil) }, want: &loadbalancers.LoadBalancer{ - ID: "AAAAA", + ID: "AAAAA", + VipSubnetID: "aaaaaaaa-bbbb-cccc-dddd-222222222222", + }, + }, + { + name: "loadbalancer on a specific network created", + openStackCluster: &infrav1.OpenStackCluster{ + Status: infrav1.OpenStackClusterStatus{ + Network: &infrav1.NetworkStatusWithSubnets{ + Subnets: []infrav1.Subnet{ + {ID: "aaaaaaaa-bbbb-cccc-dddd-222222222222"}, + }, + }, + APIServerLoadBalancer: &infrav1.LoadBalancer{ + LoadBalancerNetwork: &infrav1.NetworkStatusWithSubnets{ + NetworkStatus: infrav1.NetworkStatus{ + Name: "VIPNET", + ID: "VIPNET", + }, + Subnets: []infrav1.Subnet{ + { + Name: "vip-subnet", + CIDR: "10.0.0.0/24", + ID: "VIPSUBNET", + }, + }, + }, + }, + }, + }, + expectLoadBalancer: func(m *mock.MockLbClientMockRecorder) { + m.ListLoadBalancers(gomock.Any()).Return([]loadbalancers.LoadBalancer{}, nil) + m.ListLoadBalancerProviders().Return(octaviaProviders, nil) + m.CreateLoadBalancer(gomock.Any()).Return(&loadbalancers.LoadBalancer{ + ID: "AAAAA", + VipSubnetID: "VIPSUBNET", + VipNetworkID: "VIPNET", + }, nil) + }, + want: &loadbalancers.LoadBalancer{ + ID: "AAAAA", + VipSubnetID: "VIPSUBNET", + VipNetworkID: "VIPNET", }, }, }