github.com/jenkins-x/jx/v2@v2.1.155/pkg/cmd/step/create/step_create_templated_config.go (about) 1 package create 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "path/filepath" 8 "text/template" 9 10 "github.com/jenkins-x/jx-logging/pkg/log" 11 "github.com/jenkins-x/jx/v2/pkg/cmd/helper" 12 "github.com/jenkins-x/jx/v2/pkg/cmd/opts" 13 "github.com/jenkins-x/jx/v2/pkg/cmd/opts/step" 14 "github.com/jenkins-x/jx/v2/pkg/cmd/templates" 15 "github.com/jenkins-x/jx/v2/pkg/config" 16 "github.com/jenkins-x/jx/v2/pkg/helm" 17 "github.com/jenkins-x/jx/v2/pkg/util" 18 "github.com/pkg/errors" 19 "github.com/spf13/cobra" 20 "k8s.io/helm/pkg/chartutil" 21 ) 22 23 var ( 24 createTemplatedConfigLong = templates.LongDesc(` 25 Creates a config file from a Go template file and a jx requirements file 26 `) 27 28 createTemplatedConfigExample = templates.Examples(` 29 # creates a config file from a template file and a jx requirements file 30 jx step create templated config -t config.tmpl.yml -c config.yml 31 `) 32 ) 33 34 const ( 35 templateFileOption = "template-file" 36 parametersFileOption = "parameters-file" 37 requirementsDirOption = "requirements-dir" 38 configFileOption = "config-file" 39 ) 40 41 // StepCreateTemplatedConfigOptions command line flags 42 type StepCreateTemplatedConfigOptions struct { 43 step.StepOptions 44 45 TemplateFile string 46 ParametersFile string 47 RequirementsDir string 48 ConfigFile string 49 } 50 51 // NewCmdStepCreateTemplatedConfig Creates a new Command object 52 func NewCmdStepCreateTemplatedConfig(commonOpts *opts.CommonOptions) *cobra.Command { 53 options := &StepCreateTemplatedConfigOptions{ 54 StepOptions: step.StepOptions{ 55 CommonOptions: commonOpts, 56 }, 57 } 58 59 cmd := &cobra.Command{ 60 Use: "templated config", 61 Short: "Create a YAML config file from a Go template file and a jx requirements file", 62 Long: createTemplatedConfigLong, 63 Example: createTemplatedConfigExample, 64 Run: func(cmd *cobra.Command, args []string) { 65 options.Cmd = cmd 66 options.Args = args 67 err := options.Run() 68 helper.CheckErr(err) 69 }, 70 } 71 72 cmd.Flags().StringVarP(&options.TemplateFile, templateFileOption, "t", "", "The template file used to render the config YAML file") 73 cmd.Flags().StringVarP(&options.ParametersFile, parametersFileOption, "p", "", "The values file used as parameters in the template file") 74 cmd.Flags().StringVarP(&options.RequirementsDir, requirementsDirOption, "r", ".", "The jx requirements file directory") 75 cmd.Flags().StringVarP(&options.ConfigFile, configFileOption, "c", "", "The rendered config YAML file") 76 77 return cmd 78 } 79 80 func (o *StepCreateTemplatedConfigOptions) checkFlags() error { 81 if o.TemplateFile == "" { 82 return util.MissingArgument(templateFileOption) 83 } 84 85 if o.ParametersFile != "" { 86 parametersFile := filepath.Base(o.ParametersFile) 87 if parametersFile != helm.ParametersYAMLFile { 88 return fmt.Errorf("provided parameters file %q must be named %q", parametersFile, helm.ParametersYAMLFile) 89 } 90 } 91 92 if exists, err := util.FileExists(o.TemplateFile); err != nil || !exists { 93 return fmt.Errorf("template file %q provided in option %q does not exist", o.TemplateFile, templateFileOption) 94 } 95 96 if o.ConfigFile == "" { 97 // Override the rendered config file with the template file if it is not specified 98 o.ConfigFile = o.TemplateFile 99 } 100 101 return nil 102 } 103 104 // Run implements this command 105 func (o *StepCreateTemplatedConfigOptions) Run() error { 106 if err := o.checkFlags(); err != nil { 107 return err 108 } 109 requirements, _, err := config.LoadRequirementsConfig(o.RequirementsDir, config.DefaultFailOnValidationError) 110 if err != nil { 111 return errors.Wrapf(err, "loading requirements file form dir %q", o.RequirementsDir) 112 } 113 data, err := o.renderTemplate(requirements) 114 if err != nil { 115 return errors.Wrapf(err, "rendering the config template using the requirements from dir %q", o.RequirementsDir) 116 } 117 if err := ioutil.WriteFile(o.ConfigFile, data, util.DefaultFileWritePermissions); err != nil { 118 return errors.Wrapf(err, "writing the rendered config into file %q", o.ConfigFile) 119 } 120 121 log.Logger().Infof("Saved the rendered configuration into %s file", o.ConfigFile) 122 123 return nil 124 } 125 126 func (o *StepCreateTemplatedConfigOptions) renderTemplate(requirements *config.RequirementsConfig) ([]byte, error) { 127 templateName := filepath.Base(o.TemplateFile) 128 tmpl, err := template.New(templateName).Option("missingkey=error").ParseFiles(o.TemplateFile) 129 if err != nil { 130 return nil, errors.Wrap(err, "parsing the template file") 131 } 132 requirementsMap, err := requirements.ToMap() 133 if err != nil { 134 return nil, errors.Wrapf(err, "converting requirements into a map: %v", requirements) 135 } 136 params, err := o.parameters() 137 if err != nil { 138 return nil, errors.Wrapf(err, "loading the parameter values") 139 } 140 141 tmplData := map[string]interface{}{ 142 "Requirements": requirementsMap, 143 "Parameters": params, 144 } 145 146 var buf bytes.Buffer 147 err = tmpl.Execute(&buf, tmplData) 148 if err != nil { 149 return nil, errors.Wrapf(err, "rendering the template file: %s", o.TemplateFile) 150 } 151 return buf.Bytes(), nil 152 } 153 154 // parameters loads the parameters from file without solving the secrets URIs 155 func (o *StepCreateTemplatedConfigOptions) parameters() (chartutil.Values, error) { 156 if o.ParametersFile == "" { 157 return chartutil.Values{}, nil 158 } 159 paramsDir := filepath.Dir(o.ParametersFile) 160 return helm.LoadParameters(paramsDir, nil) 161 }