From d5f16726f1cd51dbdca62cf3b3ff0b3405ae5b12 Mon Sep 17 00:00:00 2001 From: tiansuo114 <1729765480@qq.com> Date: Wed, 7 Aug 2024 15:29:59 +0800 Subject: [PATCH] Support multiple label selection ability in EtcdNodeSelectorLabels Signed-off-by: tiansuo114 <1729765480@qq.com> fix ci Signed-off-by: tiansuo114 <1729765480@qq.com> add unit test Signed-off-by: tiansuo114 <1729765480@qq.com> change unit test Signed-off-by: tiansuo114 <1729765480@qq.com> rm mapsEqual Signed-off-by: tiansuo114 <1729765480@qq.com> fix Signed-off-by: tiansuo114 <1729765480@qq.com> 1111111111111111111111 Signed-off-by: tiansuo114 <1729765480@qq.com> Update pkg/karmadactl/cmdinit/cmdinit.go Co-authored-by: zhzhuang-zju use metav1.ParseToLabelSelector Signed-off-by: tiansuo114 <1729765480@qq.com> delete useless test Signed-off-by: tiansuo114 <1729765480@qq.com> 11 Signed-off-by: tiansuo114 <1729765480@qq.com> --- pkg/karmadactl/cmdinit/cmdinit.go | 2 +- pkg/karmadactl/cmdinit/kubernetes/deploy.go | 18 ++++-- .../cmdinit/kubernetes/statefulset.go | 12 ++-- .../cmdinit/kubernetes/statefulset_test.go | 64 +++++++++++++------ 4 files changed, 66 insertions(+), 30 deletions(-) diff --git a/pkg/karmadactl/cmdinit/cmdinit.go b/pkg/karmadactl/cmdinit/cmdinit.go index b56988f60471..e5bfeaa1ccd2 100644 --- a/pkg/karmadactl/cmdinit/cmdinit.go +++ b/pkg/karmadactl/cmdinit/cmdinit.go @@ -140,7 +140,7 @@ func NewCmdInit(parentCommand string) *cobra.Command { flags.StringVarP(&opts.EtcdInitImage, "etcd-init-image", "", kubernetes.DefaultInitImage, "etcd init container image") flags.Int32VarP(&opts.EtcdReplicas, "etcd-replicas", "", 1, "etcd replica set, cluster 3,5...singular") flags.StringVarP(&opts.EtcdHostDataPath, "etcd-data", "", "/var/lib/karmada-etcd", "etcd data path,valid in hostPath mode.") - flags.StringVarP(&opts.EtcdNodeSelectorLabels, "etcd-node-selector-labels", "", "", "etcd pod select the labels of the node. valid in hostPath mode ( e.g. --etcd-node-selector-labels karmada.io/etcd=true)") + flags.StringVarP(&opts.EtcdNodeSelectorLabels, "etcd-node-selector-labels", "", "", "the labels used for etcd pod to select nodes, valid in hostPath mode, and with each label separated by a comma. ( e.g. --etcd-node-selector-labels karmada.io/etcd=true,kubernetes.io/os=linux)") flags.StringVarP(&opts.EtcdPersistentVolumeSize, "etcd-pvc-size", "", "5Gi", "etcd data path,valid in pvc mode.") flags.StringVar(&opts.ExternalEtcdCACertPath, "external-etcd-ca-cert-path", "", "The path of CA certificate of the external etcd cluster in pem format.") flags.StringVar(&opts.ExternalEtcdClientCertPath, "external-etcd-client-cert-path", "", "The path of client side certificate to the external etcd cluster in pem format.") diff --git a/pkg/karmadactl/cmdinit/kubernetes/deploy.go b/pkg/karmadactl/cmdinit/kubernetes/deploy.go index a3b5842caf97..ce2707a3d253 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/deploy.go +++ b/pkg/karmadactl/cmdinit/kubernetes/deploy.go @@ -134,6 +134,7 @@ type CommandInitOption struct { EtcdStorageMode string EtcdHostDataPath string EtcdNodeSelectorLabels string + EtcdNodeSelectorLabelsMap map[string]string EtcdPersistentVolumeSize string ExternalEtcdCACertPath string ExternalEtcdClientCertPath string @@ -180,10 +181,6 @@ func (i *CommandInitOption) validateLocalEtcd(parentCommand string) error { return fmt.Errorf("when etcd storage mode is hostPath, dataPath is not empty. See '%s init --help'", parentCommand) } - if i.EtcdStorageMode == etcdStorageModeHostPath && i.EtcdNodeSelectorLabels != "" && utils.StringToMap(i.EtcdNodeSelectorLabels) == nil { - return fmt.Errorf("the label does not seem to be 'key=value'") - } - if i.EtcdStorageMode == etcdStorageModeHostPath && i.EtcdReplicas != 1 { return fmt.Errorf("for data security,when etcd storage mode is hostPath,etcd-replicas can only be 1") } @@ -274,12 +271,23 @@ func (i *CommandInitOption) Complete() error { } klog.Infof("karmada apiserver ip: %s", i.KarmadaAPIServerIP) + if i.EtcdStorageMode == etcdStorageModeHostPath && i.EtcdNodeSelectorLabels != "" { + selector, err := metav1.ParseToLabelSelector(i.EtcdNodeSelectorLabels) + if err != nil { + return fmt.Errorf("the etcdNodeSelector format is incorrect: %s", err) + } + labelMap, err := metav1.LabelSelectorAsMap(selector) + if err != nil { + return fmt.Errorf("failed to convert etcdNodeSelector labels to map: %v", err) + } + i.EtcdNodeSelectorLabelsMap = labelMap + } + if !i.isExternalEtcdProvided() && i.EtcdStorageMode == "hostPath" && i.EtcdNodeSelectorLabels != "" { if !i.isNodeExist(i.EtcdNodeSelectorLabels) { return fmt.Errorf("no node found by label %s", i.EtcdNodeSelectorLabels) } } - return initializeDirectory(i.KarmadaDataPath) } diff --git a/pkg/karmadactl/cmdinit/kubernetes/statefulset.go b/pkg/karmadactl/cmdinit/kubernetes/statefulset.go index 77168712dabf..e74b79328879 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/statefulset.go +++ b/pkg/karmadactl/cmdinit/kubernetes/statefulset.go @@ -28,7 +28,6 @@ import ( "k8s.io/utils/ptr" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/options" - "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" ) const ( @@ -300,11 +299,12 @@ func (i *CommandInitOption) makeETCDStatefulSet() *appsv1.StatefulSet { Volumes: *Volumes, } - if i.EtcdStorageMode == "hostPath" && i.EtcdNodeSelectorLabels != "" { - podSpec.NodeSelector = utils.StringToMap(i.EtcdNodeSelectorLabels) - } - if i.EtcdStorageMode == "hostPath" && i.EtcdNodeSelectorLabels == "" { - podSpec.NodeSelector = map[string]string{"karmada.io/etcd": ""} + if i.EtcdStorageMode == "hostPath" { + if i.EtcdNodeSelectorLabelsMap != nil { + podSpec.NodeSelector = i.EtcdNodeSelectorLabelsMap + } else { + podSpec.NodeSelector = map[string]string{"karmada.io/etcd": ""} + } } // InitContainers diff --git a/pkg/karmadactl/cmdinit/kubernetes/statefulset_test.go b/pkg/karmadactl/cmdinit/kubernetes/statefulset_test.go index ba5088edfed6..3b87b700e703 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/statefulset_test.go +++ b/pkg/karmadactl/cmdinit/kubernetes/statefulset_test.go @@ -78,43 +78,69 @@ func TestCommandInitIOption_etcdInitContainerCommand(t *testing.T) { func TestCommandInitIOption_makeETCDStatefulSet(t *testing.T) { tests := []struct { - name string - opt CommandInitOption - expectedNSValue string - expectedNSLabel string + name string + opt CommandInitOption + expectedNSMap map[string]string }{ { - name: "EtcdStorageMode is etcdStorageModeHostPath, EtcdNodeSelectorLabels is set", + name: "EtcdStorageMode is etcdStorageModeHostPath, single valid EtcdNodeSelectorLabel", opt: CommandInitOption{ EtcdStorageMode: etcdStorageModeHostPath, Namespace: "karmada", StorageClassesName: "StorageClassesName", EtcdPersistentVolumeSize: "1024", EtcdNodeSelectorLabels: "label=value", + EtcdNodeSelectorLabelsMap: map[string]string{ + "label": "value", + }, + }, + expectedNSMap: map[string]string{ + "label": "value", }, - expectedNSValue: "value", - expectedNSLabel: "label", }, { - name: "EtcdStorageMode is etcdStorageModeHostPath, EtcdNodeSelectorLabels is not set", + name: "EtcdStorageMode is etcdStorageModeHostPath, multiple valid EtcdNodeSelectorLabels", opt: CommandInitOption{ EtcdStorageMode: etcdStorageModeHostPath, Namespace: "karmada", StorageClassesName: "StorageClassesName", EtcdPersistentVolumeSize: "1024", - EtcdNodeSelectorLabels: "", + EtcdNodeSelectorLabels: "label1=value1,label2=value2,kubernetes.io/os=linux", + EtcdNodeSelectorLabelsMap: map[string]string{ + "label1": "value1", + "label2": "value2", + "kubernetes.io/os": "linux", + }, + }, + expectedNSMap: map[string]string{ + "label1": "value1", + "label2": "value2", + "kubernetes.io/os": "linux", + }, + }, + { + name: "EtcdStorageMode is etcdStorageModeHostPath, empty EtcdNodeSelectorLabels", + opt: CommandInitOption{ + EtcdStorageMode: etcdStorageModeHostPath, + Namespace: "karmada", + StorageClassesName: "StorageClassesName", + EtcdPersistentVolumeSize: "1024", + EtcdNodeSelectorLabels: "", + EtcdNodeSelectorLabelsMap: map[string]string{}, + }, + expectedNSMap: map[string]string{ + "karmada.io/etcd": "", }, - expectedNSValue: "", - expectedNSLabel: "karmada.io/etcd", }, { name: "EtcdStorageMode is etcdStorageModePVC", opt: CommandInitOption{ - EtcdStorageMode: etcdStorageModePVC, - Namespace: "karmada", - StorageClassesName: "StorageClassesName", - EtcdPersistentVolumeSize: "1024", - EtcdNodeSelectorLabels: "", + EtcdStorageMode: etcdStorageModePVC, + Namespace: "karmada", + StorageClassesName: "StorageClassesName", + EtcdPersistentVolumeSize: "1024", + EtcdNodeSelectorLabels: "", + EtcdNodeSelectorLabelsMap: map[string]string{}, }, }, } @@ -128,8 +154,10 @@ func TestCommandInitIOption_makeETCDStatefulSet(t *testing.T) { } } else { nodeSelector := etcd.Spec.Template.Spec.NodeSelector - if val, ok := nodeSelector[tt.expectedNSLabel]; !ok || val != tt.expectedNSValue { - t.Errorf("CommandInitOption.makeETCDStatefulSet() returns wrong nodeSelector %v", nodeSelector) + for label, value := range tt.expectedNSMap { + if val, ok := nodeSelector[label]; !ok || val != value { + t.Errorf("CommandInitOption.makeETCDStatefulSet() returns wrong nodeSelector %v, expected %v=%v", nodeSelector, label, value) + } } if len(etcd.Spec.VolumeClaimTemplates) != 0 {