From 3357e8b4e68b0011f7b9fb61d876f076b4fd4b16 Mon Sep 17 00:00:00 2001 From: jelipo Date: Wed, 29 Jul 2026 17:25:03 +0800 Subject: [PATCH] feat: support local files for kubeblocks upgrade --- pkg/cmd/kubeblocks/install.go | 20 ++++++++++++----- pkg/cmd/kubeblocks/upgrade.go | 21 +++++++++++------- pkg/cmd/kubeblocks/util.go | 42 ++++++++++++++++++++++------------- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/pkg/cmd/kubeblocks/install.go b/pkg/cmd/kubeblocks/install.go index b3ec5b49c..efbb854c0 100644 --- a/pkg/cmd/kubeblocks/install.go +++ b/pkg/cmd/kubeblocks/install.go @@ -82,6 +82,8 @@ type InstallOptions struct { Options OldVersion string Version string + chartFile string + crdsFile string Quiet bool CreateNamespace bool Check bool @@ -293,7 +295,7 @@ func (o *InstallOptions) Install() error { // create or update crds s := spinner.New(o.Out, spinnerMsg("Create CRDs")) defer s.Fail() - if err = createOrUpdateCRDS(o.Dynamic, o.Version); err != nil { + if err = createOrUpdateCRDS(o.Dynamic, o.Version, ""); err != nil { return fmt.Errorf("install crds failed: %s", err.Error()) } s.Success() @@ -502,11 +504,13 @@ func (o *InstallOptions) checkVersion(v util.Version) error { } // check installing version exists - if exists, err := versionExists(o.Version); !exists { - if err != nil { - return err + if o.chartFile == "" { + if exists, err := versionExists(o.Version); !exists { + if err != nil { + return err + } + return fmt.Errorf("version %s does not exist, please use \"kbcli kubeblocks list-versions --devel\" to show the available versions", o.Version) } - return fmt.Errorf("version %s does not exist, please use \"kbcli kubeblocks list-versions --devel\" to show the available versions", o.Version) } versionErr := fmt.Errorf("failed to get kubernetes version") @@ -611,9 +615,13 @@ func (o *InstallOptions) printNotes() { } func (o *InstallOptions) buildChart() *helm.InstallOpts { + chart := types.KubeBlocksChartName + "/" + types.KubeBlocksChartName + if o.chartFile != "" { + chart = o.chartFile + } return &helm.InstallOpts{ Name: types.KubeBlocksChartName, - Chart: types.KubeBlocksChartName + "/" + types.KubeBlocksChartName, + Chart: chart, Wait: o.Wait, Version: o.Version, Namespace: o.HelmCfg.Namespace(), diff --git a/pkg/cmd/kubeblocks/upgrade.go b/pkg/cmd/kubeblocks/upgrade.go index d93e932d5..8f2b9db06 100644 --- a/pkg/cmd/kubeblocks/upgrade.go +++ b/pkg/cmd/kubeblocks/upgrade.go @@ -82,6 +82,8 @@ func newUpgradeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra } cmd.Flags().StringVar(&o.Version, "version", "", "Set KubeBlocks version") + cmd.Flags().StringVar(&o.chartFile, "chart-file", "", "Path to the KubeBlocks Helm chart") + cmd.Flags().StringVar(&o.crdsFile, "crds-file", "", "Path to the KubeBlocks CRDs") cmd.Flags().StringVarP(&o.Namespace, "namespace", "n", "", "KubeBlocks namespace") cmd.Flags().BoolVar(&o.Check, "check", true, "Check kubernetes environment before upgrade") cmd.Flags().DurationVar(&o.Timeout, "timeout", 1800*time.Second, "Time to wait for upgrading KubeBlocks, such as --timeout=10m") @@ -177,14 +179,17 @@ func (o *InstallOptions) Upgrade() error { } } - // add helm repo - s := spinner.New(o.Out, spinnerMsg("Add and update repo %s", types.KubeBlocksChartName)) - defer s.Fail() - // Add repo, if exists, will update it - if err = helm.AddRepo(newHelmRepoEntry()); err != nil { - return err + var s spinner.Interface + if o.chartFile == "" { + // add helm repo + s = spinner.New(o.Out, spinnerMsg("Add and update repo %s", types.KubeBlocksChartName)) + defer s.Fail() + // Add repo, if exists, will update it + if err = helm.AddRepo(newHelmRepoEntry()); err != nil { + return err + } + s.Success() } - s.Success() // it's time to upgrade msg := "" @@ -229,7 +234,7 @@ func (o *InstallOptions) Upgrade() error { // create or update crds s = spinner.New(o.Out, spinnerMsg("Upgrade CRDs")) defer s.Fail() - if err = createOrUpdateCRDS(o.Dynamic, o.Version); err != nil { + if err = createOrUpdateCRDS(o.Dynamic, o.Version, o.crdsFile); err != nil { return fmt.Errorf("upgrade crds failed: %s", err.Error()) } s.Success() diff --git a/pkg/cmd/kubeblocks/util.go b/pkg/cmd/kubeblocks/util.go index b58b6906e..7da69a13c 100644 --- a/pkg/cmd/kubeblocks/util.go +++ b/pkg/cmd/kubeblocks/util.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "net/http" + "os" "sort" "strings" "time" @@ -317,23 +318,32 @@ func newHelmRepoEntry() *repo.Entry { } // createOrUpdateCRDS creates or updates the kubeBlocks crds. -func createOrUpdateCRDS(dynamic dynamic.Interface, kbVersion string) error { - if kbVersion == "" { - kbVersion = version.GetVersion() - } - crdsURL := util.GetKubeBlocksCRDsURL(kbVersion) - resp, err := http.Get(crdsURL) - if err != nil { - return err - } - if resp.StatusCode == http.StatusNotFound { - fmt.Printf("not found CRDs from %s, please specify the right version", crdsURL) - return nil - } else if resp.StatusCode != http.StatusOK { - return fmt.Errorf("failed to download CRDs from %s", crdsURL) +func createOrUpdateCRDS(dynamic dynamic.Interface, kbVersion, crdsFile string) error { + var reader io.ReadCloser + var err error + if crdsFile != "" { + if reader, err = os.Open(crdsFile); err != nil { + return err + } + } else { + if kbVersion == "" { + kbVersion = version.GetVersion() + } + crdsURL := util.GetKubeBlocksCRDsURL(kbVersion) + resp, err := http.Get(crdsURL) + if err != nil { + return err + } + if resp.StatusCode == http.StatusNotFound { + fmt.Printf("not found CRDs from %s, please specify the right version", crdsURL) + return nil + } else if resp.StatusCode != http.StatusOK { + return fmt.Errorf("failed to download CRDs from %s", crdsURL) + } + reader = resp.Body } - defer resp.Body.Close() - d := yaml.NewYAMLToJSONDecoder(resp.Body) + defer reader.Close() + d := yaml.NewYAMLToJSONDecoder(reader) var objs []unstructured.Unstructured for { var obj unstructured.Unstructured