diff --git a/cmd/tke-installer/app/config/config.go b/cmd/tke-installer/app/config/config.go index 516dd03aa2..d7629dc32f 100644 --- a/cmd/tke-installer/app/config/config.go +++ b/cmd/tke-installer/app/config/config.go @@ -34,12 +34,13 @@ type Config struct { SyncProjectsWithNamespaces bool Replicas int Upgrade bool + PrepareCustomK8sImages bool Kubeconfig string RegistryUsername string RegistryPassword string RegistryDomain string RegistryNamespace string - CustomProviderResTag string + CustomUpgradeResourceDir string } // CreateConfigFromOptions creates a running configuration instance based @@ -56,10 +57,12 @@ func CreateConfigFromOptions(serverName string, opts *options.Options) (*Config, SyncProjectsWithNamespaces: *opts.SyncProjectsWithNamespaces, Replicas: *opts.Replicas, Upgrade: *opts.Upgrade, + PrepareCustomK8sImages: *opts.PrepareCustomK8sImages, Kubeconfig: *opts.Kubeconfig, RegistryUsername: *opts.RegistryUsername, RegistryPassword: *opts.RegistryPassword, RegistryDomain: *opts.RegistryDomain, RegistryNamespace: *opts.RegistryNamespace, + CustomUpgradeResourceDir: *opts.CustomUpgradeResourceDir, }, nil } diff --git a/cmd/tke-installer/app/installer/constants/constants.go b/cmd/tke-installer/app/installer/constants/constants.go index 908cb78786..e3e845dd72 100644 --- a/cmd/tke-installer/app/installer/constants/constants.go +++ b/cmd/tke-installer/app/installer/constants/constants.go @@ -19,13 +19,15 @@ package constants const ( - DataDir = "data/" - ClusterFile = DataDir + "tke.json" - ClusterLogFile = DataDir + "tke.log" - CustomK8sImageDir = DataDir + "images/" - CustomK8sBinaryDir = DataDir + "bins/" - CustomK8sBinaryAmdDir = DataDir + "bins/linux-amd64/" - CustomK8sBinaryArmDir = DataDir + "bins/linux-arm64/" + DataDir = "data/" + ClusterFile = DataDir + "tke.json" + ClusterLogFile = DataDir + "tke.log" + + DefaultCustomResourceDir = DataDir + "custom_upgrade_resource" + CustomK8sImageDirName = "images/" + CustomK8sBinaryDirName = "bins/" + CustomK8sBinaryAmdDirName = "bins/linux-amd64/" + CustomK8sBinaryArmDirName = "bins/linux-arm64/" ProviderConfigFile = "provider/baremetal/conf/config.yaml" diff --git a/cmd/tke-installer/app/installer/installer.go b/cmd/tke-installer/app/installer/installer.go index d9482c5349..b901d788f5 100644 --- a/cmd/tke-installer/app/installer/installer.go +++ b/cmd/tke-installer/app/installer/installer.go @@ -474,13 +474,20 @@ func (t *TKE) runWithUI() error { restful.Filter(globalLogging) - if t.Config.Upgrade { + switch { + case t.Config.PrepareCustomK8sImages: + err := t.prepareForPrepareCustomImages(context.Background()) + if err != nil { + return err + } + go t.doPrepareCustomImages() + case t.Config.Upgrade: err := t.prepareForUpgrade(context.Background()) if err != nil { return err } go t.do() - } else { + default: if t.isFromRestore { go t.do() } @@ -955,7 +962,6 @@ func (t *TKE) findClusterProgress(request *restful.Request, response *restful.Re } func (t *TKE) do() { - start := time.Now() ctx := t.log.WithContext(context.Background()) var taskType string @@ -968,33 +974,11 @@ func (t *TKE) do() { t.initSteps() } - if t.Step == 0 { - t.log.Infof("===>starting %s task", taskType) - t.progress.Status = types.StatusDoing - } - if !t.Config.Upgrade && t.runAfterClusterReady() { t.initDataForDeployTKE() } - for t.Step < len(t.steps) { - wait.PollInfinite(10*time.Second, func() (bool, error) { - t.log.Infof("%d.%s doing", t.Step, t.steps[t.Step].Name) - start := time.Now() - err := t.steps[t.Step].Func(ctx) - if err != nil { - t.progress.Status = types.StatusRetrying - t.log.Errorf("%d.%s [Failed] [%fs] error %s", t.Step, t.steps[t.Step].Name, time.Since(start).Seconds(), err) - return false, nil - } - t.log.Infof("%d.%s [Success] [%fs]", t.Step, t.steps[t.Step].Name, time.Since(start).Seconds()) - - t.Step++ - t.backup() - t.progress.Status = types.StatusDoing - return true, nil - }) - } + t.doSteps(ctx, taskType) t.progress.Status = types.StatusSuccess if t.Para.Config.Gateway != nil { @@ -1032,6 +1016,34 @@ func (t *TKE) do() { } t.progress.Servers = append(t.progress.Servers, t.servers...) +} + +func (t *TKE) doSteps(ctx context.Context, taskType string) { + start := time.Now() + if t.Step == 0 { + t.log.Infof("===>starting %s task", taskType) + t.progress.Status = types.StatusDoing + } + + for t.Step < len(t.steps) { + wait.PollInfinite(10*time.Second, func() (bool, error) { + t.log.Infof("%d.%s doing", t.Step, t.steps[t.Step].Name) + start := time.Now() + err := t.steps[t.Step].Func(ctx) + if err != nil { + t.progress.Status = types.StatusRetrying + t.log.Errorf("%d.%s [Failed] [%fs] error %s", t.Step, t.steps[t.Step].Name, time.Since(start).Seconds(), err) + return false, nil + } + t.log.Infof("%d.%s [Success] [%fs]", t.Step, t.steps[t.Step].Name, time.Since(start).Seconds()) + + t.Step++ + t.backup() + t.progress.Status = types.StatusDoing + return true, nil + }) + } + t.log.Infof("===>%s task [Sucesss] [%fs]", taskType, time.Since(start).Seconds()) } @@ -2433,6 +2445,14 @@ func (t *TKE) writeKubeconfig(ctx context.Context) error { } func (t *TKE) patchPlatformVersion(ctx context.Context) error { + tkeVersion, _, err := t.getPlatformVersions(ctx) + if err != nil { + return err + } + if tkeVersion == spec.TKEVersion { + log.Info("skip patch platform version, current installer version is equal to platform version") + } + versionsByte, err := json.Marshal(spec.K8sValidVersions) if err != nil { return err @@ -2443,6 +2463,10 @@ func (t *TKE) patchPlatformVersion(ctx context.Context) error { "tkeVersion": spec.TKEVersion, }, } + return t.patchClusterInfo(ctx, patchData) +} + +func (t *TKE) patchClusterInfo(ctx context.Context, patchData interface{}) error { patchByte, err := json.Marshal(patchData) if err != nil { return err diff --git a/cmd/tke-installer/app/installer/prepare.go b/cmd/tke-installer/app/installer/prepare.go new file mode 100644 index 0000000000..b96789dc44 --- /dev/null +++ b/cmd/tke-installer/app/installer/prepare.go @@ -0,0 +1,285 @@ +/* + * Tencent is pleased to support the open source community by making TKEStack + * available. + * + * Copyright (C) 2012-2019 Tencent. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://opensource.org/licenses/Apache-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package installer + +import ( + "context" + "encoding/json" + "io/ioutil" + "os" + "path" + "regexp" + + "github.com/pkg/errors" + "github.com/thoas/go-funk" + "tkestack.io/tke/cmd/tke-installer/app/installer/constants" + "tkestack.io/tke/cmd/tke-installer/app/installer/images" + "tkestack.io/tke/cmd/tke-installer/app/installer/types" + "tkestack.io/tke/pkg/spec" + "tkestack.io/tke/pkg/util/template" + + // import platform schema + _ "tkestack.io/tke/api/platform/install" +) + +func (t *TKE) prepareCustomImagesSteps() { + if !t.Para.Config.Registry.IsOfficial() { + t.steps = append(t.steps, []types.Handler{ + // { + // Name: "Precheck befor prepare custom images", + // Func: t.preCheckBeforePrepareCustomImages, + // }, + { + Name: "Login registry", + Func: t.loginRegistry, + }, + { + Name: "Load images", + Func: t.loadImages, + }, + { + Name: "Load custom K8s images", + Func: t.loadCustomK8sImages, + }, + { + Name: "Build custom provider res image", + Func: t.buildCustomProviderRes, + }, + { + Name: "Add custom version in cluster info", + Func: t.addCustomK8sVersion, + }, + }...) + } + + t.steps = append(t.steps, []types.Handler{}...) + + t.steps = funk.Filter(t.steps, func(step types.Handler) bool { + return !funk.ContainsString(t.Para.Config.SkipSteps, step.Name) + }).([]types.Handler) + + t.log.Info("Steps:") + for i, step := range t.steps { + t.log.Infof("%d %s", i, step.Name) + } +} + +// func (t *TKE) preCheckBeforePrepareCustomImages(ctx context.Context) error { +// tkeVersion, _, err := t.getPlatformVersions(ctx) +// if err != nil { +// return err +// } +// if tkeVersion != spec.TKEVersion { +// return errors.Errorf("cannot prepare custom images, platform version %s is not equal to installer version %s", tkeVersion, spec.TKEVersion) +// } +// return nil +// } + +func (t *TKE) prepareForPrepareCustomImages(ctx context.Context) error { + err := t.prepareForUpgrade(ctx) + if err != nil { + return err + } + tkeVersion, _, err := t.getPlatformVersions(ctx) + if err != nil { + return err + } + if tkeVersion != spec.TKEVersion { + return errors.Errorf("cannot prepare custom images, platform version %s is not equal to installer version %s", tkeVersion, spec.TKEVersion) + } + return nil +} + +func (t *TKE) doPrepareCustomImages() { + ctx := t.log.WithContext(context.Background()) + taskType := "prepare custom images" + t.prepareCustomImagesSteps() + t.doSteps(ctx, taskType) +} + +func (t *TKE) getCustomPatchVersion(ctx context.Context) (patchVersion string, err error) { + files, err := ioutil.ReadDir(t.Config.CustomUpgradeResourceDir) + if err != nil { + return "", err + } + if len(files) != 1 { + return "", errors.Errorf("please make sure %s dir has and only has one patch version dir", t.Config.CustomUpgradeResourceDir) + } + + patchVersion = files[0].Name() + dirRegexp := regexp.MustCompile(`^\d+.\d+.\d+$`) + ressutl := dirRegexp.MatchString(patchVersion) + if !ressutl { + return "", errors.Errorf("your patch version dir name %s is not a version, please make sure your dir name is a version like 1.18.3", patchVersion) + } + return patchVersion, nil +} + +func (t *TKE) loadCustomK8sImages(ctx context.Context) error { + patchVersion, err := t.getCustomPatchVersion(ctx) + if err != nil { + return err + } + + customK8sImagesDir := path.Join(t.Config.CustomUpgradeResourceDir, patchVersion, constants.CustomK8sImageDirName) + files, err := getFilesFromDir(customK8sImagesDir) + if err != nil { + return err + } + for _, file := range files { + err = t.docker.LoadImages(path.Join(customK8sImagesDir, file.Name())) + if err != nil { + return err + } + } + return nil +} + +func (t *TKE) buildCustomProviderRes(ctx context.Context) error { + patchVersion, err := t.getCustomPatchVersion(ctx) + if err != nil { + return err + } + + amdDirExists := false + armDirExists := false + + customK8sBinaryAmdDir := path.Join(t.Config.CustomUpgradeResourceDir, patchVersion, constants.CustomK8sBinaryAmdDirName) + amdFiles, err := getFilesFromDir(customK8sBinaryAmdDir) + if err == nil { + amdDirExists = true + } else if !os.IsNotExist(err) { + return err + } + + customK8sBinaryArmDir := path.Join(t.Config.CustomUpgradeResourceDir, patchVersion, constants.CustomK8sBinaryArmDirName) + armFiles, err := getFilesFromDir(customK8sBinaryArmDir) + if err == nil { + armDirExists = true + } else if !os.IsNotExist(err) { + return err + } + + if (len(amdFiles) == 0) && (len(armFiles) == 0) { + return errors.Errorf("There is no file in %s and %s, cannot build custom provider res image", customK8sBinaryAmdDir, constants.CustomK8sBinaryArmDirName) + } + + tag, err := t.getLatestProviderResTag(ctx) + if err != nil { + return err + } + + values := map[string]interface{}{ + "ProviderResName": images.Get().ProviderRes.Name, + "Arch": "amd64", + "Tag": tag, + "HasAmdDir": amdDirExists, + "AmdDir": customK8sBinaryAmdDir, + "HasArmDir": armDirExists, + "ArmDir": customK8sBinaryArmDir, + } + + amdDockerfile, err := genCustomProviderResDockerfile(values) + if err != nil { + return err + } + values["Arch"] = "arm64" + armDockerfile, err := genCustomProviderResDockerfile(values) + if err != nil { + return err + } + + nameWithoutArch := "tkestack/" + images.Get().ProviderRes.Name + + amdTarget := nameWithoutArch + "-amd64:" + patchVersion + err = t.docker.BuildImage(amdDockerfile, amdTarget, "linux/amd64") + if err != nil { + return err + } + + armTarget := nameWithoutArch + "-arm64:" + patchVersion + err = t.docker.BuildImage(armDockerfile, armTarget, "linux/arm64") + if err != nil { + return err + } + return nil +} + +func (t *TKE) addCustomK8sVersion(ctx context.Context) error { + _, k8sValidVersions, err := t.getPlatformVersions(ctx) + if err != nil { + return err + } + patchVersion, err := t.getCustomPatchVersion(ctx) + if err != nil { + return err + } + k8sValidVersions = append(k8sValidVersions, patchVersion) + versionsByte, err := json.Marshal(k8sValidVersions) + if err != nil { + return err + } + patchData := map[string]interface{}{ + "data": map[string]interface{}{ + "k8sValidVersions": string(versionsByte), + }, + } + return t.patchClusterInfo(ctx, patchData) +} + +func (t *TKE) getLatestProviderResTag(ctx context.Context) (tag string, err error) { + _, k8sValidVersions, err := t.getPlatformVersions(ctx) + if err != nil { + return "", err + } + if len(k8sValidVersions) > len(spec.K8sValidVersions) { + return k8sValidVersions[len(k8sValidVersions)-1], nil + } + return images.Get().ProviderRes.Tag, nil +} + +func genCustomProviderResDockerfile(values map[string]interface{}) ([]byte, error) { + dockerfileTpl := `FROM tkestack/{{ .ProviderResName }}-{{ .Arch }}:{{ .Tag }} + +WORKDIR /data + +{{- if .HasAmdDir }} +COPY {{ .AmdDir }}* res/linux-amd64/ +{{- end }} + +{{- if .HasArmDir }} +COPY {{ .ArmDir }}* res/linux-arm64/ +{{- end }} + +ENTRYPOINT ["sh"]` + return template.ParseString(dockerfileTpl, values) +} + +func getFilesFromDir(path string) (files []os.FileInfo, err error) { + files = []os.FileInfo{} + imageDir, err := os.Stat(path) + if err != nil { + return files, err + } + if !imageDir.IsDir() { + return files, errors.Errorf("%s is not a dir", path) + } + files, err = ioutil.ReadDir(path) + return files, err +} diff --git a/cmd/tke-installer/app/installer/upgrader.go b/cmd/tke-installer/app/installer/upgrader.go index 9adb1e5098..65e4c1699c 100644 --- a/cmd/tke-installer/app/installer/upgrader.go +++ b/cmd/tke-installer/app/installer/upgrader.go @@ -20,11 +20,9 @@ package installer import ( "context" + "encoding/json" "fmt" - "io/ioutil" - "os" "os/exec" - "regexp" "time" "github.com/pkg/errors" @@ -36,7 +34,6 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" platformv1 "tkestack.io/tke/api/client/clientset/versioned/typed/platform/v1" - "tkestack.io/tke/cmd/tke-installer/app/installer/constants" "tkestack.io/tke/cmd/tke-installer/app/installer/images" "tkestack.io/tke/cmd/tke-installer/app/installer/types" typesv1 "tkestack.io/tke/pkg/platform/types/v1" @@ -45,7 +42,7 @@ import ( "tkestack.io/tke/pkg/util/apiclient" "tkestack.io/tke/pkg/util/containerregistry" "tkestack.io/tke/pkg/util/file" - "tkestack.io/tke/pkg/util/template" + "tkestack.io/tke/pkg/util/version" // import platform schema _ "tkestack.io/tke/api/platform/install" @@ -61,20 +58,12 @@ func (t *TKE) upgradeSteps() { t.steps = append(t.steps, []types.Handler{ { Name: "Login registry", - Func: t.loginRegistryForUpgrade, + Func: t.loginRegistry, }, { Name: "Load images", Func: t.loadImages, }, - { - Name: "Load custom K8s images", - Func: t.loadCustomK8sImages, - }, - { - Name: "Build custom provider res image", - Func: t.buildCustomProviderRes, - }, { Name: "Tag images", Func: t.tagImages, @@ -155,9 +144,22 @@ func (t *TKE) updateTKEPlatformController(ctx context.Context) error { if len(depl.Spec.Template.Spec.InitContainers) == 0 { return fmt.Errorf("%s has no initContainers", com) } - if t.Config.CustomProviderResTag != "" { - depl.Spec.Template.Spec.InitContainers[0].Image = containerregistry.GetImagePrefix(images.Get().ProviderRes.Name + ":" + t.Config.CustomProviderResTag) - } else { + + tkeVersion, k8sValidVersions, err := t.getPlatformVersions(ctx) + if err != nil { + return err + } + result := version.Compare(tkeVersion, spec.TKEVersion) + + switch { + case result < 0: + return errors.Errorf("can't upgrade, platform's version %s is higher than installer's version %s", tkeVersion, spec.TKEVersion) + case result == 0: + if len(k8sValidVersions) == len(spec.K8sValidVersions) { + return errors.Errorf("can't upgrade, platform's version %s is equal to installer's version %s, please prepare your custom upgrade images before upgrade", tkeVersion, spec.TKEVersion) + } + depl.Spec.Template.Spec.InitContainers[0].Image = containerregistry.GetImagePrefix(images.Get().ProviderRes.Name + ":" + k8sValidVersions[len(k8sValidVersions)-1]) + case result > 0: depl.Spec.Template.Spec.InitContainers[0].Image = images.Get().ProviderRes.FullName() } @@ -240,7 +242,7 @@ func (t *TKE) loadRegistry(ctx context.Context) error { return nil } -func (t *TKE) loginRegistryForUpgrade(ctx context.Context) error { +func (t *TKE) loginRegistry(ctx context.Context) error { containerregistry.Init(t.Para.Config.Registry.Domain(), t.Para.Config.Registry.Namespace()) cmd := exec.Command("docker", "login", "--username", t.Para.Config.Registry.Username(), @@ -257,137 +259,10 @@ func (t *TKE) loginRegistryForUpgrade(ctx context.Context) error { return nil } -func (t *TKE) loadCustomK8sImages(ctx context.Context) error { - files, err := getFilesFromDir(constants.CustomK8sImageDir) - if err != nil { - if os.IsNotExist(err) { - t.log.Infof("%s doesn't exist, skip load custom K8s images", constants.CustomK8sImageDir) - return nil - } - return err - } - for _, file := range files { - err = t.docker.LoadImages(constants.CustomK8sImageDir + file.Name()) - if err != nil { - return err - } - } - return nil -} - -func (t *TKE) buildCustomProviderRes(ctx context.Context) error { - amdDirExists := false - armDirExists := false - - amdFiles, err := getFilesFromDir(constants.CustomK8sBinaryAmdDir) - if err == nil { - amdDirExists = true - } else if !os.IsNotExist(err) { - return err - } - - armFiles, err := getFilesFromDir(constants.CustomK8sBinaryArmDir) - if err == nil { - armDirExists = true - } else if !os.IsNotExist(err) { - return err - } - - if !amdDirExists && !armDirExists { - t.log.Infof("%s and %s don't exist, skip build custom provider res image", constants.CustomK8sBinaryAmdDir, constants.CustomK8sBinaryArmDir) - return nil - } - - if err := addCustomK8sVersionMap(append(amdFiles, armFiles...)); err != nil { - return err - } - - values := map[string]interface{}{ - "ProviderResName": images.Get().ProviderRes.Name, - "Arch": "amd64", - "Tag": images.Get().ProviderRes.Tag, - "HasAmdDir": amdDirExists, - "AmdDir": constants.CustomK8sBinaryAmdDir, - "HasArmDir": armDirExists, - "ArmDir": constants.CustomK8sBinaryArmDir, - } - - amdDockerfile, err := genCustomProviderResDockerfile(values) - if err != nil { - return err - } - values["Arch"] = "arm64" - armDockerfile, err := genCustomProviderResDockerfile(values) - if err != nil { - return err - } - - if t.Config.CustomProviderResTag == "" { - // Use timestamp as custom provider res tag. - t.Config.CustomProviderResTag = fmt.Sprint(time.Now().Unix()) - } - nameWithoutArch := "tkestack/" + images.Get().ProviderRes.Name - - amdTarget := nameWithoutArch + "-amd64:" + t.Config.CustomProviderResTag - err = t.docker.BuildImage(amdDockerfile, amdTarget, "linux/amd64") - if err != nil { - return err - } - - armTarget := nameWithoutArch + "-arm64:" + t.Config.CustomProviderResTag - err = t.docker.BuildImage(armDockerfile, armTarget, "linux/arm64") - if err != nil { - return err - } - return nil -} - -func genCustomProviderResDockerfile(values map[string]interface{}) ([]byte, error) { - dockerfileTpl := `FROM tkestack/{{ .ProviderResName }}-{{ .Arch }}:{{ .Tag }} - -WORKDIR /data - -{{- if .HasAmdDir }} -COPY {{ .AmdDir }}* res/linux-amd64/ -{{- end }} - -{{- if .HasArmDir }} -COPY {{ .ArmDir }}* res/linux-arm64/ -{{- end }} - -ENTRYPOINT ["sh"]` - return template.ParseString(dockerfileTpl, values) -} - -func getFilesFromDir(path string) (files []os.FileInfo, err error) { - files = []os.FileInfo{} - imageDir, err := os.Stat(path) - if err != nil { - return files, err - } - if !imageDir.IsDir() { - return files, errors.Errorf("%s is not a dir", path) - } - files, err = ioutil.ReadDir(path) - return files, err -} - -func addCustomK8sVersionMap(files []os.FileInfo) error { - versionMap := map[string]bool{} - for _, file := range files { - fileRegexp := regexp.MustCompile(`^[\w-]+-v([\d\.]+).tar.gz$`) - version := fileRegexp.FindStringSubmatch(file.Name()) - if len(version) > 1 { - versionMap[version[1]] = true - } - } - - if len(versionMap) == 0 { - return errors.New("can't find any custom K8s version") - } - - for key := range versionMap { - spec.K8sValidVersions = append(spec.K8sValidVersions, key) - } - return nil +func (t *TKE) getPlatformVersions(ctx context.Context) (tkeVersion string, k8sValidVersions []string, err error) { + k8sValidVersions = []string{} + clusterInfo, err := t.globalClient.CoreV1().ConfigMaps("kube-public").Get(ctx, "cluster-info", metav1.GetOptions{}) + tkeVersion = clusterInfo.Data["tkeVersion"] + err = json.Unmarshal([]byte(clusterInfo.Data["k8sValidVersions"]), &k8sValidVersions) + return } diff --git a/cmd/tke-installer/app/options/options.go b/cmd/tke-installer/app/options/options.go index e543eebe46..bb800a7495 100644 --- a/cmd/tke-installer/app/options/options.go +++ b/cmd/tke-installer/app/options/options.go @@ -20,6 +20,7 @@ package options import ( "github.com/spf13/pflag" + "tkestack.io/tke/cmd/tke-installer/app/installer/constants" "tkestack.io/tke/pkg/util/log" ) @@ -33,11 +34,13 @@ type Options struct { SyncProjectsWithNamespaces *bool Replicas *int Upgrade *bool + PrepareCustomK8sImages *bool Kubeconfig *string RegistryUsername *string RegistryPassword *string RegistryDomain *string RegistryNamespace *string + CustomUpgradeResourceDir *string } // NewOptions creates a new Options with a default config. @@ -58,11 +61,13 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) { o.SyncProjectsWithNamespaces = fs.Bool("sync-projects-with-namespaces", false, "Enable creating/deleting the corresponding namespace when creating/deleting a project.") o.Replicas = fs.Int("replicas", 2, "tke components replicas") o.Upgrade = fs.Bool("upgrade", false, "upgrade") + o.PrepareCustomK8sImages = fs.Bool("prepare-custom-images", false, "prepare images for custom K8s version") o.Kubeconfig = fs.String("kubeconfig", "conf/kubeconfig", "specify kubeconfig for upgrade") o.RegistryUsername = fs.String("username", "", "specify registry username for upgrade") o.RegistryPassword = fs.String("password", "", "specify registry password for upgrade") o.RegistryDomain = fs.String("domain", "", "specify registry domain for upgrade") o.RegistryNamespace = fs.String("namespace", "", "specify registry namespace for upgrade") + o.CustomUpgradeResourceDir = fs.String("upgrade-resource-dir", constants.DefaultCustomResourceDir, "specify custom upgrade resource dir for prepare custom K8s images") } // ApplyFlags parsing parameters from the command line or configuration file diff --git a/docs/guide/zh-CN/best-practices/offline-pot/install-tke-installer.sh b/docs/guide/zh-CN/best-practices/offline-pot/install-tke-installer.sh index 0b58e1bbec..22023571f6 100755 --- a/docs/guide/zh-CN/best-practices/offline-pot/install-tke-installer.sh +++ b/docs/guide/zh-CN/best-practices/offline-pot/install-tke-installer.sh @@ -49,7 +49,7 @@ reinstall_tke_installer(){ if [ `docker ps -a | grep tke-installer | wc -l` -eq 1 ]; then docker rm -f tke-installer # clean data dir except images and bins which are created by user for custom K8s upgrade - find /opt/tke-installer/data/* |egrep -v "(images|bins)" | xargs rm -rf + find /opt/tke-installer/data/* |egrep -v "(custom_upgrade_resource)" | xargs rm -rf fi if [ `echo "$version" | awk -Fv '{print $2}' | awk -F. '{print $1$2$3}'` -lt 130 ]; then TKT_INSTALLER_IMAGE="tkestack/tke-installer:${version}" diff --git a/pkg/util/version/version_test.go b/pkg/util/version/version_test.go index 934e838cf4..323e1096b8 100644 --- a/pkg/util/version/version_test.go +++ b/pkg/util/version/version_test.go @@ -50,6 +50,9 @@ func TestCompare(t *testing.T) { {"comp 3", "1.0-alpha", "1.0-", lt}, {"comp 4", "1.0+build1", "1.0build1.1", lt}, {"comp 5", "1.0.build1.1", "1.0build", gt}, + {"comp 6", "1.5.0", "1.5.0", eq}, + {"comp 7", "1.5.1", "1.5.0", gt}, + {"comp 8", "1.6.0", "1.5.1", gt}, } for _, rt := range tests {