diff --git a/pkg/karmadactl/cmdinit/cmdinit.go b/pkg/karmadactl/cmdinit/cmdinit.go index 83a26c94c..331f262eb 100644 --- a/pkg/karmadactl/cmdinit/cmdinit.go +++ b/pkg/karmadactl/cmdinit/cmdinit.go @@ -5,6 +5,7 @@ import ( "io" "github.com/spf13/cobra" + "k8s.io/klog/v2" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes" "github.com/karmada-io/karmada/pkg/version" @@ -38,6 +39,13 @@ func NewCmdInit(cmdOut io.Writer, parentCommand string) *cobra.Command { }, } flags := cmd.PersistentFlags() + + releaseVer, err := version.ParseGitVersion(version.Get().GitVersion) + if err != nil { + klog.Infof("No default release version found. build version: %s", version.Get().String()) + releaseVer = &version.ReleaseVersion{} // initialize to avoid panic + } + // cert flags.StringVar(&opts.ExternalIP, "cert-external-ip", "", "the external IP of Karmada certificate (e.g 192.168.1.2,172.16.1.2)") flags.StringVar(&opts.ExternalDNS, "cert-external-dns", "", "the external DNS of Karmada certificate (e.g localhost,localhost.com)") @@ -55,21 +63,21 @@ func NewCmdInit(cmdOut io.Writer, parentCommand string) *cobra.Command { 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.EtcdPersistentVolumeSize, "etcd-pvc-size", "", "5Gi", "etcd data path,valid in pvc mode.") // karmada - crdURL := fmt.Sprintf("https://github.com/karmada-io/karmada/releases/download/%s/crds.tar.gz", version.Get().GitVersion) + crdURL := fmt.Sprintf("https://github.com/karmada-io/karmada/releases/download/%s/crds.tar.gz", releaseVer.FirstMinorRelease()) flags.StringVar(&opts.CRDs, "crds", crdURL, "Karmada crds resource.(local file e.g. --crds /root/crds.tar.gz)") flags.Int32VarP(&opts.KarmadaAPIServerNodePort, "port", "p", 32443, "Karmada apiserver service node port") flags.StringVarP(&opts.KarmadaDataPath, "karmada-data", "d", "/etc/karmada", "karmada data path. kubeconfig cert and crds files") flags.StringVarP(&opts.KarmadaAPIServerImage, "karmada-apiserver-image", "", "k8s.gcr.io/kube-apiserver:v1.21.7", "Kubernetes apiserver image") flags.Int32VarP(&opts.KarmadaAPIServerReplicas, "karmada-apiserver-replicas", "", 1, "karmada apiserver replica set") - flags.StringVarP(&opts.KarmadaSchedulerImage, "karmada-scheduler-image", "", "swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-scheduler:latest", "karmada scheduler image") + flags.StringVarP(&opts.KarmadaSchedulerImage, "karmada-scheduler-image", "", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-scheduler:%s", releaseVer.PatchRelease()), "karmada scheduler image") flags.Int32VarP(&opts.KarmadaSchedulerReplicas, "karmada-scheduler-replicas", "", 1, "karmada scheduler replica set") flags.StringVarP(&opts.KubeControllerManagerImage, "karmada-kube-controller-manager-image", "", "k8s.gcr.io/kube-controller-manager:v1.21.7", "Kubernetes controller manager image") flags.Int32VarP(&opts.KubeControllerManagerReplicas, "karmada-kube-controller-manager-replicas", "", 1, "karmada kube controller manager replica set") - flags.StringVarP(&opts.KarmadaControllerManagerImage, "karmada-controller-manager-image", "", "swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-controller-manager:latest", "karmada controller manager image") + flags.StringVarP(&opts.KarmadaControllerManagerImage, "karmada-controller-manager-image", "", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-controller-manager:%s", releaseVer.PatchRelease()), "karmada controller manager image") flags.Int32VarP(&opts.KarmadaControllerManagerReplicas, "karmada-controller-manager-replicas", "", 1, "karmada controller manager replica set") - flags.StringVarP(&opts.KarmadaWebhookImage, "karmada-webhook-image", "", "swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-webhook:latest", "karmada webhook image") + flags.StringVarP(&opts.KarmadaWebhookImage, "karmada-webhook-image", "", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-webhook:%s", releaseVer.PatchRelease()), "karmada webhook image") flags.Int32VarP(&opts.KarmadaWebhookReplicas, "karmada-webhook-replicas", "", 1, "karmada webhook replica set") - flags.StringVarP(&opts.KarmadaAggregatedAPIServerImage, "karmada-aggregated-apiserver-image", "", "swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-aggregated-apiserver:latest", "karmada aggregated apiserver image") + flags.StringVarP(&opts.KarmadaAggregatedAPIServerImage, "karmada-aggregated-apiserver-image", "", fmt.Sprintf("swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-aggregated-apiserver:%s", releaseVer.PatchRelease()), "karmada aggregated apiserver image") flags.Int32VarP(&opts.KarmadaAggregatedAPIServerReplicas, "karmada-aggregated-apiserver-replicas", "", 1, "karmada aggregated apiserver replica set") return cmd diff --git a/pkg/version/release.go b/pkg/version/release.go new file mode 100644 index 000000000..f3168a3da --- /dev/null +++ b/pkg/version/release.go @@ -0,0 +1,46 @@ +package version + +import ( + "fmt" + + utilversion "k8s.io/apimachinery/pkg/util/version" +) + +// ReleaseVersion represents a released version. +type ReleaseVersion struct { + *utilversion.Version +} + +// ParseGitVersion parses a git version string, such as: +// - v1.1.0-73-g7e6d4f69 +// - v1.1.0 +func ParseGitVersion(gitVersion string) (*ReleaseVersion, error) { + v, err := utilversion.ParseGeneric(gitVersion) + if err != nil { + return nil, err + } + + return &ReleaseVersion{ + Version: v, + }, nil +} + +// FirstMinorRelease returns the minor release but the patch releases always be 0(vx.y.0). e.g: +// - v1.2.1-12-g2eb92858 --> v1.2.0 +// - v1.2.3-12-g2e860210 --> v1.2.0 +func (r *ReleaseVersion) FirstMinorRelease() string { + if r.Version == nil { + return "" + } + + return fmt.Sprintf("v%d.%d.0", r.Version.Major(), r.Version.Minor()) +} + +// PatchRelease returns the stable version with format "vx.y.z". +func (r *ReleaseVersion) PatchRelease() string { + if r.Version == nil { + return "" + } + + return fmt.Sprintf("v%d.%d.%d", r.Version.Major(), r.Version.Minor(), r.Version.Patch()) +} diff --git a/pkg/version/release_test.go b/pkg/version/release_test.go new file mode 100644 index 000000000..346f63969 --- /dev/null +++ b/pkg/version/release_test.go @@ -0,0 +1,69 @@ +package version + +import "testing" + +func TestReleaseVersion(t *testing.T) { + tests := []struct { + Name string + GitVersion string + ExpectFirstMinorRelease string + ExpectPatchRelease string + ExpectError bool + }{ + { + Name: "first minor release", + GitVersion: "v1.1.0", + ExpectFirstMinorRelease: "v1.1.0", + ExpectPatchRelease: "v1.1.0", + ExpectError: false, + }, + { + Name: "subsequent minor release", + GitVersion: "v1.1.1", + ExpectFirstMinorRelease: "v1.1.0", + ExpectPatchRelease: "v1.1.1", + ExpectError: false, + }, + { + Name: "normal git version", + GitVersion: "v1.1.1-6-gf20c721a", + ExpectFirstMinorRelease: "v1.1.0", + ExpectPatchRelease: "v1.1.1", + ExpectError: false, + }, + { + Name: "abnormal version", + GitVersion: "vx.y.z-6-gf20c721a", + ExpectFirstMinorRelease: "", + ExpectPatchRelease: "", + ExpectError: true, + }, + } + + for i := range tests { + tc := tests[i] + + t.Run(tc.Name, func(t *testing.T) { + rv, err := ParseGitVersion(tc.GitVersion) + if err != nil { + if !tc.ExpectError { + t.Fatalf("No error is expected but got: %v", err) + } + // Stop and passes this test as error is expected. + return + } else if err == nil { + if tc.ExpectError { + t.Fatalf("Expect error, but got nil") + } + } + + if rv.FirstMinorRelease() != tc.ExpectFirstMinorRelease { + t.Fatalf("expect first minor release: %s, but got: %s", tc.ExpectFirstMinorRelease, rv.FirstMinorRelease()) + } + + if rv.PatchRelease() != tc.ExpectPatchRelease { + t.Fatalf("expect patch release: %s, but got: %s", tc.ExpectPatchRelease, rv.PatchRelease()) + } + }) + } +}