forked from toolshed/abra
		
	chore: formatting pass on kadabra [ci skip]
This commit is contained in:
		@ -189,6 +189,7 @@ func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return app
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ var allFlag = &cli.BoolFlag{
 | 
			
		||||
	Destination: &updateAll,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Check for available upgrades
 | 
			
		||||
// Notify checks for available upgrades
 | 
			
		||||
var Notify = cli.Command{
 | 
			
		||||
	Name:    "notify",
 | 
			
		||||
	Aliases: []string{"n"},
 | 
			
		||||
@ -49,24 +49,31 @@ var Notify = cli.Command{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		majorFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:      internal.SubCommandBefore,
 | 
			
		||||
	Description: `It reads the deployed app versions and looks for new versions in the recipe catalogue. If a new patch/minor version is available, a notification is printed. To include major versions use the --major flag.`,
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
It reads the deployed app versions and looks for new versions in the recipe
 | 
			
		||||
catalogue. If a new patch/minor version is available, a notification is
 | 
			
		||||
printed. To include major versions use the --major flag.
 | 
			
		||||
`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
 | 
			
		||||
		cl, err := client.New("default")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		stacks, err := stack.GetStacks(cl)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, stackInfo := range stacks {
 | 
			
		||||
			stackName := stackInfo.Name
 | 
			
		||||
			recipeName, err := getLabel(cl, stackName, "recipe")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if recipeName != "" {
 | 
			
		||||
				_, err = getLatestUpgrade(cl, stackName, recipeName)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
@ -74,24 +81,33 @@ var Notify = cli.Command{
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Upgrade apps
 | 
			
		||||
// UpgradeApp upgrades apps.
 | 
			
		||||
var UpgradeApp = cli.Command{
 | 
			
		||||
	Name:      "upgrade",
 | 
			
		||||
	Aliases:   []string{"u"},
 | 
			
		||||
	Usage:     "Upgrade apps",
 | 
			
		||||
	ArgsUsage: "<stack_name> <recipe>",
 | 
			
		||||
	ArgsUsage: "<stack-name> <recipe>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
		majorFlag,
 | 
			
		||||
		allFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:      internal.SubCommandBefore,
 | 
			
		||||
	Description: `Upgrade an app by specifying its stack name and recipe. By passing --all instead every deployed app is upgraded. For each apps with enabled auto updates the deployed version is compared with the current recipe catalogue version. If a new patch/minor version is available the app is upgraded. To include major versions use the --major flag. Don't do that, it will probably break things. Only apps that are not deployed with --chaos are upgraded, to update chaos deployments use the --chaos flag. Use it with care.`,
 | 
			
		||||
	Before: internal.SubCommandBefore,
 | 
			
		||||
	Description: `
 | 
			
		||||
Upgrade an app by specifying its stack name and recipe. By passing "--all"
 | 
			
		||||
instead, every deployed app is upgraded. For each apps with enabled auto
 | 
			
		||||
updates the deployed version is compared with the current recipe catalogue
 | 
			
		||||
version. If a new patch/minor version is available, the app is upgraded. To
 | 
			
		||||
include major versions use the "--major" flag. Don't do that, it will probably
 | 
			
		||||
break things. Only apps that are not deployed with "--chaos" are upgraded, to
 | 
			
		||||
update chaos deployments use the "--chaos" flag. Use it with care.
 | 
			
		||||
`,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		cl, err := client.New("default")
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@ -105,6 +121,7 @@ var UpgradeApp = cli.Command{
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -112,22 +129,25 @@ var UpgradeApp = cli.Command{
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, stackInfo := range stacks {
 | 
			
		||||
			stackName := stackInfo.Name
 | 
			
		||||
			recipeName, err := getLabel(cl, stackName, "recipe")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = tryUpgrade(cl, stackName, recipeName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getLabel reads docker label in the format coop-cloud.${STACK_NAME}.${LABEL}
 | 
			
		||||
// getLabel reads docker labels in the format of "coop-cloud.${STACK_NAME}.${LABEL}".
 | 
			
		||||
func getLabel(cl *dockerclient.Client, stackName string, label string) (string, error) {
 | 
			
		||||
	filter := filters.NewArgs()
 | 
			
		||||
	filter.Add("label", fmt.Sprintf("%s=%s", convert.LabelNamespace, stackName))
 | 
			
		||||
@ -136,34 +156,41 @@ func getLabel(cl *dockerclient.Client, stackName string, label string) (string,
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, service := range services {
 | 
			
		||||
		labelKey := fmt.Sprintf("coop-cloud.%s.%s", stackName, label)
 | 
			
		||||
		if labelValue, ok := service.Spec.Labels[labelKey]; ok {
 | 
			
		||||
			return labelValue, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("no %s label found for %s", label, stackName)
 | 
			
		||||
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getBoolLabel reads a boolean docker label
 | 
			
		||||
// getBoolLabel reads a boolean docker label.
 | 
			
		||||
func getBoolLabel(cl *dockerclient.Client, stackName string, label string) (bool, error) {
 | 
			
		||||
	lableValue, err := getLabel(cl, stackName, label)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if lableValue != "" {
 | 
			
		||||
		value, err := strconv.ParseBool(lableValue)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return value, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("Boolean label %s could not be found for %s, set default to false.", label, stackName)
 | 
			
		||||
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getEnv reads Env variables from docker services
 | 
			
		||||
// getEnv reads env variables from docker services.
 | 
			
		||||
func getEnv(cl *dockerclient.Client, stackName string) (config.AppEnv, error) {
 | 
			
		||||
	envMap := make(map[string]string)
 | 
			
		||||
	filter := filters.NewArgs()
 | 
			
		||||
@ -173,6 +200,7 @@ func getEnv(cl *dockerclient.Client, stackName string) (config.AppEnv, error) {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, service := range services {
 | 
			
		||||
		envList := service.Spec.TaskTemplate.ContainerSpec.Env
 | 
			
		||||
		for _, envString := range envList {
 | 
			
		||||
@ -187,53 +215,60 @@ func getEnv(cl *dockerclient.Client, stackName string) (config.AppEnv, error) {
 | 
			
		||||
			envMap[k] = v
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return envMap, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getLatestUpgrade returns the latest available version for an app regarding to the --major flag
 | 
			
		||||
// if it is newer than the currently deployed version
 | 
			
		||||
// getLatestUpgrade returns the latest available version for an app respecting
 | 
			
		||||
// the "--major" flag if it is newer than the currently deployed version.
 | 
			
		||||
func getLatestUpgrade(cl *dockerclient.Client, stackName string, recipeName string) (string, error) {
 | 
			
		||||
	deployedVersion, err := getDeployedVersion(cl, stackName, recipeName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	availableUpgrades, err := getAvailableUpgrades(cl, stackName, recipeName, deployedVersion)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(availableUpgrades) == 0 {
 | 
			
		||||
		logrus.Debugf("no available upgrades for %s", stackName)
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	// Uncomment to select the next version instead of the last version
 | 
			
		||||
	// availableUpgrades = internal.ReverseStringList(availableUpgrades)
 | 
			
		||||
 | 
			
		||||
	var chosenUpgrade string
 | 
			
		||||
	if len(availableUpgrades) > 0 {
 | 
			
		||||
		chosenUpgrade = availableUpgrades[len(availableUpgrades)-1]
 | 
			
		||||
		logrus.Infof("%s (%s) can be upgraded from version %s to %s", stackName, recipeName, deployedVersion, chosenUpgrade)
 | 
			
		||||
	}
 | 
			
		||||
	return chosenUpgrade, nil
 | 
			
		||||
 | 
			
		||||
	return chosenUpgrade, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getDeployedVersion returns the currently deployed version of an app
 | 
			
		||||
// getDeployedVersion returns the currently deployed version of an app.
 | 
			
		||||
func getDeployedVersion(cl *dockerclient.Client, stackName string, recipeName string) (string, error) {
 | 
			
		||||
	logrus.Debugf("Retrieve deployed version whether %s is already deployed", stackName)
 | 
			
		||||
 | 
			
		||||
	isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, stackName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !isDeployed {
 | 
			
		||||
		return "", fmt.Errorf("%s is not deployed?", stackName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if deployedVersion == "unknown" {
 | 
			
		||||
		return "", fmt.Errorf("failed to determine deployed version of %s", stackName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return deployedVersion, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getAvailableUpgrades returns all available versions of an app that are newer than
 | 
			
		||||
// the deployed version. It only includes major steps if the --major flag is set.
 | 
			
		||||
// getAvailableUpgrades returns all available versions of an app that are newer
 | 
			
		||||
// than the deployed version. It only includes major upgrades if the "--major"
 | 
			
		||||
// flag is set.
 | 
			
		||||
func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName string,
 | 
			
		||||
	deployedVersion string) ([]string, error) {
 | 
			
		||||
	catl, err := recipe.ReadRecipeCatalogue()
 | 
			
		||||
@ -251,64 +286,73 @@ func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var availableUpgrades []string
 | 
			
		||||
 | 
			
		||||
	for _, version := range versions {
 | 
			
		||||
		parsedDeployedVersion, err := tagcmp.Parse(deployedVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		parsedVersion, err := tagcmp.Parse(version)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		versionDelta, err := parsedDeployedVersion.UpgradeDelta(parsedVersion)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if 0 < versionDelta.UpgradeType() && (versionDelta.UpgradeType() < 4 || majorUpdate) {
 | 
			
		||||
			availableUpgrades = append(availableUpgrades, version)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("Available updates for %s: %s", stackName, availableUpgrades)
 | 
			
		||||
 | 
			
		||||
	return availableUpgrades, nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// processRecipeRepoVersion clones, pulls, checks out the version and lints the recipe repository
 | 
			
		||||
// processRecipeRepoVersion clones, pulls, checks out the version and lints the
 | 
			
		||||
// recipe repository.
 | 
			
		||||
func processRecipeRepoVersion(recipeName string, version string) error {
 | 
			
		||||
	if err := recipe.EnsureExists(recipeName); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := recipe.EnsureUpToDate(recipeName); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := recipe.EnsureVersion(recipeName, version); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if r, err := recipe.Get(recipeName); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if err := lint.LintForErrors(r); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// mergeAbraShEnv merges abra.sh env's into the app env's
 | 
			
		||||
// mergeAbraShEnv merges abra.sh env vars into the app env vars.
 | 
			
		||||
func mergeAbraShEnv(recipeName string, env config.AppEnv) error {
 | 
			
		||||
	abraShPath := fmt.Sprintf("%s/%s/%s", config.RECIPES_DIR, recipeName, "abra.sh")
 | 
			
		||||
	abraShEnv, err := config.ReadAbraShEnvVars(abraShPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k, v := range abraShEnv {
 | 
			
		||||
		logrus.Debugf("read v:%s k: %s", v, k)
 | 
			
		||||
		env[k] = v
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// createDeployConfig merges and enriches the compose config for the deployment
 | 
			
		||||
// createDeployConfig merges and enriches the compose config for the deployment.
 | 
			
		||||
func createDeployConfig(recipeName string, stackName string, env config.AppEnv) (*composetypes.Config, stack.Deploy, error) {
 | 
			
		||||
	env["STACK_NAME"] = stackName
 | 
			
		||||
 | 
			
		||||
@ -317,64 +361,77 @@ func createDeployConfig(recipeName string, stackName string, env config.AppEnv)
 | 
			
		||||
		Prune:        false,
 | 
			
		||||
		ResolveImage: stack.ResolveImageAlways,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	composeFiles, err := config.GetAppComposeFiles(recipeName, env)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, deployOpts, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deployOpts.Composefiles = composeFiles
 | 
			
		||||
	compose, err := config.GetAppComposeConfig(stackName, deployOpts, env)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, deployOpts, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config.ExposeAllEnv(stackName, compose, env)
 | 
			
		||||
 | 
			
		||||
	// after the upgrade the deployment won't be in chaos state anymore
 | 
			
		||||
	config.SetChaosLabel(compose, stackName, false)
 | 
			
		||||
	config.SetRecipeLabel(compose, stackName, recipeName)
 | 
			
		||||
	config.SetUpdateLabel(compose, stackName, env)
 | 
			
		||||
 | 
			
		||||
	return compose, deployOpts, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tryUpgrade performs the upgrade if all the requirements are fulfilled
 | 
			
		||||
// tryUpgrade performs the upgrade if all the requirements are fulfilled.
 | 
			
		||||
func tryUpgrade(cl *dockerclient.Client, stackName string, recipeName string) error {
 | 
			
		||||
	if recipeName == "" {
 | 
			
		||||
		logrus.Debugf("Don't update %s due to missing recipe name", stackName)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chaos, err := getBoolLabel(cl, stackName, "chaos")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if chaos && !internal.Chaos {
 | 
			
		||||
		logrus.Debugf("Don't update %s due to chaos deployment.", stackName)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	updatesEnabled, err := getBoolLabel(cl, stackName, "autoupdate")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !updatesEnabled {
 | 
			
		||||
		logrus.Debugf("Don't update %s due to disabling auto updates or missing ENABLE_AUTOUPDATE env.", stackName)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	upgradeVersion, err := getLatestUpgrade(cl, stackName, recipeName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if upgradeVersion == "" {
 | 
			
		||||
		logrus.Debugf("Don't update %s due to no new version.", stackName)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	err = upgrade(cl, stackName, recipeName, upgradeVersion)
 | 
			
		||||
	return err
 | 
			
		||||
 | 
			
		||||
	err = upgrade(cl, stackName, recipeName, upgradeVersion)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// upgrade performs all necessary steps to upgrade an app
 | 
			
		||||
// upgrade performs all necessary steps to upgrade an app.
 | 
			
		||||
func upgrade(cl *dockerclient.Client, stackName string, recipeName string, upgradeVersion string) error {
 | 
			
		||||
	env, err := getEnv(cl, stackName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app := config.App{
 | 
			
		||||
		Name:   stackName,
 | 
			
		||||
		Recipe: recipeName,
 | 
			
		||||
@ -396,14 +453,16 @@ func upgrade(cl *dockerclient.Client, stackName string, recipeName string, upgra
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Infof("Upgrade %s (%s) to version %s", stackName, recipeName, upgradeVersion)
 | 
			
		||||
 | 
			
		||||
	err = stack.RunDeploy(cl, deployOpts, compose, stackName, true)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
	app := &cli.App{
 | 
			
		||||
		Name: "kadabra",
 | 
			
		||||
		Usage: `The Co-op Cloud autoupdater
 | 
			
		||||
		Usage: `The Co-op Cloud auto-updater
 | 
			
		||||
    ____                           ____ _                 _
 | 
			
		||||
   / ___|___         ___  _ __    / ___| | ___  _   _  __| |
 | 
			
		||||
  | |   / _ \ _____ / _ \| '_ \  | |   | |/ _ \| | | |/ _' |
 | 
			
		||||
@ -419,9 +478,10 @@ func newAbraApp(version, commit string) *cli.App {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app.Before = func(c *cli.Context) error {
 | 
			
		||||
		logrus.Debugf("abra version %s, commit %s", version, commit)
 | 
			
		||||
		logrus.Debugf("kadabra version %s, commit %s", version, commit)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return app
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user