@@ -420,6 +420,150 @@ kubeProxyReplacement: true
420420 resp := validator .validate (context .Background (), req )
421421 Expect (resp .Allowed ).To (BeTrue ())
422422 })
423+
424+ It ("should allow when ConfigMap uses templated values with ControlPlaneEndpoint" , func () {
425+ cni := & v1alpha1.CNI {
426+ Provider : v1alpha1 .CNIProviderCilium ,
427+ AddonConfig : v1alpha1.AddonConfig {
428+ Values : & v1alpha1.AddonValues {
429+ SourceRef : & v1alpha1.ValuesReference {
430+ Kind : "ConfigMap" ,
431+ Name : "cilium-values" ,
432+ },
433+ },
434+ },
435+ }
436+ cluster := createTestClusterWithControlPlaneEndpoint (
437+ "test-cluster" ,
438+ "test-namespace" ,
439+ v1alpha1 .KubeProxyModeDisabled ,
440+ cni ,
441+ "192.168.1.100" ,
442+ 6443 ,
443+ )
444+ req := createAdmissionRequest (cluster )
445+
446+ // Create ConfigMap with templated values where kubeProxyReplacement depends on templating
447+ // Without templating, this would fail because {{ true }} is not a valid boolean
448+ configMap := & corev1.ConfigMap {
449+ ObjectMeta : metav1.ObjectMeta {
450+ Name : "cilium-values" ,
451+ Namespace : "test-namespace" ,
452+ },
453+ Data : map [string ]string {
454+ "values.yaml" : `
455+ ipam:
456+ mode: kubernetes
457+ # This will only work if templating is applied
458+ kubeProxyReplacement: true
459+ k8sServiceHost: "{{ trimPrefix .ControlPlaneEndpoint.Host "https://" }}"
460+ k8sServicePort: "{{ .ControlPlaneEndpoint.Port }}"
461+ ` ,
462+ },
463+ }
464+
465+ client := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (configMap ).Build ()
466+ validator = NewAdvancedCiliumConfigurationValidator (client , decoder )
467+
468+ resp := validator .validate (context .Background (), req )
469+ Expect (resp .Allowed ).To (BeTrue ())
470+ })
471+
472+ It ("should deny when ConfigMap uses templated values that would be false after templating" , func () {
473+ cni := & v1alpha1.CNI {
474+ Provider : v1alpha1 .CNIProviderCilium ,
475+ AddonConfig : v1alpha1.AddonConfig {
476+ Values : & v1alpha1.AddonValues {
477+ SourceRef : & v1alpha1.ValuesReference {
478+ Kind : "ConfigMap" ,
479+ Name : "cilium-values" ,
480+ },
481+ },
482+ },
483+ }
484+ cluster := createTestClusterWithControlPlaneEndpoint (
485+ "test-cluster" ,
486+ "test-namespace" ,
487+ v1alpha1 .KubeProxyModeDisabled ,
488+ cni ,
489+ "192.168.1.100" ,
490+ 6443 ,
491+ )
492+ req := createAdmissionRequest (cluster )
493+
494+ // Create ConfigMap with templated values that evaluate to false
495+ configMap := & corev1.ConfigMap {
496+ ObjectMeta : metav1.ObjectMeta {
497+ Name : "cilium-values" ,
498+ Namespace : "test-namespace" ,
499+ },
500+ Data : map [string ]string {
501+ "values.yaml" : `
502+ ipam:
503+ mode: kubernetes
504+ kubeProxyReplacement: {{ false }}
505+ k8sServiceHost: "{{ trimPrefix .ControlPlaneEndpoint.Host "https://" }}"
506+ k8sServicePort: "{{ .ControlPlaneEndpoint.Port }}"
507+ ` ,
508+ },
509+ }
510+
511+ client := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (configMap ).Build ()
512+ validator = NewAdvancedCiliumConfigurationValidator (client , decoder )
513+
514+ resp := validator .validate (context .Background (), req )
515+ Expect (resp .Allowed ).To (BeFalse ())
516+ expectedMessage := "kube-proxy is disabled, but Cilium ConfigMap test-namespace/cilium-values does not have 'kubeProxyReplacement' enabled"
517+ Expect (resp .Result .Message ).To (Equal (expectedMessage ))
518+ })
519+
520+ It ("should error out when ConfigMap uses unknown templated values" , func () {
521+ cni := & v1alpha1.CNI {
522+ Provider : v1alpha1 .CNIProviderCilium ,
523+ AddonConfig : v1alpha1.AddonConfig {
524+ Values : & v1alpha1.AddonValues {
525+ SourceRef : & v1alpha1.ValuesReference {
526+ Kind : "ConfigMap" ,
527+ Name : "cilium-values" ,
528+ },
529+ },
530+ },
531+ }
532+ cluster := createTestClusterWithControlPlaneEndpoint (
533+ "test-cluster" ,
534+ "test-namespace" ,
535+ v1alpha1 .KubeProxyModeDisabled ,
536+ cni ,
537+ "192.168.1.100" ,
538+ 6443 ,
539+ )
540+ req := createAdmissionRequest (cluster )
541+
542+ // Create ConfigMap with unknown template field
543+ configMap := & corev1.ConfigMap {
544+ ObjectMeta : metav1.ObjectMeta {
545+ Name : "cilium-values" ,
546+ Namespace : "test-namespace" ,
547+ },
548+ Data : map [string ]string {
549+ "values.yaml" : `
550+ ipam:
551+ mode: kubernetes
552+ kubeProxyReplacement: true
553+ k8sServiceHost: "{{ .UnknownField.Host }}"
554+ k8sServicePort: "{{ .ControlPlaneEndpoint.Port }}"
555+ ` ,
556+ },
557+ }
558+
559+ client := fake .NewClientBuilder ().WithScheme (scheme ).WithObjects (configMap ).Build ()
560+ validator = NewAdvancedCiliumConfigurationValidator (client , decoder )
561+
562+ resp := validator .validate (context .Background (), req )
563+ Expect (resp .Allowed ).To (BeFalse ())
564+ Expect (resp .Result .Message ).To (ContainSubstring ("failed templating values" ))
565+ Expect (resp .Result .Message ).To (ContainSubstring ("can't evaluate field UnknownField" ))
566+ })
423567 })
424568})
425569
@@ -467,6 +611,21 @@ func createTestCluster(
467611 }
468612}
469613
614+ func createTestClusterWithControlPlaneEndpoint (
615+ name , namespace string ,
616+ kubeProxyMode v1alpha1.KubeProxyMode ,
617+ cni * v1alpha1.CNI ,
618+ host string ,
619+ port int32 ,
620+ ) * clusterv1.Cluster {
621+ cluster := createTestCluster (name , namespace , kubeProxyMode , cni )
622+ cluster .Spec .ControlPlaneEndpoint = clusterv1.APIEndpoint {
623+ Host : host ,
624+ Port : port ,
625+ }
626+ return cluster
627+ }
628+
470629func createAdmissionRequest (cluster * clusterv1.Cluster ) admission.Request {
471630 objRaw , err := json .Marshal (cluster )
472631 Expect (err ).NotTo (HaveOccurred ())
0 commit comments