From 3c6396fbca6efcdb843a6f7dbd325e98eabebe22 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sat, 9 Oct 2021 17:44:35 -0400 Subject: [PATCH] feat: implement the scheduler plugin This also performs a one-time migration of the DOKKU_SCHEDULER values the scheduler plugin properties. Closes #4739 --- docs/appendices/0.26.0-migration-guide.md | 6 + docs/deployment/schedulers/null.md | 4 +- .../schedulers/scheduler-management.md | 116 ++++++++++++++++++ docs/development/plugin-triggers.md | 19 +++ docs/getting-started/upgrading.md | 2 + docs/networking/network.md | 2 +- docs/template.html | 6 +- plugins/common/common.go | 4 +- plugins/common/functions | 19 +-- plugins/common/src/common/common.go | 6 + plugins/scheduler/.gitignore | 9 ++ plugins/scheduler/Makefile | 6 + plugins/scheduler/go.mod | 14 +++ plugins/scheduler/go.sum | 12 ++ plugins/scheduler/plugin.toml | 4 + plugins/scheduler/report.go | 45 +++++++ plugins/scheduler/scheduler.go | 13 ++ plugins/scheduler/src/commands/commands.go | 56 +++++++++ .../scheduler/src/subcommands/subcommands.go | 50 ++++++++ plugins/scheduler/src/triggers/triggers.go | 39 ++++++ plugins/scheduler/subcommands.go | 29 +++++ plugins/scheduler/triggers.go | 71 +++++++++++ tests/unit/proxied-app.bats | 2 +- 23 files changed, 510 insertions(+), 24 deletions(-) create mode 100644 docs/appendices/0.26.0-migration-guide.md create mode 100644 docs/deployment/schedulers/scheduler-management.md create mode 100644 plugins/scheduler/.gitignore create mode 100644 plugins/scheduler/Makefile create mode 100644 plugins/scheduler/go.mod create mode 100644 plugins/scheduler/go.sum create mode 100644 plugins/scheduler/plugin.toml create mode 100644 plugins/scheduler/report.go create mode 100644 plugins/scheduler/scheduler.go create mode 100644 plugins/scheduler/src/commands/commands.go create mode 100644 plugins/scheduler/src/subcommands/subcommands.go create mode 100644 plugins/scheduler/src/triggers/triggers.go create mode 100644 plugins/scheduler/subcommands.go create mode 100644 plugins/scheduler/triggers.go diff --git a/docs/appendices/0.26.0-migration-guide.md b/docs/appendices/0.26.0-migration-guide.md new file mode 100644 index 000000000..9edfe60a6 --- /dev/null +++ b/docs/appendices/0.26.0-migration-guide.md @@ -0,0 +1,6 @@ +# 0.25.0 Migration Guide + + +## Changes + +- The `scheduler` plugin now controls the scheduler in use for deploys. Apps will have their `DOKKU_SCHEDULER` environment variables migrated to the scheduler plugin, after which that value will be removed from said app. Please see the [scheduler documentation](/docs/deployment/schedulers/scheduler-management.md) for more information. diff --git a/docs/deployment/schedulers/null.md b/docs/deployment/schedulers/null.md index ad375508b..b17ba5c91 100644 --- a/docs/deployment/schedulers/null.md +++ b/docs/deployment/schedulers/null.md @@ -8,8 +8,8 @@ The `null` scheduler does nothing, and is useful for routing to services not man ### Detection -This scheduler is _never_ auto-detected. The scheduler _must_ be specified via the `config:set` command: +This scheduler is _never_ auto-detected. The scheduler _must_ be specified via the `scheduler:set` command: ```shell -dokku config:set node-js-app DOCKER_SCHEDULER=null +dokku scheduler:set node-js-app selected null ``` diff --git a/docs/deployment/schedulers/scheduler-management.md b/docs/deployment/schedulers/scheduler-management.md new file mode 100644 index 000000000..776eb97f5 --- /dev/null +++ b/docs/deployment/schedulers/scheduler-management.md @@ -0,0 +1,116 @@ +# Scheduler Management + +> New as of 0.26.0 + +``` +scheduler:report [] [] # Displays a scheduler report for one or more apps +scheduler:set () # Set or clear a scheduler property for an app +``` + +Schedulers are a way of customizing how an app image is deployed, and can be used to interact with non-local systems such as Kubernetes and Nomad. + +## Usage + +### Scheduler selection + +Dokku supports the following built-in schedulers: + +- `scheduler-docker-local`: Schedules apps against the local docker socket and runs containers directly on the Dokku host. See the [docker-local scheduler documentation](/docs/deployment/schedulers/docker-local.md) for more information on how this scheduler functions. +- `scheduler-null`: Does nothing during the scheduler phase. See the [null scheduler documentation](/docs/deployment/schedulers/null.md) for more information on how this scheduler functions. + +See the [alternate schedulers documentation](/docs/deployment/schedulers/alternate-schedulers.md) for more information on other scheduler plugins. + +### Overriding the auto-selected scheduler + +If desired, the scheduler can be specified via the `scheduler:set` command by speifying a value for `selected`. The selected scheduler will always be used. + +```shell +dokku scheduler:set node-js-app selected docker-local +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku scheduler:set node-js-app selected +``` + +The `selected` property can also be set globally. The global default is an empty string, and auto-detection will be performed when no value is set per-app or globally. + +```shell +dokku scheduler:set --global selected docker-local +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku scheduler:set --global selected +``` + +### Displaying scheduler reports for an app + +You can get a report about the app's scheduler status using the `scheduler:report` command: + +```shell +dokku scheduler:report +``` + +``` +=====> node-js-app scheduler information + Scheduler computed selected: herokuish + Scheduler global selected: herokuish + Scheduler selected: herokuish +=====> python-sample scheduler information + Scheduler computed selected: dockerfile + Scheduler global selected: herokuish + Scheduler selected: dockerfile +=====> ruby-sample scheduler information + Scheduler computed selected: herokuish + Scheduler global selected: herokuish + Scheduler selected: +``` + +You can run the command for a specific app also. + +```shell +dokku scheduler:report node-js-app +``` + +``` +=====> node-js-app scheduler information + Scheduler selected: herokuish +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku scheduler:report node-js-app --scheduler-selected +``` + +### Custom schedulers + +To create a custom scheduler, the following triggers may be implemented: + +- `check-deploy` +- `core-post-deploy` +- `post-app-clone-setup` +- `post-app-rename-setup` +- `post-create` +- `post-delete` +- `pre-deploy` +- `pre-restore` +- `scheduler-app-status` +- `scheduler-deploy` +- `scheduler-docker-cleanup` +- `scheduler-inspect` +- `scheduler-is-deployed` +- `scheduler-logs` +- `scheduler-logs-failed` +- `scheduler-retire` +- `scheduler-run` +- `scheduler-stop` +- `scheduler-tags-create` +- `scheduler-tags-destroy` + +Custom plugins names _must_ have the prefix `scheduler-` or scheduler overriding via `scheduler:set` may not function as expected. + +Schedulers can use any tools available on the system to build the docker image, and may even be used to interact with off-server systems. The only current requirement is that the scheduler must have access to the image built in the build phase. If this is not the case, the registry plugin can be used to push the image to a registry that the scheduler software can access. diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 719741905..baee56069 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -2058,6 +2058,25 @@ DOKKU_SCHEDULER="$1"; APP="$2"; IMAGE_TAG="$3"; # TODO ``` +### `scheduler-detect` + +> Warning: The scheduler plugin trigger apis are under development and may change +> between minor releases until the 1.0 release. + +- Description: Allows you to check which scheduler is in use for an app +- Invoked by: `dokku deploy` +- Arguments: `$APP` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +APP="$1" + +# TODO +``` + ### `scheduler-enter` > Warning: The scheduler plugin trigger apis are under development and may change diff --git a/docs/getting-started/upgrading.md b/docs/getting-started/upgrading.md index ec51a23da..d7fe03270 100644 --- a/docs/getting-started/upgrading.md +++ b/docs/getting-started/upgrading.md @@ -19,6 +19,8 @@ Docker releases updates periodically to their engine. We recommend reading their Before upgrading, check the migration guides to get comfortable with new features and prepare your deployment to be upgraded. +- [Upgrading to 0.26](/docs/appendices/0.26.0-migration-guide.md) +- [Upgrading to 0.25](/docs/appendices/0.25.0-migration-guide.md) - [Upgrading to 0.24](/docs/appendices/0.24.0-migration-guide.md) - [Upgrading to 0.23](/docs/appendices/0.23.0-migration-guide.md) - [Upgrading to 0.22](/docs/appendices/0.22.0-migration-guide.md) diff --git a/docs/networking/network.md b/docs/networking/network.md index 7cd897caf..ae9406da2 100644 --- a/docs/networking/network.md +++ b/docs/networking/network.md @@ -141,7 +141,7 @@ dokku apps:create local-app dokku builder:set local-app selected null # set the scheduler to the null scheduler, which does nothing -dokku config:set local-app DOKKU_SCHEDULER=null +dokku scheduler:set local-app selected null # set the static-web-listener network property to the ip:port combination for your app. dokku network:set local-app static-web-listener 127.0.0.1:8080 diff --git a/docs/template.html b/docs/template.html index 5833e81d7..ff2a68b54 100644 --- a/docs/template.html +++ b/docs/template.html @@ -160,8 +160,10 @@ Schedulers - Docker Local - Alternate Schedulers + Scheduler Management + Docker Local + Null Scheduler + Alternate Schedulers Development diff --git a/plugins/common/common.go b/plugins/common/common.go index bc1d25053..1d8ad86aa 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -101,7 +101,7 @@ func GetAppScheduler(appName string) string { } func getAppScheduler(appName string) string { - b, _ := PlugnTriggerOutput("config-get", []string{appName, "DOKKU_SCHEDULER"}...) + b, _ := PlugnTriggerOutput("scheduler-detect", []string{appName}...) value := strings.TrimSpace(string(b[:])) if value != "" { return value @@ -111,7 +111,7 @@ func getAppScheduler(appName string) string { // GetGlobalScheduler fetchs the global scheduler func GetGlobalScheduler() string { - b, _ := PlugnTriggerOutput("config-get-global", []string{"DOKKU_SCHEDULER"}...) + b, _ := PlugnTriggerOutput("scheduler-detect", []string{"--global"}...) value := strings.TrimSpace(string(b[:])) if value != "" { return value diff --git a/plugins/common/functions b/plugins/common/functions index a4e354fb3..e22d160ca 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -324,22 +324,8 @@ get_app_image_name() { get_app_scheduler() { declare desc="fetch the scheduler for a given application" declare APP="$1" - local DOKKU_APP_SCHEDULER DOKKU_GLOBAL_SCHEDULER DOKKU_SCHEDULER - if [[ "$APP" == "--global" ]]; then - APP="" - fi - - source "$PLUGIN_AVAILABLE_PATH/config/functions" - [[ -n "$APP" ]] && DOKKU_APP_SCHEDULER="$(config_get "$APP" DOKKU_SCHEDULER || true)" - DOKKU_GLOBAL_SCHEDULER="$(config_get --global DOKKU_SCHEDULER || true)" - - DOKKU_SCHEDULER=${DOKKU_APP_SCHEDULER:="$DOKKU_GLOBAL_SCHEDULER"} - if [[ -z "$DOKKU_SCHEDULER" ]]; then - DOKKU_SCHEDULER="docker-local" - fi - - echo "$DOKKU_SCHEDULER" + "$PLUGIN_CORE_AVAILABLE_PATH/common/common" --quiet scheduler-detect "$APP" } get_running_image_tag() { @@ -690,7 +676,8 @@ release_and_deploy() { dokku_release "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" if [[ "$DOKKU_SKIP_DEPLOY" != "true" ]]; then - dokku_log_info1 "Deploying $APP..." + local DOKKU_SCHEDULER=$(get_app_scheduler "$APP") + dokku_log_info1 "Deploying $APP via the $DOKKU_SCHEDULER scheduler..." cmd-deploy "$APP" "$IMAGE_TAG" dokku_log_info2 "Application deployed:" get_app_urls urls "$APP" | sed "s/^/ /" diff --git a/plugins/common/src/common/common.go b/plugins/common/src/common/common.go index 29eb5f207..432aa00e8 100644 --- a/plugins/common/src/common/common.go +++ b/plugins/common/src/common/common.go @@ -32,6 +32,12 @@ func main() { if !common.IsDeployed(appName) { err = fmt.Errorf("App %v not deployed", appName) } + case "scheduler-detect": + appName := flag.Arg(1) + if *global { + appName = "--global" + } + fmt.Print(common.GetAppScheduler(appName)) default: err = fmt.Errorf("Invalid common command call: %v", cmd) } diff --git a/plugins/scheduler/.gitignore b/plugins/scheduler/.gitignore new file mode 100644 index 000000000..dee5411f7 --- /dev/null +++ b/plugins/scheduler/.gitignore @@ -0,0 +1,9 @@ +/commands +/subcommands/* +/triggers/* +/triggers +/network-* +/install +/post-* +/report +/scheduler-detect diff --git a/plugins/scheduler/Makefile b/plugins/scheduler/Makefile new file mode 100644 index 000000000..92c038939 --- /dev/null +++ b/plugins/scheduler/Makefile @@ -0,0 +1,6 @@ +SUBCOMMANDS = subcommands/report subcommands/set +TRIGGERS = triggers/scheduler-detect triggers/install triggers/post-delete triggers/report +BUILD = commands subcommands triggers +PLUGIN_NAME = scheduler + +include ../../common.mk diff --git a/plugins/scheduler/go.mod b/plugins/scheduler/go.mod new file mode 100644 index 000000000..82e5869da --- /dev/null +++ b/plugins/scheduler/go.mod @@ -0,0 +1,14 @@ +module github.com/dokku/dokku/plugins/scheduler + +go 1.15 + +require ( + github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 + github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 + github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 + github.com/dokku/dokku/plugins/config v0.0.0-00010101000000-000000000000 + github.com/spf13/pflag v1.0.5 // indirect +) + +replace github.com/dokku/dokku/plugins/common => ../common +replace github.com/dokku/dokku/plugins/config => ../config diff --git a/plugins/scheduler/go.sum b/plugins/scheduler/go.sum new file mode 100644 index 000000000..fb5ba1a79 --- /dev/null +++ b/plugins/scheduler/go.sum @@ -0,0 +1,12 @@ +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA= +github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= +github.com/joho/godotenv v1.2.0 h1:vGTvz69FzUFp+X4/bAkb0j5BoLC+9bpqTWY8mjhA9pc= +github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3 h1:utdYOikI1XjNtTFGCwSM6OmFJblU4ld4gACoJsbadJg= +github.com/ryanuber/columnize v1.1.2-0.20190319233515-9e6335e58db3/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/plugins/scheduler/plugin.toml b/plugins/scheduler/plugin.toml new file mode 100644 index 000000000..23820684a --- /dev/null +++ b/plugins/scheduler/plugin.toml @@ -0,0 +1,4 @@ +[plugin] +description = "dokku core scheduler plugin" +version = "0.25.6" +[plugin.config] diff --git a/plugins/scheduler/report.go b/plugins/scheduler/report.go new file mode 100644 index 000000000..6b9548f29 --- /dev/null +++ b/plugins/scheduler/report.go @@ -0,0 +1,45 @@ +package scheduler + +import ( + "github.com/dokku/dokku/plugins/common" +) + +// ReportSingleApp is an internal function that displays the scheduler report for one or more apps +func ReportSingleApp(appName string, format string, infoFlag string) error { + if err := common.VerifyAppName(appName); err != nil { + return err + } + + flags := map[string]common.ReportFunc{ + "--scheduler-computed-selected": reportComputedSelected, + "--scheduler-global-selected": reportGlobalSelected, + "--scheduler-selected": reportSelected, + } + + flagKeys := []string{} + for flagKey := range flags { + flagKeys = append(flagKeys, flagKey) + } + + trimPrefix := false + uppercaseFirstCharacter := true + infoFlags := common.CollectReport(appName, infoFlag, flags) + return common.ReportSingleApp("scheduler", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter) +} + +func reportComputedSelected(appName string) string { + value := reportSelected(appName) + if value == "" { + value = reportGlobalSelected(appName) + } + + return value +} + +func reportGlobalSelected(appName string) string { + return common.PropertyGetDefault("scheduler", "--global", "selected", "docker-local") +} + +func reportSelected(appName string) string { + return common.PropertyGet("scheduler", appName, "selected") +} diff --git a/plugins/scheduler/scheduler.go b/plugins/scheduler/scheduler.go new file mode 100644 index 000000000..951836ac1 --- /dev/null +++ b/plugins/scheduler/scheduler.go @@ -0,0 +1,13 @@ +package scheduler + +var ( + // DefaultProperties is a map of all valid network properties with corresponding default property values + DefaultProperties = map[string]string{ + "selected": "docker-local", + } + + // GlobalProperties is a map of all valid global network properties + GlobalProperties = map[string]bool{ + "selected": true, + } +) diff --git a/plugins/scheduler/src/commands/commands.go b/plugins/scheduler/src/commands/commands.go new file mode 100644 index 000000000..417eb77e7 --- /dev/null +++ b/plugins/scheduler/src/commands/commands.go @@ -0,0 +1,56 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strconv" + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +const ( + helpHeader = `Usage: dokku scheduler[:COMMAND] + +Manage scheduler settings for an app + +Additional commands:` + + helpContent = ` + scheduler:report [] [], Displays a scheduler report for one or more apps + scheduler:set (), Set or clear a scheduler property for an app +` +) + +func main() { + flag.Usage = usage + flag.Parse() + + cmd := flag.Arg(0) + switch cmd { + case "scheduler", "scheduler:help": + usage() + case "help": + command := common.NewShellCmd(fmt.Sprintf("ps -o command= %d", os.Getppid())) + command.ShowOutput = false + output, err := command.Output() + + if err == nil && strings.Contains(string(output), "--all") { + fmt.Println(helpContent) + } else { + fmt.Print("\n scheduler, Manage scheduler settings for an app\n") + } + default: + dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT")) + if err != nil { + fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable") + dokkuNotImplementExitCode = 10 + } + os.Exit(dokkuNotImplementExitCode) + } +} + +func usage() { + common.CommandUsage(helpHeader, helpContent) +} diff --git a/plugins/scheduler/src/subcommands/subcommands.go b/plugins/scheduler/src/subcommands/subcommands.go new file mode 100644 index 000000000..148c3d753 --- /dev/null +++ b/plugins/scheduler/src/subcommands/subcommands.go @@ -0,0 +1,50 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/scheduler" + + flag "github.com/spf13/pflag" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + var err error + switch subcommand { + case "report": + args := flag.NewFlagSet("scheduler:report", flag.ExitOnError) + format := args.String("format", "stdout", "format: [ stdout | json ]") + osArgs, infoFlag, flagErr := common.ParseReportArgs("scheduler", os.Args[2:]) + if flagErr == nil { + args.Parse(osArgs) + appName := args.Arg(0) + err = scheduler.CommandReport(appName, *format, infoFlag) + } + case "set": + args := flag.NewFlagSet("scheduler:set", flag.ExitOnError) + global := args.Bool("global", false, "--global: set a global property") + args.Parse(os.Args[2:]) + appName := args.Arg(0) + property := args.Arg(1) + value := args.Arg(2) + if *global { + appName = "--global" + property = args.Arg(0) + value = args.Arg(1) + } + err = scheduler.CommandSet(appName, property, value) + default: + err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/scheduler/src/triggers/triggers.go b/plugins/scheduler/src/triggers/triggers.go new file mode 100644 index 000000000..76d70f5de --- /dev/null +++ b/plugins/scheduler/src/triggers/triggers.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/scheduler" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + var err error + switch trigger { + case "scheduler-detect": + appName := flag.Arg(0) + err = scheduler.TriggerSchedulerDetect(appName) + case "install": + err = scheduler.TriggerInstall() + case "post-delete": + appName := flag.Arg(0) + err = scheduler.TriggerPostDelete(appName) + case "report": + appName := flag.Arg(0) + err = scheduler.ReportSingleApp(appName, "", "") + default: + err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/scheduler/subcommands.go b/plugins/scheduler/subcommands.go new file mode 100644 index 000000000..98ed46e44 --- /dev/null +++ b/plugins/scheduler/subcommands.go @@ -0,0 +1,29 @@ +package scheduler + +import ( + "github.com/dokku/dokku/plugins/common" +) + +// CommandReport displays a scheduler report for one or more apps +func CommandReport(appName string, format string, infoFlag string) error { + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return err + } + for _, appName := range apps { + if err := ReportSingleApp(appName, format, infoFlag); err != nil { + return err + } + } + return nil + } + + return ReportSingleApp(appName, format, infoFlag) +} + +// CommandSet set or clear a scheduler property for an app +func CommandSet(appName string, property string, value string) error { + common.CommandPropertySet("scheduler", appName, property, value, DefaultProperties, GlobalProperties) + return nil +} diff --git a/plugins/scheduler/triggers.go b/plugins/scheduler/triggers.go new file mode 100644 index 000000000..554a28524 --- /dev/null +++ b/plugins/scheduler/triggers.go @@ -0,0 +1,71 @@ +package scheduler + +import ( + "fmt" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/config" +) + +// TriggerSchedulerDetect outputs a manually selected scheduler for the app +func TriggerSchedulerDetect(appName string) error { + if scheduler := common.PropertyGet("scheduler", appName, "selected"); scheduler != "" { + fmt.Println(scheduler) + return nil + } + + if scheduler := common.PropertyGet("scheduler", "--global", "selected"); scheduler != "" { + fmt.Println(scheduler) + return nil + } + + fmt.Println("docker-local") + return nil +} + +// TriggerInstall runs the install step for the scheduler plugin +func TriggerInstall() error { + if err := common.PropertySetup("scheduler"); err != nil { + return fmt.Errorf("Unable to install the scheduler plugin: %s", err.Error()) + } + + apps, err := common.DokkuApps() + if err != nil { + return nil + } + + globalScheduler := config.GetWithDefault("--scheduler", "DOKKU_SCHEDULER", "") + if globalScheduler != "" { + common.LogVerboseQuiet(fmt.Sprintf("Setting scheduler property 'selected' to %v", globalScheduler)) + if err := common.PropertyWrite("scheduler", "--global", "selected", globalScheduler); err != nil { + return err + } + + if err := config.UnsetMany("--global", []string{"DOKKU_SCHEDULER"}, false); err != nil { + common.LogWarn(err.Error()) + } + } + + for _, appName := range apps { + scheduler := config.GetWithDefault(appName, "DOKKU_SCHEDULER", "") + if scheduler == "" { + continue + } + + common.LogVerboseQuiet(fmt.Sprintf("Setting scheduler property 'selected' to %v", scheduler)) + if err := common.PropertyWrite("scheduler", appName, "selected", scheduler); err != nil { + return err + } + + if err := config.UnsetMany(appName, []string{"DOKKU_SCHEDULER"}, false); err != nil { + common.LogWarn(err.Error()) + } + } + + return nil +} + +// TriggerPostDelete destroys the scheduler property for a given app container +func TriggerPostDelete(appName string) error { + return common.PropertyDestroy("scheduler", appName) +} diff --git a/tests/unit/proxied-app.bats b/tests/unit/proxied-app.bats index 794f1a114..e16928634 100644 --- a/tests/unit/proxied-app.bats +++ b/tests/unit/proxied-app.bats @@ -19,7 +19,7 @@ teardown() { echo "status: $status" assert_success - run /bin/bash -c "dokku config:set $TEST_APP DOKKU_SCHEDULER=null" + run /bin/bash -c "dokku scheduler:set $TEST_APP selected null" echo "output: $output" echo "status: $status" assert_success