From 23ad4bb2301482214beff7d9d7404c494c074b69 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Wed, 18 Nov 2020 01:23:36 -0500 Subject: [PATCH] refactor: add ability to skip deploys and fix process scaling --- plugins/ps/functions.go | 149 ++++++++++++++-------- plugins/ps/src/subcommands/subcommands.go | 3 +- plugins/ps/subcommands.go | 6 +- 3 files changed, 98 insertions(+), 60 deletions(-) diff --git a/plugins/ps/functions.go b/plugins/ps/functions.go index 4b19358eb..ef12a1b02 100644 --- a/plugins/ps/functions.go +++ b/plugins/ps/functions.go @@ -181,6 +181,11 @@ func hasScaleFile(appName string) bool { return common.FileExists(scalefilePath) } +func hasProcfile(appName string) bool { + procfilePath := getProcfilePath(appName) + return common.FileExists(procfilePath) +} + func isValidRestartPolicy(policy string) bool { if policy == "" { return false @@ -266,13 +271,39 @@ func scaleReport(appName string) error { return nil } -func scaleSet(appName string, processTuples []string) error { +func parseProcessTuples(processTuples []string) (map[string]int, error) { + scale := make(map[string]int) + + for _, processTuple := range processTuples { + s := strings.Split(processTuple, "=") + if len(s) == 1 { + return scale, fmt.Errorf("Missing count for process type %s", processTuple) + } + + processType := s[0] + count, err := strconv.Atoi(s[1]) + if err != nil { + return scale, fmt.Errorf("Invalid count for process type %s", s[0]) + } + + scale[processType] = count + } + + return scale, nil +} + +func scaleSet(appName string, skipDeploy bool, processTuples []string) error { if !canScaleApp(appName) { return fmt.Errorf("App %s contains DOKKU_SCALE file and cannot be manually scaled", appName) } common.LogInfo1(fmt.Sprintf("Scaling %s processes: %s", appName, strings.Join(processTuples, " "))) - if err := updateScalefile(appName, processTuples); err != nil { + scale, err := parseProcessTuples(processTuples) + if err != nil { + return err + } + + if err := updateScalefile(appName, scale); err != nil { return err } @@ -284,81 +315,87 @@ func scaleSet(appName string, processTuples []string) error { if err != nil { return err } + + if skipDeploy { + return nil + } + return common.PlugnTrigger("release-and-deploy", []string{appName, imageTag}...) } -func updateScalefile(appName string, processTuples []string) error { - procfilePath := getProcfilePath(appName) +func readScaleFile(appName string) (map[string]int, error) { + scale := make(map[string]int) + if !hasScaleFile(appName) { + return scale, errors.New("No DOKKU_SCALE file found") + } + scalefilePath := getScalefilePath(appName) lines, err := common.FileToSlice(scalefilePath) if err != nil { - return err + return scale, err } - processTypes := make(map[string]bool) - hasProcfile := common.FileExists(procfilePath) - if hasProcfile { - processTypes, err = processesInProcfile(procfilePath) - if err != nil { - return err - } - } - - newLines := []string{} - for processType := range processTypes { - found := false - for _, line := range lines { - if strings.HasPrefix(line, fmt.Sprintf("%s=", processType)) { - newLines = append(newLines, line) - found = true - break - } - } - - if !found { - newLines = append(newLines, fmt.Sprintf("%s=0", processType)) - } - } - - scale := []string{} - for _, processTuple := range processTuples { - s := strings.Split(processTuple, "=") - if len(s) == 1 { - return fmt.Errorf("Missing count for process type %s", processTuple) + for i, line := range lines { + s := strings.Split(line, "=") + if len(s) != 2 { + common.LogWarn(fmt.Sprintf("Invalid scale entry on line %d, skipping", i)) + continue } processType := s[0] count, err := strconv.Atoi(s[1]) if err != nil { - return fmt.Errorf("Invalid count for process type %s", s[0]) + common.LogWarn(fmt.Sprintf("Invalid count on line %d, skipping", i)) + continue } - if _, ok := processTypes[processType]; !ok && hasProcfile && count != 0 { + scale[processType] = count + } + + common.LogWarn("No valid entries found in scale file, defaulting to web=1") + if len(scale) == 0 { + scale["web"] = 1 + } + + return scale, nil +} + +func updateScalefile(appName string, scaleUpdates map[string]int) error { + if !hasScaleFile(appName) { + if err := generateScalefile(appName); err != nil { + return err + } + } + + scale, err := readScaleFile(appName) + if err != nil { + return err + } + + procfilePath := getProcfilePath(appName) + procfileExists := hasProcfile(appName) + validProcessTypes := make(map[string]bool) + if procfileExists { + validProcessTypes, err = processesInProcfile(procfilePath) + if err != nil { + return err + } + } + + for processType, count := range scaleUpdates { + if procfileExists && !validProcessTypes[processType] && count != 0 { return fmt.Errorf("%s is not a valid process name to scale up", processType) } - - scale = append(scale, fmt.Sprintf("%s=%d", processType, count)) + scale[processType] = count } - for _, line := range newLines { - s := strings.Split(line, "=") - processType := s[0] - - found := false - for _, s := range scale { - if strings.HasPrefix(s, fmt.Sprintf("%s=", processType)) { - found = true - break - } - } - - if !found { - scale = append(scale, line) - } - + content := []string{} + for processType, count := range scale { + content = append(content, fmt.Sprintf("%s=%d", processType, count)) } - if err := common.WriteSliceToFile(scalefilePath, scale); err != nil { + scalefilePath := getScalefilePath(appName) + if err := common.WriteSliceToFile(scalefilePath, content); err != nil { return err } diff --git a/plugins/ps/src/subcommands/subcommands.go b/plugins/ps/src/subcommands/subcommands.go index cecfc6e75..21be3e9ab 100644 --- a/plugins/ps/src/subcommands/subcommands.go +++ b/plugins/ps/src/subcommands/subcommands.go @@ -55,10 +55,11 @@ func main() { err = ps.CommandRetire() case "scale": args := flag.NewFlagSet("ps:scale", flag.ExitOnError) + skipDeploy := args.Bool("skip-deploy", false, "--skip-deploy: skip deploy of the app") args.Parse(os.Args[2:]) appName := args.Arg(0) _, processTuples := common.ShiftString(args.Args()) - err = ps.CommandScale(appName, processTuples) + err = ps.CommandScale(appName, *skipDeploy, processTuples) case "set": args := flag.NewFlagSet("ps:set", flag.ExitOnError) args.Parse(os.Args[2:]) diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index 131a3b5a7..3be60b88d 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -88,7 +88,7 @@ func CommandRetire() error { return nil } -func CommandScale(appName string, processTuples []string) error { +func CommandScale(appName string, skipDeploy bool, processTuples []string) error { if appName == "" { return errors.New("Please specify an app to run the command on") } @@ -114,7 +114,7 @@ func CommandScale(appName string, processTuples []string) error { return err } } else if common.FileExists(procfilePath) { - if err := updateScalefile(appName, []string{}); err != nil { + if err := updateScalefile(appName, make(map[string]int)); err != nil { return err } } @@ -123,7 +123,7 @@ func CommandScale(appName string, processTuples []string) error { return scaleReport(appName) } - return scaleSet(appName, processTuples) + return scaleSet(appName, skipDeploy, processTuples) } func CommandSet(appName string, property string, value string) error {