github.com/verrazzano/verrazzano@v1.7.0/tools/charts-manager/vcm/cmd/pull/pull.go (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package pull 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "github.com/spf13/cobra" 13 vcmhelpers "github.com/verrazzano/verrazzano/tools/charts-manager/vcm/cmd/helpers" 14 "github.com/verrazzano/verrazzano/tools/charts-manager/vcm/pkg/constants" 15 "github.com/verrazzano/verrazzano/tools/charts-manager/vcm/pkg/fs" 16 "github.com/verrazzano/verrazzano/tools/charts-manager/vcm/pkg/helm" 17 cmdhelpers "github.com/verrazzano/verrazzano/tools/vz/cmd/helpers" 18 "github.com/verrazzano/verrazzano/tools/vz/pkg/helpers" 19 ) 20 21 const ( 22 CommandName = "pull" 23 helpShort = "Pulls an upstream chart/version" 24 helpLong = `The command 'pull' pulls an upstream chart from a given helm repo url and unpacks that to a charts directory.` 25 ErrPatchVersionNotFound = "unable to find version to patch, error %v" 26 ErrPatchNotGenerated = "unable to generate patch file, error %v" 27 ErrPatchNotApplied = "unable to apply patch file %s, error %v" 28 ErrPatchNotRemoved = "unable to remove patch file at %v, error %v" 29 ErrPatchReview = "please review patch file at %s and applied changes" 30 ) 31 32 func buildExample() string { 33 examples := []string{fmt.Sprintf(constants.CommandWithFlagExampleFormat+" "+ 34 constants.FlagExampleFormat+" "+ 35 constants.FlagExampleFormat+" "+ 36 constants.FlagExampleFormat, 37 CommandName, constants.FlagChartName, constants.FlagChartShorthand, constants.FlagChartExampleKeycloak, 38 constants.FlagVersionName, constants.FlagPatchVersionShorthand, constants.FlagVersionExample210, 39 constants.FlagDirName, constants.FlagDirShorthand, constants.FlagDirExampleLocal, 40 constants.FlagRepoName, constants.FlagRepoShorthand, constants.FlagRepoExampleCodecentric)} 41 42 examples = append(examples, "\n") 43 examples = append(examples, fmt.Sprintf(constants.CommandWithFlagExampleFormat, examples[len(examples)-1], 44 constants.FlagTargetVersionName, constants.FlagChartShorthand, constants.FlagTargetVersionExample002)) 45 46 examples = append(examples, "\n") 47 examples = append(examples, fmt.Sprintf(constants.CommandWithFlagExampleFormat, examples[len(examples)-1], 48 constants.FlagUpstreamProvenanceName, constants.FlagUpstreamProvenanceShorthand, constants.FlagUpstreamProvenanceDefault)) 49 50 examples = append(examples, "\n") 51 examples = append(examples, fmt.Sprintf(constants.CommandWithFlagExampleFormat, examples[len(examples)-1], 52 constants.FlagPatchName, constants.FlagPatchShorthand, constants.FlagPatchDefault)) 53 54 examples = append(examples, "\n") 55 examples = append(examples, fmt.Sprintf(constants.CommandWithFlagExampleFormat, examples[len(examples)-1], 56 constants.FlagPatchVersionName, constants.FlagPatchVersionShorthand, constants.FlagPatchVersionExample001)) 57 58 return fmt.Sprintln(examples) 59 } 60 61 // NewCmdPull creates a new instance of pull cmd. 62 func NewCmdPull(vzHelper helpers.VZHelper, inHfs fs.ChartFileSystem, inHelmConfig helm.HelmConfig) *cobra.Command { 63 cmd := cmdhelpers.NewCommand(vzHelper, CommandName, helpShort, helpLong) 64 cmd.RunE = func(cmd *cobra.Command, args []string) error { 65 var hfs fs.ChartFileSystem 66 var helmConfig helm.HelmConfig 67 if inHfs == nil { 68 hfs = fs.HelmChartFileSystem{} 69 } else { 70 hfs = inHfs 71 } 72 73 if inHelmConfig == nil { 74 var err error 75 helmConfig, err = helm.NewHelmConfig(vzHelper) 76 if err != nil { 77 return fmt.Errorf("unable to init helm config, error %v", err) 78 } 79 } else { 80 helmConfig = inHelmConfig 81 } 82 83 return runCmdPull(cmd, vzHelper, hfs, helmConfig) 84 } 85 cmd.Example = buildExample() 86 cmd.PersistentFlags().StringP(constants.FlagChartName, constants.FlagChartShorthand, "", constants.FlagChartUsage) 87 cmd.PersistentFlags().StringP(constants.FlagVersionName, constants.FlagVersionShorthand, "", constants.FlagVersionUsage) 88 cmd.PersistentFlags().StringP(constants.FlagDirName, constants.FlagDirShorthand, "", constants.FlagDirUsage) 89 cmd.PersistentFlags().StringP(constants.FlagRepoName, constants.FlagRepoShorthand, "", constants.FlagRepoUsage) 90 cmd.PersistentFlags().StringP(constants.FlagTargetVersionName, constants.FlagTargetVersionShorthand, "", constants.FlagTargetVersionUsage) 91 cmd.PersistentFlags().BoolP(constants.FlagUpstreamProvenanceName, constants.FlagUpstreamProvenanceShorthand, constants.FlagUpstreamProvenanceDefault, constants.FlagUpstreamProvenanceUsage) 92 cmd.PersistentFlags().BoolP(constants.FlagPatchName, constants.FlagPatchShorthand, constants.FlagPatchDefault, constants.FlagPatchUsage) 93 cmd.PersistentFlags().StringP(constants.FlagPatchVersionName, constants.FlagPatchVersionShorthand, "", constants.FlagPatchVersionUsage) 94 95 return cmd 96 } 97 98 // runCmdPull - run the "vcm pull" command to pull a chart/version from a helm repo and unpack into a chart dierctory with either the same version 99 // or a target version. Also saves the original chart in a upstream directory and applies any changes that were done to prevopus versions of 100 // this chart in the same charts directory. 101 func runCmdPull(cmd *cobra.Command, vzHelper helpers.VZHelper, hfs fs.ChartFileSystem, helmConfig helm.HelmConfig) error { 102 chart, err := vcmhelpers.GetMandatoryStringFlagValueOrError(cmd, constants.FlagChartName, constants.FlagChartShorthand) 103 if err != nil { 104 return err 105 } 106 107 version, err := vcmhelpers.GetMandatoryStringFlagValueOrError(cmd, constants.FlagVersionName, constants.FlagVersionShorthand) 108 if err != nil { 109 return err 110 } 111 112 chartsDir, err := vcmhelpers.GetMandatoryStringFlagValueOrError(cmd, constants.FlagDirName, constants.FlagDirShorthand) 113 if err != nil { 114 return err 115 } 116 117 repo, err := vcmhelpers.GetMandatoryStringFlagValueOrError(cmd, constants.FlagRepoName, constants.FlagRepoShorthand) 118 if err != nil { 119 return err 120 } 121 122 targetVersion, err := cmd.PersistentFlags().GetString(constants.FlagTargetVersionName) 123 if err != nil { 124 return err 125 } 126 127 if targetVersion == "" { 128 targetVersion = version 129 } 130 131 if len(strings.TrimSpace(targetVersion)) == 0 { 132 return fmt.Errorf(vcmhelpers.ErrFormatNotEmpty, constants.FlagTargetVersionName) 133 } 134 135 saveUpstream, err := cmd.PersistentFlags().GetBool(constants.FlagUpstreamProvenanceName) 136 if err != nil { 137 return err 138 } 139 140 patchDiffs, err := cmd.PersistentFlags().GetBool(constants.FlagPatchName) 141 if err != nil { 142 return err 143 } 144 145 var patchVersion string 146 if patchDiffs { 147 patchVersion, err = cmd.PersistentFlags().GetString(constants.FlagPatchVersionName) 148 if err != nil { 149 return err 150 } 151 } 152 153 fmt.Fprintf(vzHelper.GetOutputStream(), "Adding/Updtaing %s chart repo with url %s..\n", chart, repo) 154 repoName, err := helmConfig.AddAndUpdateChartRepo(chart, repo) 155 if err != nil { 156 return err 157 } 158 159 fmt.Fprintf(vzHelper.GetOutputStream(), "Pulling %s chart version %s to target version %s..\n", chart, version, targetVersion) 160 err = helmConfig.DownloadChart(chart, repoName, version, targetVersion, chartsDir) 161 if err != nil { 162 return err 163 } 164 165 err = hfs.RearrangeChartDirectory(chartsDir, chart, targetVersion) 166 if err != nil { 167 return err 168 } 169 170 fmt.Fprintf(vzHelper.GetOutputStream(), "Pulled chart %s version %s to target version %s from %s to %s/%s/%s.\n", chart, version, targetVersion, repo, chartsDir, chart, targetVersion) 171 if saveUpstream { 172 fmt.Fprintf(vzHelper.GetOutputStream(), "Saving upstream chart..\n") 173 err = hfs.SaveUpstreamChart(chartsDir, chart, version, targetVersion) 174 if err != nil { 175 return err 176 } 177 178 upstreamChartDir, err := filepath.Abs(fmt.Sprintf("%s/../provenance/%s/upstreams/%s", chartsDir, chart, version)) 179 if err != nil { 180 return err 181 } 182 183 fmt.Fprintf(vzHelper.GetOutputStream(), "Upstream chart saved to %s.\n", upstreamChartDir) 184 fmt.Fprintf(vzHelper.GetOutputStream(), "Saving chart provenance file..\n") 185 chartProvenance, err := helmConfig.GetChartProvenance(chart, repo, version) 186 if err != nil { 187 return err 188 } 189 190 err = hfs.SaveChartProvenance(chartsDir, chartProvenance, chart, targetVersion) 191 if err != nil { 192 return err 193 } 194 195 provenanceFile, err := filepath.Abs(fmt.Sprintf("%s/../provenance/%s/%s.yaml", chartsDir, chart, targetVersion)) 196 if err != nil { 197 return err 198 } 199 200 fmt.Fprintf(vzHelper.GetOutputStream(), "Upstream provenance manifest created in %s.\n", provenanceFile) 201 } 202 203 if patchDiffs { 204 if patchVersion == "" { 205 patchVersion, err = hfs.FindChartVersionToPatch(chartsDir, chart, targetVersion) 206 if err != nil { 207 return fmt.Errorf(ErrPatchVersionNotFound, err) 208 } 209 } 210 211 if patchVersion != "" { 212 patchFile, err := hfs.GeneratePatchFile(chartsDir, chart, patchVersion) 213 if err != nil { 214 return fmt.Errorf(ErrPatchNotGenerated, err) 215 } 216 217 if patchFile == "" { 218 fmt.Fprintf(vzHelper.GetOutputStream(), "Nothing to patch from previous version.\n") 219 return nil 220 } 221 222 rejectsFileGenerated, err := hfs.ApplyPatchFile(chartsDir, vzHelper, chart, targetVersion, patchFile) 223 if err != nil { 224 return fmt.Errorf(ErrPatchNotApplied, patchFile, err) 225 } 226 227 if !rejectsFileGenerated { 228 fmt.Fprintf(vzHelper.GetOutputStream(), "Any diffs from version %s has been applied.\n", patchVersion) 229 err = os.Remove(patchFile) 230 if err != nil { 231 return fmt.Errorf(ErrPatchNotRemoved, patchFile, err) 232 } 233 } else { 234 return fmt.Errorf(ErrPatchReview, patchFile) 235 } 236 } 237 } 238 return nil 239 }