@@ -27,7 +27,13 @@ import (
2727 "strings"
2828
2929 "github.com/Masterminds/semver/v3"
30+ kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
31+ "github.com/apecloud/kubeblocks/pkg/constant"
3032 "github.com/spf13/cobra"
33+ helmaction "helm.sh/helm/v3/pkg/action"
34+ "helm.sh/helm/v3/pkg/chart/loader"
35+ "helm.sh/helm/v3/pkg/releaseutil"
36+ apierrors "k8s.io/apimachinery/pkg/api/errors"
3137 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3238 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3339 "k8s.io/apimachinery/pkg/runtime"
@@ -37,13 +43,16 @@ import (
3743 "k8s.io/client-go/kubernetes"
3844 cmdutil "k8s.io/kubectl/pkg/cmd/util"
3945 "k8s.io/kubectl/pkg/util/templates"
46+ "sigs.k8s.io/yaml"
4047
4148 extensionsv1alpha1 "github.com/apecloud/kubeblocks/apis/extensions/v1alpha1"
4249
50+ "github.com/apecloud/kbcli/pkg/cluster"
4351 clusterCmd "github.com/apecloud/kbcli/pkg/cmd/cluster"
4452 "github.com/apecloud/kbcli/pkg/printer"
4553 "github.com/apecloud/kbcli/pkg/types"
4654 "github.com/apecloud/kbcli/pkg/util"
55+ "github.com/apecloud/kbcli/pkg/util/helm"
4756)
4857
4958var addonInstallExample = templates .Examples (`
@@ -136,6 +145,7 @@ func newInstallCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra
136145 o .name = args [0 ]
137146 util .CheckErr (o .Complete ())
138147 util .CheckErr (o .Validate ())
148+ util .CheckErr (o .process09ClusterDefAndComponentVersions ())
139149 util .CheckErr (o .Run (f , streams ))
140150 // avoid unnecessary messages for upgrade
141151 fmt .Fprintf (o .Out , "addon %s installed successfully\n " , o .name )
@@ -304,3 +314,106 @@ func validateVersion(annotations, kbVersion string) (bool, error) {
304314 validate , _ := constraint .Validate (v )
305315 return validate , nil
306316}
317+
318+ func (o * installOption ) process09ClusterDefAndComponentVersions () error {
319+ kbDeploys , err := util .GetKBDeploys (o .Client , util .KubeblocksAppComponent , metav1 .NamespaceAll )
320+ if err != nil || len (kbDeploys ) < 2 {
321+ return err
322+ }
323+ var newKBNamespace string
324+ for _ , v := range kbDeploys {
325+ if strings .HasPrefix (v .Labels [constant .AppVersionLabelKey ], "1.0" ) {
326+ newKBNamespace = v .Namespace
327+ break
328+ }
329+ }
330+ // 1. get manifests from the helm repo
331+ chartsDownloader , err := helm .NewDownloader (helm .NewConfig (newKBNamespace , "" , "" , false ))
332+ if err != nil {
333+ return err
334+ }
335+ // DownloadTo can't specify the saved name, so download it to TempDir and rename it when copy
336+ chartPath , _ , err := chartsDownloader .DownloadTo (o .addon .Spec .Helm .ChartLocationURL , "" , cluster .CliChartsCacheDir )
337+ if err != nil {
338+ return err
339+ }
340+ // 2. overwrite the spec of ClusterDefinition and ComponentVersion with the new version
341+ actionCfg , err := helm .NewActionConfig (helm .NewConfig (newKBNamespace , "" , "" , false ))
342+ if err != nil {
343+ return err
344+ }
345+ chart , err := loader .Load (chartPath )
346+ if err != nil {
347+ return err
348+ }
349+ renderer := helmaction .NewInstall (actionCfg )
350+ renderer .ReleaseName = o .addon .Name + "for-upgrade"
351+ renderer .Namespace = newKBNamespace
352+ renderer .DryRun = true
353+ renderer .Replace = true
354+ renderer .ClientOnly = true
355+ valuesMap := map [string ]interface {}{}
356+ if o .addon .Spec .Helm != nil {
357+ for _ , v := range o .addon .Spec .Helm .InstallValues .SetValues {
358+ keyValues := strings .Split (v , "=" )
359+ if len (keyValues ) != 2 {
360+ return fmt .Errorf ("invalid install value: %s" , v )
361+ }
362+ valuesMap [keyValues [0 ]] = keyValues [1 ]
363+ }
364+ }
365+ release , err := renderer .Run (chart , valuesMap )
366+ if err != nil {
367+ return err
368+ }
369+
370+ updateObject := func (obj runtime.Object , gvr schema.GroupVersionResource ) error {
371+ unstructuredObj := obj .(* unstructured.Unstructured )
372+ targetObj , err := o .Dynamic .Resource (gvr ).Namespace ("" ).Get (context .TODO (), unstructuredObj .GetName (), metav1.GetOptions {})
373+ if err != nil {
374+ if apierrors .IsNotFound (err ) {
375+ return nil
376+ }
377+ return err
378+ }
379+ annotations := targetObj .GetAnnotations ()
380+ annotations [constant .CRDAPIVersionAnnotationKey ] = kbappsv1 .GroupVersion .String ()
381+ annotations ["meta.helm.sh/release-name" ] = "kb-addon-" + o .addon .Name
382+ annotations ["meta.helm.sh/release-namespace" ] = newKBNamespace
383+ targetObj .SetAnnotations (annotations )
384+ targetObj .Object ["spec" ] = unstructuredObj .Object ["spec" ]
385+ if _ , err = o .Dynamic .Resource (gvr ).Namespace ("" ).Update (context .TODO (), targetObj , metav1.UpdateOptions {}); err != nil {
386+ return err
387+ }
388+ return nil
389+ }
390+ manifests := releaseutil .SplitManifests (release .Manifest )
391+ for _ , manifest := range manifests {
392+
393+ // convert yaml to json
394+ jsonData , err := yaml .YAMLToJSON ([]byte (manifest ))
395+ if err != nil {
396+ return err
397+ }
398+ // check if jsonData is empty or null
399+ if len (jsonData ) == 0 || string (jsonData ) == "null" {
400+ continue
401+ }
402+ // get resource gvk
403+ obj , gvk , err := unstructured .UnstructuredJSONScheme .Decode (jsonData , nil , nil )
404+ if err != nil {
405+ return err
406+ }
407+ switch gvk .Kind {
408+ case types .KindClusterDef :
409+ if err = updateObject (obj , types .ClusterDefGVR ()); err != nil {
410+ return err
411+ }
412+ case types .KindComponentVersion :
413+ if err = updateObject (obj , types .ComponentVersionsGVR ()); err != nil {
414+ return err
415+ }
416+ }
417+ }
418+ return nil
419+ }
0 commit comments