github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/builder/tools/migrate_scripts.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package tools 21 22 import ( 23 "fmt" 24 "io" 25 "os" 26 "path/filepath" 27 "strings" 28 29 "github.com/spf13/cobra" 30 corev1 "k8s.io/api/core/v1" 31 "k8s.io/cli-runtime/pkg/genericiooptions" 32 cmdutil "k8s.io/kubectl/pkg/cmd/util" 33 "k8s.io/kubectl/pkg/util/templates" 34 "sigs.k8s.io/controller-runtime/pkg/client" 35 36 "github.com/1aal/kubeblocks/pkg/cli/cmd/builder/template" 37 "github.com/1aal/kubeblocks/pkg/cli/printer" 38 "github.com/1aal/kubeblocks/pkg/cli/util" 39 cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core" 40 cfgutil "github.com/1aal/kubeblocks/pkg/configuration/util" 41 "github.com/1aal/kubeblocks/pkg/generics" 42 ) 43 44 type migrateOptions struct { 45 genericiooptions.IOStreams 46 47 Factory cmdutil.Factory 48 // dynamic dynamic.Interface 49 50 helmTemplateDir string 51 scriptsOutputPath string 52 regex string 53 cmName string 54 overwrite bool 55 } 56 57 func (o *migrateOptions) complete() error { 58 if o.helmTemplateDir == "" { 59 return cfgcore.MakeError("helm template dir is required") 60 } 61 if ok, _ := cfgutil.CheckPathExists(o.helmTemplateDir); !ok { 62 return cfgcore.MakeError("helm template dir is not exists") 63 } 64 if o.regex == "" && o.cmName == "" { 65 return cfgcore.MakeError("regex or cm name are required") 66 } 67 68 if o.scriptsOutputPath == "" { 69 return cfgcore.MakeError("scripts output path is required") 70 } 71 72 ok, err := cfgutil.CheckPathExists(o.scriptsOutputPath) 73 if err != nil { 74 return err 75 } 76 if !ok { 77 err = os.MkdirAll(o.scriptsOutputPath, os.ModePerm) 78 } 79 return err 80 } 81 82 func (o *migrateOptions) run() error { 83 tmpDir, err := os.MkdirTemp(os.TempDir(), "tmp-") 84 if err != nil { 85 return err 86 } 87 defer os.RemoveAll(tmpDir) 88 89 output := filepath.Join(tmpDir, "helm-output") 90 if err := template.HelmTemplate(o.helmTemplateDir, output); err != nil { 91 return err 92 } 93 94 allObjects, err := template.CreateObjectsFromDirectory(output) 95 if err != nil { 96 return err 97 } 98 99 if o.cmName != "" { 100 return o.processSpecConfigMap(allObjects) 101 } 102 _ = template.GetTypedResourceObjectBySignature(allObjects, generics.ConfigMapSignature, o.processConfigMap) 103 return nil 104 } 105 106 func (o *migrateOptions) processSpecConfigMap(objects []client.Object) error { 107 cm := template.GetTypedResourceObjectBySignature(objects, generics.ConfigMapSignature, template.WithResourceName(o.cmName)) 108 if cm == nil { 109 return cfgcore.MakeError("configmap %s not found", o.cmName) 110 } 111 dumpHelmScripts(cm.Data, o.scriptsOutputPath, o.Out, o.overwrite) 112 return nil 113 } 114 115 func (o *migrateOptions) processConfigMap(object client.Object) (r bool) { 116 r = false 117 cm, ok := object.(*corev1.ConfigMap) 118 if !ok { 119 return 120 } 121 if strings.Contains(cm.Name, "script") { 122 dumpHelmScripts(cm.Data, o.scriptsOutputPath, o.Out, o.overwrite) 123 } 124 return 125 } 126 127 func dumpHelmScripts(data map[string]string, outputPath string, out io.Writer, overwrite bool) { 128 if outputPath == "" { 129 return 130 } 131 for k, v := range data { 132 f := filepath.Join(outputPath, k) 133 if ok, _ := cfgutil.CheckPathExists(f); ok { 134 fmt.Fprintf(out, "file [%s] is exists\n", printer.BoldRed(k)) 135 if !overwrite { 136 os.Exit(-1) 137 } 138 } 139 util.CheckErr(os.WriteFile(f, []byte(v), os.ModePerm)) 140 } 141 } 142 143 func (o *migrateOptions) buildFlags(cmd *cobra.Command) { 144 cmd.Flags().StringVar(&o.helmTemplateDir, "helm", "", "specify the helm template dir") 145 cmd.Flags().StringVar(&o.scriptsOutputPath, "output", "", "specify the scripts output path") 146 cmd.Flags().StringVar(&o.cmName, "configmap", "", "specify the configmap name") 147 cmd.Flags().StringVar(&o.regex, "regex", "", "specify the regex for configmap") 148 cmd.Flags().BoolVar(&o.overwrite, "force", false, "whether overwrite the exists file") 149 } 150 151 var migrateExamples = templates.Examples(` 152 `) 153 154 func NewMigrateHelmScriptsCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command { 155 o := &migrateOptions{ 156 Factory: f, 157 IOStreams: streams, 158 } 159 cmd := &cobra.Command{ 160 Use: "migrate-scripts", 161 Aliases: []string{"migrate"}, 162 Short: "migrate - a developer tool.", 163 Example: migrateExamples, 164 Run: func(cmd *cobra.Command, args []string) { 165 util.CheckErr(o.complete()) 166 util.CheckErr(o.run()) 167 }, 168 } 169 o.buildFlags(cmd) 170 return cmd 171 }