github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/edit/edit_deploy.go (about) 1 package edit 2 3 import ( 4 "fmt" 5 "strings" 6 7 v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1" 8 "github.com/jenkins-x/jx-logging/pkg/log" 9 "github.com/olli-ai/jx/v2/pkg/cmd/helper" 10 "github.com/olli-ai/jx/v2/pkg/util" 11 "github.com/spf13/cobra" 12 13 "github.com/olli-ai/jx/v2/pkg/cmd/opts" 14 "github.com/olli-ai/jx/v2/pkg/cmd/templates" 15 ) 16 17 var ( 18 editDeployKindLong = templates.LongDesc(` 19 Edits the deploy kind to use for your project or team 20 `) 21 22 editDeployKindExample = templates.Examples(` 23 # Edit the deploy kind for your current project and prompts you to pick one of the available kinds 24 jx edit deploy 25 26 # to switch to use Knative Serve deployments 27 jx edit deploy knative 28 29 # to switch to normal kubernetes deployments 30 jx edit deploy default 31 32 # to switch to use canary deployments (requires flagger and its dependencies) 33 jx edit deploy --canary 34 35 # to disable canary deployments and don't ask any more questions 36 jx edit deploy --canary=false -b 37 38 # to disable canary deployments and confirm if you want to change the deployment kind and HPA 39 jx edit deploy --canary=false 40 41 # Edit the default deploy kind for your team and be prompted for answers 42 jx edit deploy --team 43 44 # Set the default for your team to use knative and canary but no HPA 45 jx edit deploy --team knative --canary=true --hpa=false 46 `) 47 48 deployKinds = []string{opts.DeployKindKnative, opts.DeployKindDefault} 49 50 knativeDeployKey = "knativeDeploy:" 51 deployCanaryKey = "canary:" 52 deployHPAKey = "hpa:" 53 enabledKey = " enabled:" 54 ) 55 56 // EditDeployKindOptions the options for the create spring command 57 type EditDeployKindOptions struct { 58 EditOptions 59 60 Kind string 61 DeployOptions v1.DeployOptions 62 Dir string 63 Team bool 64 } 65 66 // NewCmdEditDeployKind creates a command object for the "create" command 67 func NewCmdEditDeployKind(commonOpts *opts.CommonOptions) *cobra.Command { 68 cmd, _ := NewCmdEditDeployKindAndOption(commonOpts) 69 return cmd 70 } 71 72 // NewCmdEditDeployKindAndOption creates a command object for the "create" command 73 func NewCmdEditDeployKindAndOption(commonOpts *opts.CommonOptions) (*cobra.Command, *EditDeployKindOptions) { 74 options := &EditDeployKindOptions{ 75 EditOptions: EditOptions{ 76 CommonOptions: commonOpts, 77 }, 78 } 79 80 cmd := &cobra.Command{ 81 Use: "deploy", 82 Short: "Edits the deploy kind to use for your project or team", 83 Long: editDeployKindLong, 84 Example: editDeployKindExample, 85 Run: func(cmd *cobra.Command, args []string) { 86 options.Cmd = cmd 87 options.Args = args 88 err := options.Run() 89 helper.CheckErr(err) 90 }, 91 } 92 cmd.Flags().BoolVarP(&options.Team, "team", "t", false, "Edits the team default") 93 cmd.Flags().StringVarP(&options.Kind, opts.OptionKind, "k", "", fmt.Sprintf("The kind to use which should be one of: %s", strings.Join(deployKinds, ", "))) 94 cmd.Flags().BoolVarP(&options.DeployOptions.Canary, opts.OptionCanary, "", false, "should we use canary rollouts (progressive delivery). e.g. using a Canary deployment via flagger. Requires the installation of flagger and istio/gloo in your cluster") 95 cmd.Flags().BoolVarP(&options.DeployOptions.HPA, opts.OptionHPA, "", false, "should we enable the Horizontal Pod Autoscaler.") 96 options.Cmd = cmd 97 return cmd, options 98 } 99 100 // Run implements the command 101 func (o *EditDeployKindOptions) Run() error { 102 settings, err := o.TeamSettings() 103 if err != nil { 104 return err 105 } 106 if o.Team { 107 teamDeployOptions := settings.GetDeployOptions() 108 name, err := o.pickDeployKind(settings.DeployKind) 109 if err != nil { 110 return err 111 } 112 canary, err := o.pickProgressiveDelivery(teamDeployOptions.Canary) 113 if err != nil { 114 return err 115 } 116 hpa, err := o.pickHPA(teamDeployOptions.HPA) 117 if err != nil { 118 return err 119 } 120 121 callback := func(env *v1.Environment) error { 122 teamSettings := &env.Spec.TeamSettings 123 teamSettings.DeployKind = name 124 125 dopt := &v1.DeployOptions{} 126 if !canary && !hpa { 127 teamSettings.DeployOptions = nil 128 } else { 129 dopt = &v1.DeployOptions{Canary: canary, HPA: hpa} 130 teamSettings.DeployOptions = dopt 131 } 132 133 log.Logger().Infof("Setting the team deploy to kind: %s with canary: %s and HPA: %s", 134 util.ColorInfo(name), util.ColorInfo(toString(dopt.Canary)), util.ColorInfo(toString(dopt.HPA))) 135 return nil 136 } 137 return o.ModifyDevEnvironment(callback) 138 } 139 140 fn := func(text string) (string, error) { 141 defaultName, currentDeployOptions := o.FindDefaultDeployKindInValuesYaml(text) 142 name := "" 143 144 name, err := o.pickDeployKind(defaultName) 145 if err != nil { 146 return name, err 147 } 148 canary, err := o.pickProgressiveDelivery(currentDeployOptions.Canary) 149 if err != nil { 150 return name, err 151 } 152 hpa, err := o.pickHPA(currentDeployOptions.HPA) 153 if err != nil { 154 return name, err 155 } 156 return o.setDeployKindInValuesYaml(text, name, canary, hpa) 157 } 158 return o.ModifyHelmValuesFile(o.Dir, fn) 159 } 160 161 // FindDefaultDeployKindInValuesYaml finds the deployment values for the given values.yaml text 162 func (o *EditDeployKindOptions) FindDefaultDeployKindInValuesYaml(yamlText string) (string, v1.DeployOptions) { 163 deployOptions := v1.DeployOptions{} 164 // lets try find the current setting 165 knativeFlag := "" 166 mainSection := "" 167 lines := strings.Split(yamlText, "\n") 168 169 for _, line := range lines { 170 if strings.HasPrefix(line, "#") { 171 continue 172 } 173 if !strings.HasPrefix(line, " ") && !strings.HasPrefix(line, "\t") { 174 idx := strings.Index(line, ":") 175 if idx > 0 { 176 mainSection = line[0 : idx+1] 177 } 178 } 179 if strings.HasPrefix(line, knativeDeployKey) { 180 knativeFlag = strings.TrimSpace(line[len(knativeDeployKey):]) 181 } else if strings.HasPrefix(line, enabledKey) { 182 if mainSection == deployCanaryKey { 183 deployOptions.Canary = toBool(strings.TrimSpace(line[len(enabledKey):])) 184 } else if mainSection == deployHPAKey { 185 deployOptions.HPA = toBool(strings.TrimSpace(line[len(enabledKey):])) 186 } 187 } 188 } 189 kind := opts.DeployKindDefault 190 if knativeFlag == "true" { 191 kind = opts.DeployKindKnative 192 } 193 return kind, deployOptions 194 } 195 196 // setDeployKindInValuesYaml sets the `knativeDeployKey` key to true or false based on the deployment kind 197 func (o *EditDeployKindOptions) setDeployKindInValuesYaml(yamlText string, deployKind string, progressive bool, hpa bool) (string, error) { 198 var buffer strings.Builder 199 200 mainSection := "" 201 lines := strings.Split(yamlText, "\n") 202 for _, line := range lines { 203 if !strings.HasPrefix(line, " ") && !strings.HasPrefix(line, "\t") { 204 idx := strings.Index(line, ":") 205 if idx > 0 { 206 mainSection = line[0 : idx+1] 207 } 208 } 209 if strings.HasPrefix(line, knativeDeployKey) { 210 buffer.WriteString(knativeDeployKey) 211 buffer.WriteString(" ") 212 if deployKind == opts.DeployKindKnative { 213 buffer.WriteString("true") 214 } else { 215 buffer.WriteString("false") 216 } 217 } else if strings.HasPrefix(line, enabledKey) { 218 if mainSection == deployCanaryKey { 219 buffer.WriteString(enabledKey) 220 buffer.WriteString(" ") 221 buffer.WriteString(toString(progressive)) 222 } else if mainSection == deployHPAKey { 223 buffer.WriteString(enabledKey) 224 buffer.WriteString(" ") 225 buffer.WriteString(toString(hpa)) 226 } else { 227 buffer.WriteString(line) 228 } 229 } else { 230 buffer.WriteString(line) 231 } 232 buffer.WriteString("\n") 233 } 234 return buffer.String(), nil 235 } 236 237 func (o *EditDeployKindOptions) pickDeployKind(defaultName string) (string, error) { 238 if defaultName == "" { 239 defaultName = opts.DeployKindDefault 240 } 241 // return the CLI option if specified 242 if o.FlagChanged(opts.OptionKind) { 243 return o.Kind, nil 244 } 245 if o.BatchMode { 246 return defaultName, nil 247 } 248 if o.Kind != "" { 249 return o.Kind, nil 250 } 251 args := o.Args 252 if len(args) > 0 { 253 return args[0], nil 254 } 255 if util.StringArrayIndex(deployKinds, defaultName) < 0 { 256 defaultName = opts.DeployKindDefault 257 } 258 name, err := util.PickNameWithDefault(deployKinds, "Pick the deployment kind: ", defaultName, "lets you switch between knative serve based deployments and default kubernetes deployments", o.GetIOFileHandles()) 259 if err != nil { 260 return name, err 261 } 262 if name == "" { 263 return name, fmt.Errorf("no kind chosen") 264 } 265 return name, nil 266 } 267 268 func (o *EditDeployKindOptions) pickProgressiveDelivery(defaultValue bool) (bool, error) { 269 // return the CLI option if specified 270 if o.FlagChanged(opts.OptionCanary) { 271 return o.DeployOptions.Canary, nil 272 } 273 if o.BatchMode { 274 return defaultValue, nil 275 } 276 return util.Confirm("Would you like to use Canary Delivery", defaultValue, "Canary delivery lets us use Canary rollouts to incrementally test applications", o.GetIOFileHandles()) 277 } 278 279 func (o *EditDeployKindOptions) pickHPA(defaultValue bool) (bool, error) { 280 // return the CLI option if specified 281 if o.FlagChanged(opts.OptionHPA) { 282 return o.DeployOptions.HPA, nil 283 } 284 if o.BatchMode { 285 return defaultValue, nil 286 } 287 return util.Confirm("Would you like to use the Horizontal Pod Autoscaler with deployments", defaultValue, "The Horizontal Pod Autoscaler lets you scale your pods up and down automatically", o.GetIOFileHandles()) 288 } 289 290 func toBool(text string) bool { 291 return strings.ToLower(text) == "true" 292 } 293 294 func toString(flag bool) string { 295 if flag { 296 return "true" 297 } 298 return "false" 299 } 300 301 // ToDeployArguments converts the given deploy kind, canary and HPA to CLI arguments we can parse on the command object 302 func ToDeployArguments(optionsKind string, kind string, canary bool, hpa bool) []string { 303 return []string{"--" + optionsKind + "=" + kind, "--" + opts.OptionCanary + "=" + toString(canary), "--" + opts.OptionHPA + "=" + toString(hpa)} 304 }