diff --git a/charts/internal/cloud-provider-config/templates/cloud-provider-config.yaml b/charts/internal/cloud-provider-config/templates/cloud-provider-config.yaml index 3e9c36b..076b7c5 100644 --- a/charts/internal/cloud-provider-config/templates/cloud-provider-config.yaml +++ b/charts/internal/cloud-provider-config/templates/cloud-provider-config.yaml @@ -6,3 +6,5 @@ metadata: data: cloudprovider.conf: | clusterName: {{ .Values.clusterName }} + networking: + configureNodeAddresses: {{ .Values.networking.configureNodeAddresses }} diff --git a/charts/internal/cloud-provider-config/values.yaml b/charts/internal/cloud-provider-config/values.yaml index b730fae..c212ab0 100644 --- a/charts/internal/cloud-provider-config/values.yaml +++ b/charts/internal/cloud-provider-config/values.yaml @@ -1 +1,3 @@ clusterName: test +networking: + configureNodeAddresses: true diff --git a/hack/api-reference/api.md b/hack/api-reference/api.md index f1fe852..405d260 100644 --- a/hack/api-reference/api.md +++ b/hack/api-reference/api.md @@ -308,6 +308,51 @@ map[string]bool <p>FeatureGates contains information about enabled feature gates.</p> </td> </tr> +<tr> +<td> +<code>networking</code></br> +<em> +<a href="#metal.provider.extensions.gardener.cloud/v1alpha1.CloudControllerNetworking"> +CloudControllerNetworking +</a> +</em> +</td> +<td> +<em>(Optional)</em> +<p>Networking contains configuration settings for CCM networking.</p> +</td> +</tr> +</tbody> +</table> +<h3 id="metal.provider.extensions.gardener.cloud/v1alpha1.CloudControllerNetworking">CloudControllerNetworking +</h3> +<p> +(<em>Appears on:</em> +<a href="#metal.provider.extensions.gardener.cloud/v1alpha1.CloudControllerManagerConfig">CloudControllerManagerConfig</a>) +</p> +<p> +<p>CloudControllerNetworking contains configuration settings for CCM networking.</p> +</p> +<table> +<thead> +<tr> +<th>Field</th> +<th>Description</th> +</tr> +</thead> +<tbody> +<tr> +<td> +<code>configureNodeAddresses</code></br> +<em> +bool +</em> +</td> +<td> +<em>(Optional)</em> +<p>ConfigureNodeAddresses enables the configuration of node addresses.</p> +</td> +</tr> </tbody> </table> <h3 id="metal.provider.extensions.gardener.cloud/v1alpha1.IgnitionConfig">IgnitionConfig diff --git a/pkg/apis/metal/types_controlplane.go b/pkg/apis/metal/types_controlplane.go index bb21ed0..011690b 100644 --- a/pkg/apis/metal/types_controlplane.go +++ b/pkg/apis/metal/types_controlplane.go @@ -21,10 +21,19 @@ type ControlPlaneConfig struct { LoadBalancerConfig *LoadBalancerConfig } +// CloudControllerNetworking contains configuration settings for CCM networking. +type CloudControllerNetworking struct { + // ConfigureNodeAddresses enables the configuration of node addresses. + ConfigureNodeAddresses bool +} + // CloudControllerManagerConfig contains configuration settings for the cloud-controller-manager. type CloudControllerManagerConfig struct { // FeatureGates contains information about enabled feature gates. FeatureGates map[string]bool + + // Networking contains configuration settings for CCM networking. + Networking *CloudControllerNetworking } // LoadBalancerConfig contains configuration settings for the shoot loadbalancing. diff --git a/pkg/apis/metal/v1alpha1/types_controlplane.go b/pkg/apis/metal/v1alpha1/types_controlplane.go index e46aa0e..09798f9 100644 --- a/pkg/apis/metal/v1alpha1/types_controlplane.go +++ b/pkg/apis/metal/v1alpha1/types_controlplane.go @@ -23,11 +23,22 @@ type ControlPlaneConfig struct { LoadBalancerConfig *LoadBalancerConfig `json:"loadBalancerConfig,omitempty"` } +// CloudControllerNetworking contains configuration settings for CCM networking. +type CloudControllerNetworking struct { + // ConfigureNodeAddresses enables the configuration of node addresses. + // +optional + ConfigureNodeAddresses bool `json:"configureNodeAddresses,omitempty"` +} + // CloudControllerManagerConfig contains configuration settings for the cloud-controller-manager. type CloudControllerManagerConfig struct { // FeatureGates contains information about enabled feature gates. // +optional FeatureGates map[string]bool `json:"featureGates,omitempty"` + + // Networking contains configuration settings for CCM networking. + // +optional + Networking *CloudControllerNetworking `json:"networking,omitempty"` } // LoadBalancerConfig contains configuration settings for the shoot loadbalancing. diff --git a/pkg/apis/metal/v1alpha1/zz_generated.conversion.go b/pkg/apis/metal/v1alpha1/zz_generated.conversion.go index d1bc0f5..772d63c 100644 --- a/pkg/apis/metal/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/metal/v1alpha1/zz_generated.conversion.go @@ -55,6 +55,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*CloudControllerNetworking)(nil), (*metal.CloudControllerNetworking)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_CloudControllerNetworking_To_metal_CloudControllerNetworking(a.(*CloudControllerNetworking), b.(*metal.CloudControllerNetworking), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*metal.CloudControllerNetworking)(nil), (*CloudControllerNetworking)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_metal_CloudControllerNetworking_To_v1alpha1_CloudControllerNetworking(a.(*metal.CloudControllerNetworking), b.(*CloudControllerNetworking), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*CloudProfileConfig)(nil), (*metal.CloudProfileConfig)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_CloudProfileConfig_To_metal_CloudProfileConfig(a.(*CloudProfileConfig), b.(*metal.CloudProfileConfig), scope) }); err != nil { @@ -262,6 +272,7 @@ func Convert_metal_CalicoBgpConfig_To_v1alpha1_CalicoBgpConfig(in *metal.CalicoB func autoConvert_v1alpha1_CloudControllerManagerConfig_To_metal_CloudControllerManagerConfig(in *CloudControllerManagerConfig, out *metal.CloudControllerManagerConfig, s conversion.Scope) error { out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) + out.Networking = (*metal.CloudControllerNetworking)(unsafe.Pointer(in.Networking)) return nil } @@ -272,6 +283,7 @@ func Convert_v1alpha1_CloudControllerManagerConfig_To_metal_CloudControllerManag func autoConvert_metal_CloudControllerManagerConfig_To_v1alpha1_CloudControllerManagerConfig(in *metal.CloudControllerManagerConfig, out *CloudControllerManagerConfig, s conversion.Scope) error { out.FeatureGates = *(*map[string]bool)(unsafe.Pointer(&in.FeatureGates)) + out.Networking = (*CloudControllerNetworking)(unsafe.Pointer(in.Networking)) return nil } @@ -280,6 +292,26 @@ func Convert_metal_CloudControllerManagerConfig_To_v1alpha1_CloudControllerManag return autoConvert_metal_CloudControllerManagerConfig_To_v1alpha1_CloudControllerManagerConfig(in, out, s) } +func autoConvert_v1alpha1_CloudControllerNetworking_To_metal_CloudControllerNetworking(in *CloudControllerNetworking, out *metal.CloudControllerNetworking, s conversion.Scope) error { + out.ConfigureNodeAddresses = in.ConfigureNodeAddresses + return nil +} + +// Convert_v1alpha1_CloudControllerNetworking_To_metal_CloudControllerNetworking is an autogenerated conversion function. +func Convert_v1alpha1_CloudControllerNetworking_To_metal_CloudControllerNetworking(in *CloudControllerNetworking, out *metal.CloudControllerNetworking, s conversion.Scope) error { + return autoConvert_v1alpha1_CloudControllerNetworking_To_metal_CloudControllerNetworking(in, out, s) +} + +func autoConvert_metal_CloudControllerNetworking_To_v1alpha1_CloudControllerNetworking(in *metal.CloudControllerNetworking, out *CloudControllerNetworking, s conversion.Scope) error { + out.ConfigureNodeAddresses = in.ConfigureNodeAddresses + return nil +} + +// Convert_metal_CloudControllerNetworking_To_v1alpha1_CloudControllerNetworking is an autogenerated conversion function. +func Convert_metal_CloudControllerNetworking_To_v1alpha1_CloudControllerNetworking(in *metal.CloudControllerNetworking, out *CloudControllerNetworking, s conversion.Scope) error { + return autoConvert_metal_CloudControllerNetworking_To_v1alpha1_CloudControllerNetworking(in, out, s) +} + func autoConvert_v1alpha1_CloudProfileConfig_To_metal_CloudProfileConfig(in *CloudProfileConfig, out *metal.CloudProfileConfig, s conversion.Scope) error { out.MachineImages = *(*[]metal.MachineImages)(unsafe.Pointer(&in.MachineImages)) out.RegionConfigs = *(*[]metal.RegionConfig)(unsafe.Pointer(&in.RegionConfigs)) diff --git a/pkg/apis/metal/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/metal/v1alpha1/zz_generated.deepcopy.go index f80e133..882a65d 100644 --- a/pkg/apis/metal/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/metal/v1alpha1/zz_generated.deepcopy.go @@ -76,6 +76,11 @@ func (in *CloudControllerManagerConfig) DeepCopyInto(out *CloudControllerManager (*out)[key] = val } } + if in.Networking != nil { + in, out := &in.Networking, &out.Networking + *out = new(CloudControllerNetworking) + **out = **in + } return } @@ -89,6 +94,22 @@ func (in *CloudControllerManagerConfig) DeepCopy() *CloudControllerManagerConfig return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudControllerNetworking) DeepCopyInto(out *CloudControllerNetworking) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudControllerNetworking. +func (in *CloudControllerNetworking) DeepCopy() *CloudControllerNetworking { + if in == nil { + return nil + } + out := new(CloudControllerNetworking) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudProfileConfig) DeepCopyInto(out *CloudProfileConfig) { *out = *in diff --git a/pkg/apis/metal/validation/controlplane.go b/pkg/apis/metal/validation/controlplane.go index 3ed1b47..5a2c1da 100644 --- a/pkg/apis/metal/validation/controlplane.go +++ b/pkg/apis/metal/validation/controlplane.go @@ -8,6 +8,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" apismetal "github.com/ironcore-dev/gardener-extension-provider-metal/pkg/apis/metal" + "github.com/ironcore-dev/gardener-extension-provider-metal/pkg/metal" ) // ValidateControlPlaneConfig validates a ControlPlaneConfig object. @@ -15,7 +16,7 @@ func ValidateControlPlaneConfig(controlPlaneConfig *apismetal.ControlPlaneConfig allErrs := field.ErrorList{} if controlPlaneConfig.CloudControllerManager != nil { - allErrs = append(allErrs, featurevalidation.ValidateFeatureGates(controlPlaneConfig.CloudControllerManager.FeatureGates, version, fldPath.Child("cloudControllerManager", "featureGates"))...) + allErrs = append(allErrs, featurevalidation.ValidateFeatureGates(controlPlaneConfig.CloudControllerManager.FeatureGates, version, fldPath.Child("cloudControllerManager", metal.CloudControllerManagerFeatureGatesKeyName))...) } // TODO add validation for IPs diff --git a/pkg/apis/metal/zz_generated.deepcopy.go b/pkg/apis/metal/zz_generated.deepcopy.go index b210ff0..61c557c 100644 --- a/pkg/apis/metal/zz_generated.deepcopy.go +++ b/pkg/apis/metal/zz_generated.deepcopy.go @@ -76,6 +76,11 @@ func (in *CloudControllerManagerConfig) DeepCopyInto(out *CloudControllerManager (*out)[key] = val } } + if in.Networking != nil { + in, out := &in.Networking, &out.Networking + *out = new(CloudControllerNetworking) + **out = **in + } return } @@ -89,6 +94,22 @@ func (in *CloudControllerManagerConfig) DeepCopy() *CloudControllerManagerConfig return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudControllerNetworking) DeepCopyInto(out *CloudControllerNetworking) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudControllerNetworking. +func (in *CloudControllerNetworking) DeepCopy() *CloudControllerNetworking { + if in == nil { + return nil + } + out := new(CloudControllerNetworking) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudProfileConfig) DeepCopyInto(out *CloudProfileConfig) { *out = *in diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index bd17b93..4f26bbf 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -300,7 +300,12 @@ func getCCMChartValues( } if cpConfig.CloudControllerManager != nil { - values["featureGates"] = cpConfig.CloudControllerManager.FeatureGates + values[metal.CloudControllerManagerFeatureGatesKeyName] = cpConfig.CloudControllerManager.FeatureGates + if cpConfig.CloudControllerManager.Networking != nil { + values[metal.CloudControllerManagerNetworkingKeyName] = map[string]any{ + metal.CloudControllerManagerNodeAddressesConfigKeyName: cpConfig.CloudControllerManager.Networking.ConfigureNodeAddresses, + } + } } overlayEnabled, err := isOverlayEnabled(cluster.Shoot.Spec.Networking) diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index acabb74..302cfdf 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -90,6 +90,9 @@ var _ = Describe("Valueprovider Reconcile", func() { cloudProviderConfig := map[string]any{} Expect(yaml.Unmarshal([]byte(config.Data["cloudprovider.conf"]), &cloudProviderConfig)).NotTo(HaveOccurred()) Expect(cloudProviderConfig["clusterName"]).To(Equal(cluster.Name)) + networkingConfig, ok := cloudProviderConfig[metal.CloudControllerManagerNetworkingKeyName].(map[string]any) + Expect(ok).To(BeTrue()) + Expect(networkingConfig[metal.CloudControllerManagerNodeAddressesConfigKeyName]).To(BeTrue()) }) }) @@ -209,7 +212,7 @@ var _ = Describe("Valueprovider Reconcile", func() { "secrets": map[string]any{ "server": "cloud-controller-manager-server", }, - "featureGates": map[string]bool{ + metal.CloudControllerManagerFeatureGatesKeyName: map[string]bool{ "CustomResourceValidation": true, }, "podNetwork": "10.0.0.0/16", @@ -219,6 +222,130 @@ var _ = Describe("Valueprovider Reconcile", func() { }) }) + Describe("#GetControlPlaneChartValues", func() { + It("should return correct shoot system chart values for disabled CCM address config", func(ctx SpecContext) { + cp := &extensionsv1alpha1.ControlPlane{ + ObjectMeta: metav1.ObjectMeta{ + Name: "control-plane", + Namespace: ns.Name, + }, + Spec: extensionsv1alpha1.ControlPlaneSpec{ + Region: "foo", + SecretRef: corev1.SecretReference{ + Name: "my-infra-creds", + Namespace: ns.Name, + }, + DefaultSpec: extensionsv1alpha1.DefaultSpec{ + Type: metal.Type, + ProviderConfig: &runtime.RawExtension{ + Raw: encode(&apismetal.ControlPlaneConfig{ + CloudControllerManager: &apismetal.CloudControllerManagerConfig{ + FeatureGates: map[string]bool{ + "CustomResourceValidation": true, + }, + Networking: &apismetal.CloudControllerNetworking{ + ConfigureNodeAddresses: false, + }, + }, + }), + }, + }, + }, + } + providerCloudProfile := &apismetal.CloudProfileConfig{} + providerCloudProfileJson, err := json.Marshal(providerCloudProfile) + Expect(err).NotTo(HaveOccurred()) + networkProviderConfig := &unstructured.Unstructured{Object: map[string]any{ + "kind": "FooNetworkConfig", + "apiVersion": "v1alpha1", + "overlay": map[string]any{ + "enabled": false, + }, + }} + networkProviderConfigData, err := runtime.Encode(unstructured.UnstructuredJSONScheme, networkProviderConfig) + Expect(err).NotTo(HaveOccurred()) + cluster := &controller.Cluster{ + CloudProfile: &gardencorev1beta1.CloudProfile{ + Spec: gardencorev1beta1.CloudProfileSpec{ + ProviderConfig: &runtime.RawExtension{ + Raw: providerCloudProfileJson, + }, + }, + }, + Shoot: &gardencorev1beta1.Shoot{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns.Name, + Name: "my-shoot", + }, + Spec: gardencorev1beta1.ShootSpec{ + Networking: &gardencorev1beta1.Networking{ + ProviderConfig: &runtime.RawExtension{Raw: networkProviderConfigData}, + Pods: ptr.To[string]("10.0.0.0/16"), + }, + Kubernetes: gardencorev1beta1.Kubernetes{ + Version: "1.26.0", + VerticalPodAutoscaler: &gardencorev1beta1.VerticalPodAutoscaler{ + Enabled: true, + }, + }, + }, + }, + Seed: &gardencorev1beta1.Seed{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + metal.LocalMetalAPIAnnotation: "true", + }, + }, + }, + } + + checksums := map[string]string{ + metal.CloudProviderConfigName: "8bafb35ff1ac60275d62e1cbd495aceb511fb354f74a20f7d06ecb48b3a68432", + } + values, err := vp.GetControlPlaneChartValues(ctx, cp, cluster, fakeSecretsManager, checksums, false) + Expect(err).NotTo(HaveOccurred()) + Expect(values).To(Equal(map[string]any{ + "global": map[string]any{ + "genericTokenKubeconfigSecretName": "generic-token-kubeconfig", + }, + "cloud-controller-manager": map[string]any{ + "enabled": true, + "replicas": 1, + "clusterName": ns.Name, + "podAnnotations": map[string]any{ + "checksum/secret-cloud-provider-config": "8bafb35ff1ac60275d62e1cbd495aceb511fb354f74a20f7d06ecb48b3a68432", + }, + "podLabels": map[string]any{ + "maintenance.gardener.cloud/restart": "true", + metal.AllowEgressToIstioIngressLabel: "allowed", + }, + "tlsCipherSuites": []string{ + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + }, + "secrets": map[string]any{ + "server": "cloud-controller-manager-server", + }, + metal.CloudControllerManagerFeatureGatesKeyName: map[string]bool{ + "CustomResourceValidation": true, + }, + metal.CloudControllerManagerNetworkingKeyName: map[string]any{ + metal.CloudControllerManagerNodeAddressesConfigKeyName: false, + }, + "podNetwork": "10.0.0.0/16", + "configureCloudRoutes": true, + }, + })) + }) + }) + Describe("#GetControlPlaneShootChartValues", func() { It("should return correct shoot system chart values without metallb", func(ctx SpecContext) { cp := &extensionsv1alpha1.ControlPlane{ diff --git a/pkg/metal/types.go b/pkg/metal/types.go index 96db525..728e468 100644 --- a/pkg/metal/types.go +++ b/pkg/metal/types.go @@ -56,6 +56,12 @@ const ( CloudProviderConfigName = "cloud-provider-config" // CloudControllerManagerName is a constant for the name of the CloudController deployed by the worker controller. CloudControllerManagerName = "cloud-controller-manager" + // CloudControllerManagerFeatureGatesKeyName is the key name for the feature gates key in CCM configuration + CloudControllerManagerFeatureGatesKeyName = "featureGates" + // CloudControllerManagerNetworkingKeyName is the key name for the networking key in CCM configuration + CloudControllerManagerNetworkingKeyName = "networking" + // CloudControllerManagerNodeAddressesConfigKeyName is the key name for the networking key in CCM configuration + CloudControllerManagerNodeAddressesConfigKeyName = "configureNodeAddresses" // CalicoBgpName is a constant for the name of the Calico BGP deployed by the worker controller. CalicoBgpName = "calico-bgp" // MetallbName is a constant for the name of the MetalLB deployed by the worker controller.