diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 17a2c71ff..9119826ab 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -58,7 +58,7 @@ jobs: PACKER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Get changed files in the docs folder id: changed-files-specific - uses: tj-actions/changed-files@v42.1.0 + uses: tj-actions/changed-files@v43.0.0 with: files: contrib/images/digitalocean/** - name: Run `packer validate` diff --git a/Makefile b/Makefile index 06cac420a..9b177269b 100644 --- a/Makefile +++ b/Makefile @@ -75,9 +75,12 @@ go-clean: fi ;\ done -copyfiles: - $(MAKE) go-build || exit 1 +copydokku: cp dokku /usr/local/bin/dokku + chmod 0755 /usr/local/bin/dokku + +copyfiles: copydokku + $(MAKE) go-build || exit 1 mkdir -p ${CORE_PLUGINS_PATH} ${PLUGINS_PATH} rm -rf ${CORE_PLUGINS_PATH}/* test -d ${CORE_PLUGINS_PATH}/enabled || PLUGIN_PATH=${CORE_PLUGINS_PATH} plugn init diff --git a/contrib/dokku_client.sh b/contrib/dokku_client.sh index 590d3d0dc..d2c7c4f04 100755 --- a/contrib/dokku_client.sh +++ b/contrib/dokku_client.sh @@ -188,9 +188,14 @@ main() { [[ " storage:ensure-directory " == *" $CMD "* ]] && unset APP [[ "$CMD" =~ events*|plugin*|ssh-keys* ]] && unset APP [[ -n "$APP_ARG" ]] && [[ "$APP_ARG" == "--global" ]] && unset APP - [[ -n "$@" ]] && [[ -n "$APP" ]] && app_arg="--app $APP" + if [[ -n "$@" ]] && [[ -n "$APP" ]]; then + set -- "$APP" "$@" + set -- "--app" "$@" + fi # echo "ssh -o LogLevel=QUIET -p $DOKKU_PORT -t dokku@$DOKKU_REMOTE_HOST -- $app_arg $@" - ssh -o LogLevel=QUIET -p $DOKKU_PORT -t dokku@$DOKKU_REMOTE_HOST -- $app_arg $@ || { + local ssh_args=("-o" "LogLevel=QUIET" "-p" "$DOKKU_PORT" "-t" "dokku@$DOKKU_REMOTE_HOST" "--") + ssh_args+=("$@") + ssh "${ssh_args[@]}" || { ssh_exit_code="$?" echo " ! Failed to execute dokku command over ssh: exit code $?" 1>&2 echo " ! If there was no output from Dokku, ensure your configured SSH Key can connect to the remote server" 1>&2 diff --git a/docs/_build/requirements.txt b/docs/_build/requirements.txt index df25e547d..ca779377d 100644 --- a/docs/_build/requirements.txt +++ b/docs/_build/requirements.txt @@ -3,7 +3,7 @@ click==8.1.7 ghp-import==2.1.0 importlib-metadata==7.0.2 Jinja2==3.1.3 -Markdown>=3.2.1,<3.6 +Markdown>=3.2.1,<3.7 MarkupSafe==2.1.5 mergedeep==1.3.4 mkdocs==1.5.3 @@ -20,4 +20,4 @@ pyyaml_env_tag==0.1 six==1.16.0 soupsieve==2.5 watchdog==4.0.0 -zipp==3.17.0 +zipp==3.18.1 diff --git a/docs/appendices/0.34.0-migration-guide.md b/docs/appendices/0.34.0-migration-guide.md new file mode 100644 index 000000000..43461200f --- /dev/null +++ b/docs/appendices/0.34.0-migration-guide.md @@ -0,0 +1,14 @@ +# 0.34.0 Migration Guide + +## Removals + +- The `disable-chown` property of the `scheduler-docker-local` plugin has been removed. Mounted paths will no longer have file permissions changed during the pre-deploy phase. Files baked into the container image for herokuish builds will always be owned by the correct user. +- The `git:unlock` command has been removed. It was previously used to "unlock" a temporary directory that already existed. The directory the `git:unlock` command used to cleanup is now properly removed on exit of the `git:from-image` command. + +## Changes + +- The k3s scheduler now defaults to nginx as it's default proxy implementation. The traefik proxy implementation is still available, though users will need to set the global `ingress-class` k3s property to `traefik` via the following command: + + ```shell + dokku scheduler-k3s:set --global ingress-class traefik + ``` diff --git a/docs/deployment/methods/git.md b/docs/deployment/methods/git.md index 9126a3d62..eb46b3261 100644 --- a/docs/deployment/methods/git.md +++ b/docs/deployment/methods/git.md @@ -10,13 +10,12 @@ git:from-archive [--archive-type ARCHIVE_TYPE] [ [ ] # Updates an app's git repository with a given docker image git:generate-deploy-key # Generates a deploy ssh key git:load-image [--build-dir DIRECTORY] [ ] # Updates an app's git repository with a docker image loaded from stdin -git:sync [--build] [] # Clone or fetch an app from remote git repo +git:sync [--build|build-if-changes] [] # Clone or fetch an app from remote git repo git:initialize # Initialize a git repository for an app git:public-key # Outputs the dokku public deploy key git:report [] [] # Displays a git report for one or more apps git:set () # Set or clear a git property for an app git:status # Show the working tree status for an app -git:unlock [--force] # Removes previous git clone folder for new deployment ``` Git-based deployment has been the traditional method of deploying applications in Dokku. As of v0.12.0, Dokku introduces a few ways to customize the experience of deploying via `git push`. A Git-based deployment currently supports building applications via: @@ -158,6 +157,12 @@ By default, this command does not trigger an application build. To do so during dokku git:sync --build node-js-app https://github.com/heroku/node-js-getting-started.git ``` +When running `git:sync` without a reference, it may be useful to only build when there are changes. To do so, specify the `--build-if-changes` flag. + +```shell +dokku git:sync --build-if-changes node-js-app https://github.com/heroku/node-js-getting-started.git +``` + ### Initializing from private repositories > [!IMPORTANT] diff --git a/docs/deployment/schedulers/docker-local.md b/docs/deployment/schedulers/docker-local.md index a5f78d279..869f937ad 100644 --- a/docs/deployment/schedulers/docker-local.md +++ b/docs/deployment/schedulers/docker-local.md @@ -32,20 +32,6 @@ dokku scheduler:set node-js-app selected Many builders only produce amd64-compatible images. The docker-local scheduler will automatically detect these and run them via the `--platform=linux/amd64` on arm64 deploy targets. -### Disabling chown of persistent storage - -The `scheduler-docker-local` plugin will ensure your storage mounts are owned by either `herokuishuser` or the overridden value you have set in `DOKKU_APP_USER`. You may disable this by running the following `scheduler-docker-local:set` command for your application: - -```shell -dokku scheduler-docker-local:set node-js-app disable-chown true -``` - -Once set, you may re-enable it by setting a blank value for `disable-chown`: - -```shell -dokku scheduler-docker-local:set node-js-app disable-chown -``` - ### Disabling the init process The `scheduler-docker-local` injects an init process by default via the `--init`. For some apps - such as those where the built docker image uses S6 as the init - this may be undesirable and cause issues with process starts. You may disable this by running the following `scheduler-docker-local:set` command for your application: diff --git a/docs/deployment/schedulers/k3s.md b/docs/deployment/schedulers/k3s.md index e24a3b4db..c357332ea 100644 --- a/docs/deployment/schedulers/k3s.md +++ b/docs/deployment/schedulers/k3s.md @@ -58,12 +58,12 @@ By default, Dokku will attempt to auto-detect the IP address of the server. In c dokku scheduler-k3s:initialize --server-ip 192.168.20.15 ``` -Dokku's k3s integration natively uses `Traefik` as it's ingress load balancer via [Traefik's CRDs](https://doc.traefik.io/traefik/providers/kubernetes-crd/), but a cluster can be set to use `nginx` via the [ingress-nginx](https://github.com/kubernetes/ingress-nginx) project. Switching to nginx will result in any `nginx` plugin settings being respected, either by turning them into annotations or creating a custom server snippet. +Dokku's k3s integration natively uses `nginx` as it's ingress load balancer via [ingress-nginx](https://github.com/kubernetes/ingress-nginx). Properties set by the `nginx` plugin will be respected, either by turning them into annotations or creating a custom server/location snippet that the `ingress-nginx` project can use. -To change the ingress, set the `--ingress-class` flag: +Dokku can also use Traefik on cluster initialization via the [Traefik's CRDs](https://doc.traefik.io/traefik/providers/kubernetes-crd/). To change the ingress, set the `--ingress-class` flag: ```shell -dokku scheduler-k3s:initialize --ingress-class nginx +dokku scheduler-k3s:initialize --ingress-class traefik ``` ### Adding nodes to the cluster diff --git a/docs/getting-started/upgrading/index.md b/docs/getting-started/upgrading/index.md index a8bad588a..ce2b6a60c 100644 --- a/docs/getting-started/upgrading/index.md +++ b/docs/getting-started/upgrading/index.md @@ -18,6 +18,7 @@ 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.34](/docs/appendices/0.34.0-migration-guide.md) - [Upgrading to 0.33](/docs/appendices/0.33.0-migration-guide.md) - [Upgrading to 0.32](/docs/appendices/0.32.0-migration-guide.md) - [Upgrading to 0.31](/docs/appendices/0.31.0-migration-guide.md) diff --git a/docs/networking/proxies/traefik.md b/docs/networking/proxies/traefik.md index bf89e9398..8657f3054 100644 --- a/docs/networking/proxies/traefik.md +++ b/docs/networking/proxies/traefik.md @@ -116,16 +116,6 @@ dokku traefik:set --global log-level DEBUG After modifying, the Traefik container will need to be restarted. -### Setting rule priority - -By default, app deployments will result in the newer traefik rules using a higher priority in order to have any newer rules respected by Traefik. Rule priorities will always increase according to the current unix timestamp. The priority may be fixed by setting the app-level `priority` property: - -```shell -dokku traefik:set node-js-app priority 12345 -``` - -After modifying, the app container will need to be recreated via a `ps:rebuild` or an app deployment. - ### SSL Configuration The traefik plugin only supports automatic ssl certificates from it's letsencrypt integration. Managed certificates provided by the `certs` plugin are ignored. diff --git a/docs/networking/proxy-management.md b/docs/networking/proxy-management.md index 470b525ec..6b1ec7f55 100644 --- a/docs/networking/proxy-management.md +++ b/docs/networking/proxy-management.md @@ -12,7 +12,7 @@ proxy:report [] [] # Displays a proxy report fo proxy:set [|--global] # Set proxy type for app ``` -In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into the proxy plugin. Dokku 0.6.0 introduced the ability to map host ports to specific container ports. In the future this will allow other proxy software - such as HAProxy or Caddy - to be used in place of nginx. +In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into the proxy plugin. Dokku 0.6.0 introduced the ability to map host ports to specific container ports. This allows other proxy software - such as HAProxy or Caddy - to be used in place of nginx. ## Usage diff --git a/dokku b/dokku index 46f8d6f92..862efa690 100755 --- a/dokku +++ b/dokku @@ -55,7 +55,7 @@ export DOKKU_SYSTEM_USER=${DOKKU_SYSTEM_USER:="dokku"} export DOKKU_API_VERSION=1 export DOKKU_NOT_IMPLEMENTED_EXIT=10 export DOKKU_VALID_EXIT=0 -export DOKKU_PID="$BASHPID" +export DOKKU_PID="${DOKKU_PID:=$$}" export DOKKU_LOGS_DIR=${DOKKU_LOGS_DIR:="/var/log/dokku"} export DOKKU_LOGS_HOST_DIR=${DOKKU_LOGS_HOST_DIR:=$DOKKU_LOGS_DIR} @@ -88,8 +88,8 @@ fi ! has_tty && DOKKU_QUIET_OUTPUT=1 if [[ $(id -un) != "dokku" ]]; then - unset TMP TMPDIR TEMP TEMPDIR if [[ ! $1 =~ plugin:* ]] && [[ $1 != "ssh-keys:add" ]] && [[ $1 != "ssh-keys:remove" ]] && [[ $1 != "scheduler-k3s:initialize" ]] && [[ $1 != "scheduler-k3s:uninstall" ]]; then + unset DOKKU_PID TMP TMPDIR TEMP TEMPDIR export SSH_USER=$(id -un) sudo -u dokku -E -H "$0" "$@" exit $? @@ -106,15 +106,20 @@ fi if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then export -n SSH_ORIGINAL_COMMAND - if [[ $1 =~ config-* ]] || [[ $1 =~ docker-options* ]]; then - xargs $0 <<<$SSH_ORIGINAL_COMMAND - exit $? - else + exit_code=0 + if [[ $1 =~ git-* ]] || [[ $1 =~ git:* ]]; then set -f $0 $SSH_ORIGINAL_COMMAND + exit_code=$? + set +f + else + readarray -t -O "${#ssh_arg_array[@]}" ssh_arg_array < <(printf '%s' "$SSH_ORIGINAL_COMMAND" | xargs -n 1) + set -f + $0 "${ssh_arg_array[@]}" + exit_code=$? set +f - exit $? fi + exit $exit_code fi if ! dokku_auth "$@"; then diff --git a/plugins/00_dokku-standard/subcommands/report b/plugins/00_dokku-standard/subcommands/report index 791772fa9..d9ead2b29 100755 --- a/plugins/00_dokku-standard/subcommands/report +++ b/plugins/00_dokku-standard/subcommands/report @@ -17,6 +17,10 @@ cmd-report() { dokku_log_info1 "uname: $(uname -a)" dokku_log_info1 "memory: " free -m | sed "s/^/ /" + dokku_log_info1 "disk utilization: " + df -h --type btrfs --type ext4 --type ext3 --type ext2 --type vfat --type iso9660 | sed "s/^/ /" + dokku_log_info1 "disk inode utilization: " + df -hi --type btrfs --type ext4 --type ext3 --type ext2 --type vfat --type iso9660 | sed "s/^/ /" dokku_log_info1 "docker version: " "$DOCKER_BIN" version | sed "s/^/ /" dokku_log_info1 "docker daemon info: " diff --git a/plugins/20_events/install b/plugins/20_events/install index 9a352e198..ffebb1977 100755 --- a/plugins/20_events/install +++ b/plugins/20_events/install @@ -56,16 +56,12 @@ EOF cat >"$DOKKU_LOGROTATE_FILE" </dev/null || true - endscript - create 664 syslog dokku + notifempty + copytruncate } EOF diff --git a/plugins/app-json/functions.go b/plugins/app-json/functions.go index fe24ca885..99527666d 100644 --- a/plugins/app-json/functions.go +++ b/plugins/app-json/functions.go @@ -102,8 +102,11 @@ func getPhaseScript(appName string, phase string) (string, error) { func getReleaseCommand(appName string, image string) string { processType := "release" port := "5000" - b, _ := common.PlugnTriggerOutput("procfile-get-command", []string{appName, processType, port}...) - return strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "procfile-get-command", + Args: []string{appName, processType, port}, + }) + return results.StdoutContents() } func getDokkuAppShell(appName string) string { @@ -114,13 +117,19 @@ func getDokkuAppShell(appName string) string { ctx := context.Background() errs, ctx := errgroup.WithContext(ctx) errs.Go(func() error { - b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_APP_SHELL"}...) - globalShell = strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTriggerWithContext(ctx, common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_APP_SHELL"}, + }) + globalShell = results.StdoutContents() return nil }) errs.Go(func() error { - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_APP_SHELL"}...) - appShell = strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTriggerWithContext(ctx, common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_APP_SHELL"}, + }) + appShell = results.StdoutContents() return nil }) @@ -204,8 +213,13 @@ func executeScript(appName string, image string, imageTag string, phase string) } var dockerArgs []string - if b, err := common.PlugnTriggerSetup("docker-args-deploy", []string{appName, imageTag}...).SetInput("").Output(); err == nil { - words, err := shellquote.Split(strings.TrimSpace(string(b[:]))) + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "docker-args-deploy", + Args: []string{appName, imageTag}, + Stdin: strings.NewReader(""), + }) + if err == nil { + words, err := shellquote.Split(results.StdoutContents()) if err != nil { return err } @@ -213,8 +227,13 @@ func executeScript(appName string, image string, imageTag string, phase string) dockerArgs = append(dockerArgs, words...) } - if b, err := common.PlugnTriggerSetup("docker-args-process-deploy", []string{appName, imageSourceType, imageTag}...).SetInput("").Output(); err == nil { - words, err := shellquote.Split(strings.TrimSpace(string(b[:]))) + results, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "docker-args-process-deploy", + Args: []string{appName, imageSourceType, imageTag}, + Stdin: strings.NewReader(""), + }) + if err == nil { + words, err := shellquote.Split(results.StdoutContents()) if err != nil { return err } @@ -398,12 +417,15 @@ func createdContainerID(appName string, dockerArgs []string, image string, comma arguments = append(arguments, image) arguments = append(arguments, command...) - b, err := common.PlugnTriggerOutput("config-export", []string{appName, "false", "true", "json"}...) + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-export", + Args: []string{appName, "false", "true", "json"}, + }) if err != nil { return "", err } var env map[string]string - if err := json.Unmarshal(b, &env); err != nil { + if err := json.Unmarshal(results.StdoutBytes(), &env); err != nil { return "", err } @@ -420,7 +442,11 @@ func createdContainerID(appName string, dockerArgs []string, image string, comma } containerID := result.StdoutContents() - err = common.PlugnTrigger("post-container-create", []string{"app", containerID, appName, phase}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-container-create", + Args: []string{"app", containerID, appName, phase}, + StreamStdio: true, + }) return containerID, err } @@ -440,12 +466,27 @@ func setScale(appName string, image string) error { } if len(args) == 3 { - return common.PlugnTrigger("ps-can-scale", []string{appName, "true"}...) - } - - if err := common.PlugnTrigger("ps-can-scale", []string{appName, "false"}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "ps-can-scale", + Args: []string{appName, "true"}, + StreamStdio: true, + }) return err } - return common.PlugnTrigger("ps-set-scale", args...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "ps-can-scale", + Args: []string{appName, "false"}, + StreamStdio: true, + }) + if err != nil { + return err + } + + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "ps-set-scale", + Args: args, + StreamStdio: true, + }) + return err } diff --git a/plugins/app-json/go.mod b/plugins/app-json/go.mod index 8ffa9aa50..da0eeb9ba 100644 --- a/plugins/app-json/go.mod +++ b/plugins/app-json/go.mod @@ -12,8 +12,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/app-json/go.sum b/plugins/app-json/go.sum index 6131c1424..bc9e30440 100644 --- a/plugins/app-json/go.sum +++ b/plugins/app-json/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/plugins/app-json/triggers.go b/plugins/app-json/triggers.go index 230e423c1..b556c0d49 100644 --- a/plugins/app-json/triggers.go +++ b/plugins/app-json/triggers.go @@ -101,11 +101,17 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error { } processSpecificAppJSON := fmt.Sprintf("%s.%s", existingAppJSON, os.Getenv("DOKKU_PID")) - b, _ := common.PlugnTriggerOutput("git-get-property", []string{appName, "source-image"}...) - appSourceImage := strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "git-get-property", + Args: []string{appName, "source-image"}, + }) + appSourceImage := results.StdoutContents() - b, _ = common.PlugnTriggerOutput("builder-get-property", []string{appName, "build-dir"}...) - buildDir := strings.TrimSpace(string(b[:])) + results, _ = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "builder-get-property", + Args: []string{appName, "build-dir"}, + }) + buildDir := results.StdoutContents() repoDefaultAppJSONPath := path.Join(sourceWorkDir, "app.json") if appSourceImage == "" { @@ -179,7 +185,7 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { return common.CloneAppData("app-json", oldAppName, newAppName) } -// TriggerPostCreate ensures apps the correct data directory structure +// TriggerPostCreate ensures apps have the correct data directory structure func TriggerPostCreate(appName string) error { return common.CreateAppDataDirectory("app-json", appName) } diff --git a/plugins/apps/Makefile b/plugins/apps/Makefile index 8a92e94b9..7bf928361 100644 --- a/plugins/apps/Makefile +++ b/plugins/apps/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/clone subcommands/create subcommands/destroy subcommands/exists subcommands/list subcommands/lock subcommands/locked subcommands/rename subcommands/report subcommands/unlock -TRIGGERS = triggers/app-create triggers/app-destroy triggers/app-exists triggers/app-maybe-create triggers/deploy-source-set triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report +TRIGGERS = triggers/app-create triggers/app-destroy triggers/app-exists triggers/app-maybe-create triggers/deploy-source-set triggers/install triggers/post-app-clone-setup triggers/post-app-rename triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = apps diff --git a/plugins/apps/functions.go b/plugins/apps/functions.go index 60cfb6e4c..96a3e04f0 100644 --- a/plugins/apps/functions.go +++ b/plugins/apps/functions.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "os" - "strings" "time" "github.com/dokku/dokku/plugins/common" @@ -17,8 +16,8 @@ func appExists(appName string) error { // checks if an app is locked func appIsLocked(appName string) bool { - lockfilePath := fmt.Sprintf("%v/.deploy.lock", common.AppRoot(appName)) - _, err := os.Stat(lockfilePath) + lockPath := getLockPath(appName) + _, err := os.Stat(lockPath) return !os.IsNotExist(err) } @@ -39,11 +38,12 @@ func createApp(appName string) error { return err } - if err := common.PlugnTrigger("post-create", []string{appName}...); err != nil { - return err - } - - return nil + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-create", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // destroys an app @@ -57,19 +57,41 @@ func destroyApp(appName string) error { common.LogInfo1(fmt.Sprintf("Destroying %s (including all add-ons)", appName)) imageTag, _ := common.GetRunningImageTag(appName, "") - if err := common.PlugnTrigger("pre-delete", []string{appName, imageTag}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "pre-delete", + Args: []string{appName, imageTag}, + StreamStdio: true, + }) + if err != nil { return err } scheduler := common.GetAppScheduler(appName) removeContainers := "true" - if err := common.PlugnTrigger("scheduler-stop", []string{scheduler, appName, removeContainers}...); err != nil { + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-stop", + Args: []string{scheduler, appName, removeContainers}, + StreamStdio: true, + }) + if err != nil { return err } - if err := common.PlugnTrigger("scheduler-post-delete", []string{scheduler, appName, imageTag}...); err != nil { + + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-post-delete", + Args: []string{scheduler, appName, imageTag}, + StreamStdio: true, + }) + if err != nil { return err } - if err := common.PlugnTrigger("post-delete", []string{appName, imageTag}...); err != nil { + + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-delete", + Args: []string{appName, imageTag}, + StreamStdio: true, + }) + if err != nil { return err } @@ -77,7 +99,12 @@ func destroyApp(appName string) error { common.DockerCleanup(appName, forceCleanup) common.LogInfo1("Retiring old containers and images") - if err := common.PlugnTrigger("scheduler-retire", []string{scheduler, appName}...); err != nil { + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-retire", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + if err != nil { return err } @@ -94,14 +121,22 @@ func destroyApp(appName string) error { return nil } +// returns the lock path +func getLockPath(appName string) string { + return fmt.Sprintf("%v/.deploy.lock", common.GetAppDataDirectory("apps", appName)) +} + // creates an app if allowed func maybeCreateApp(appName string) error { if err := appExists(appName); err == nil { return nil } - b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_DISABLE_APP_AUTOCREATION"}...) - disableAutocreate := strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_DISABLE_APP_AUTOCREATION"}, + }) + disableAutocreate := results.StdoutContents() if disableAutocreate == "true" { common.LogWarn("App auto-creation disabled.") return fmt.Errorf("Re-enable app auto-creation or create an app with 'dokku apps:create %s'", appName) diff --git a/plugins/apps/go.mod b/plugins/apps/go.mod index f9c13adab..a7453d6cf 100644 --- a/plugins/apps/go.mod +++ b/plugins/apps/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/apps/go.sum b/plugins/apps/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/apps/go.sum +++ b/plugins/apps/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/apps/src/triggers/triggers.go b/plugins/apps/src/triggers/triggers.go index e79febbed..191ba79c3 100644 --- a/plugins/apps/src/triggers/triggers.go +++ b/plugins/apps/src/triggers/triggers.go @@ -41,10 +41,17 @@ func main() { oldAppName := flag.Arg(0) newAppName := flag.Arg(1) err = apps.TriggerPostAppCloneSetup(oldAppName, newAppName) + case "post-app-rename": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = apps.TriggerPostAppRename(oldAppName, newAppName) case "post-app-rename-setup": oldAppName := flag.Arg(0) newAppName := flag.Arg(1) err = apps.TriggerPostAppRenameSetup(oldAppName, newAppName) + case "post-create": + appName := flag.Arg(0) + err = apps.TriggerPostCreate(appName) case "post-delete": appName := flag.Arg(0) err = apps.TriggerPostDelete(appName) diff --git a/plugins/apps/subcommands.go b/plugins/apps/subcommands.go index d8eef9ba2..56e6f7cc4 100644 --- a/plugins/apps/subcommands.go +++ b/plugins/apps/subcommands.go @@ -40,7 +40,12 @@ func CommandClone(oldAppName string, newAppName string, skipDeploy bool, ignoreE return err } - if err := common.PlugnTrigger("post-app-clone-setup", []string{oldAppName, newAppName}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-app-clone-setup", + Args: []string{oldAppName, newAppName}, + StreamStdio: true, + }) + if err != nil { return err } @@ -48,15 +53,21 @@ func CommandClone(oldAppName string, newAppName string, skipDeploy bool, ignoreE os.Setenv("SKIP_REBUILD", "true") } - if err := common.PlugnTrigger("git-has-code", []string{newAppName}...); err != nil { + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "git-has-code", + Args: []string{newAppName}, + StreamStdio: true, + }) + if err != nil { os.Setenv("SKIP_REBUILD", "true") } - if err := common.PlugnTrigger("post-app-clone", []string{oldAppName, newAppName}...); err != nil { - return err - } - - return nil + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-app-clone", + Args: []string{oldAppName, newAppName}, + StreamStdio: true, + }) + return err } // CommandCreate creates app via command line @@ -108,8 +119,8 @@ func CommandLock(appName string) error { return err } - lockfilePath := fmt.Sprintf("%v/.deploy.lock", common.AppRoot(appName)) - if _, err := os.Create(lockfilePath); err != nil { + lockPath := getLockPath(appName) + if _, err := os.Create(lockPath); err != nil { return errors.New("Unable to create deploy lock") } @@ -158,7 +169,12 @@ func CommandRename(oldAppName string, newAppName string, skipDeploy bool) error return err } - if err := common.PlugnTrigger("post-app-rename-setup", []string{oldAppName, newAppName}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-app-rename-setup", + Args: []string{oldAppName, newAppName}, + StreamStdio: true, + }) + if err != nil { return err } @@ -171,15 +187,21 @@ func CommandRename(oldAppName string, newAppName string, skipDeploy bool) error os.Setenv("SKIP_REBUILD", "true") } - if err := common.PlugnTrigger("git-has-code", []string{newAppName}...); err != nil { + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "git-has-code", + Args: []string{newAppName}, + StreamStdio: true, + }) + if err != nil { os.Setenv("SKIP_REBUILD", "true") } - if err := common.PlugnTrigger("post-app-rename", []string{oldAppName, newAppName}...); err != nil { - return err - } - - return nil + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-app-rename", + Args: []string{oldAppName, newAppName}, + StreamStdio: true, + }) + return err } // CommandReport displays an app report for one or more apps @@ -206,7 +228,7 @@ func CommandUnlock(appName string) error { return err } - lockfilePath := fmt.Sprintf("%v/.deploy.lock", common.AppRoot(appName)) + lockfilePath := getLockPath(appName) if _, err := os.Stat(lockfilePath); !os.IsNotExist(err) { common.LogWarn("A deploy may be in progress.") common.LogWarn("Removing the app lock will not stop in progress deploys.") diff --git a/plugins/apps/triggers.go b/plugins/apps/triggers.go index 9a82d9363..ad16adb10 100644 --- a/plugins/apps/triggers.go +++ b/plugins/apps/triggers.go @@ -43,6 +43,10 @@ func TriggerInstall() error { return fmt.Errorf("Unable to install the apps plugin: %s", err.Error()) } + if err := common.SetupAppData("apps"); err != nil { + return err + } + apps, err := common.UnfilteredDokkuApps() if err != nil { return nil @@ -79,7 +83,12 @@ func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { return err } - return nil + return common.CloneAppData("apps", oldAppName, newAppName) +} + +// TriggerPostAppRename removes the old app data +func TriggerPostAppRename(oldAppName string, newAppName string) error { + return common.MigrateAppDataDirectory("apps", oldAppName, newAppName) } // TriggerPostAppRenameSetup renames apps files @@ -92,14 +101,22 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { return err } - return nil + return common.CloneAppData("apps", oldAppName, newAppName) } -// TriggerPostDelete is the apps post-delete plugin trigger +// TriggerPostCreate ensures apps have the correct data directory structure +func TriggerPostCreate(appName string) error { + return common.CreateAppDataDirectory("apps", appName) +} + +// TriggerPostDelete destroys the apps data for a given app container func TriggerPostDelete(appName string) error { - if err := common.PropertyDestroy("apps", appName); err != nil { - common.LogWarn(err.Error()) + dataErr := common.RemoveAppDataDirectory("apps", appName) + propertyErr := common.PropertyDestroy("apps", appName) + + if dataErr != nil { + return dataErr } - return nil + return propertyErr } diff --git a/plugins/builder-herokuish/builder-release b/plugins/builder-herokuish/builder-release index 2522f7c55..e8b845d3d 100755 --- a/plugins/builder-herokuish/builder-release +++ b/plugins/builder-herokuish/builder-release @@ -33,7 +33,10 @@ trigger-builder-herokuish-builder-release() { DOCKER_BUILD_ARGS+=("--platform=linux/amd64") fi - if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-herokuish/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$TMP_WORK_DIR"; then + DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true) + DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"} + + if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-herokuish/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" --build-arg DOKKU_APP_USER=$DOKKU_APP_USER -t "$IMAGE" "$TMP_WORK_DIR"; then dokku_log_warn "Failure injecting environment variables" return 1 fi diff --git a/plugins/builder-herokuish/dockerfiles/builder-release.Dockerfile b/plugins/builder-herokuish/dockerfiles/builder-release.Dockerfile index 9f88539df..b6a59e631 100644 --- a/plugins/builder-herokuish/dockerfiles/builder-release.Dockerfile +++ b/plugins/builder-herokuish/dockerfiles/builder-release.Dockerfile @@ -1,4 +1,8 @@ ARG APP_IMAGE FROM $APP_IMAGE -COPY 00-global-env.sh 01-app-env.sh /app/.profile.d/ +ARG DOKKU_APP_USER herokuishuser +COPY --chown=$DOKKU_APP_USER 00-global-env.sh 01-app-env.sh /app/.profile.d/ +RUN chown -R "$DOKKU_APP_USER:$DOKKU_APP_USER" /app +USER $DOKKU_APP_USER +ENV HEROKUISH_SETUIDGUID false diff --git a/plugins/builder-herokuish/dockerfiles/copy-source.Dockerfile b/plugins/builder-herokuish/dockerfiles/copy-source.Dockerfile index 4769e35c6..0bb8e9aae 100644 --- a/plugins/builder-herokuish/dockerfiles/copy-source.Dockerfile +++ b/plugins/builder-herokuish/dockerfiles/copy-source.Dockerfile @@ -4,4 +4,5 @@ FROM $APP_IMAGE ARG DOKKU_APP_USER herokuishuser RUN USER=$DOKKU_APP_USER /exec true COPY --chown=$DOKKU_APP_USER . /app -WORKDIR /app \ No newline at end of file +WORKDIR /app +ENV HEROKUISH_DISABLE_CHOWN true diff --git a/plugins/builder-herokuish/dockerfiles/pre-build.Dockerfile b/plugins/builder-herokuish/dockerfiles/pre-build.Dockerfile index 943c4c1e9..a2ab687ee 100644 --- a/plugins/builder-herokuish/dockerfiles/pre-build.Dockerfile +++ b/plugins/builder-herokuish/dockerfiles/pre-build.Dockerfile @@ -1,5 +1,5 @@ ARG APP_IMAGE FROM $APP_IMAGE -COPY .env.d /tmp/env -COPY .env /app/.env +COPY --chown=$DOKKU_APP_USER .env.d /tmp/env +COPY --chown=$DOKKU_APP_USER .env /app/.env diff --git a/plugins/builder-herokuish/post-app-clone-setup b/plugins/builder-herokuish/post-app-clone-setup deleted file mode 100755 index 3abb15417..000000000 --- a/plugins/builder-herokuish/post-app-clone-setup +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" - -trigger-builder-herokuish-post-app-clone-setup() { - declare desc="builder-herokuish post-app-clone-setup plugin trigger" - declare trigger="post-app-clone-setup" - declare OLD_APP="$1" NEW_APP="$2" - - local NEW_CACHE_DIR="$DOKKU_ROOT/$NEW_APP/cache" - local NEW_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$NEW_APP/cache" - - pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null - find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" - popd &>/dev/null || pushd "/tmp" >/dev/null - - if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" - "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$NEW_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache - fi - rm -rf "$NEW_CACHE_DIR" -} - -trigger-builder-herokuish-post-app-clone-setup "$@" diff --git a/plugins/builder-herokuish/post-app-rename-setup b/plugins/builder-herokuish/post-app-rename-setup deleted file mode 100755 index 26c5a6dbb..000000000 --- a/plugins/builder-herokuish/post-app-rename-setup +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" - -trigger-builder-herokuish-post-app-clone-setup() { - declare desc="builder-herokuish post-app-clone-setup plugin trigger" - declare trigger="post-app-clone-setup" - declare OLD_APP="$1" NEW_APP="$2" - - local OLD_CACHE_DIR="$DOKKU_ROOT/$OLD_APP/cache" - local OLD_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$OLD_APP/cache" - - if [[ -d "$OLD_CACHE_DIR" ]] && ! rmdir "$OLD_CACHE_DIR" &>/dev/null; then - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" - "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$OLD_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache - fi - rm -rf "$OLD_CACHE_DIR" - - pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null - find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" - popd &>/dev/null || pushd "/tmp" >/dev/null -} - -trigger-builder-herokuish-post-app-clone-setup "$@" diff --git a/plugins/builder/go.mod b/plugins/builder/go.mod index 66c63df64..59d3bec3b 100644 --- a/plugins/builder/go.mod +++ b/plugins/builder/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/builder/go.sum b/plugins/builder/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/builder/go.sum +++ b/plugins/builder/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/buildpacks/functions.go b/plugins/buildpacks/functions.go index 04f933b3d..f3545233e 100644 --- a/plugins/buildpacks/functions.go +++ b/plugins/buildpacks/functions.go @@ -44,7 +44,7 @@ func rewriteBuildpacksFile(sourceWorkDir string) error { func validBuildpackURL(buildpack string) (string, error) { if buildpack == "" { - return buildpack, errors.New("Must specify a buildpack to add") + return buildpack, errors.New("Must specify a buildpack url or reference") } reHerokuValue := regexp.MustCompile(`(?m)^([\w-]+\/[\w-]+)$`) diff --git a/plugins/buildpacks/go.mod b/plugins/buildpacks/go.mod index cf1b1530d..779a4a1ca 100644 --- a/plugins/buildpacks/go.mod +++ b/plugins/buildpacks/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/buildpacks/go.sum b/plugins/buildpacks/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/buildpacks/go.sum +++ b/plugins/buildpacks/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/buildpacks/report.go b/plugins/buildpacks/report.go index 68b95aa01..cec28af2a 100644 --- a/plugins/buildpacks/report.go +++ b/plugins/buildpacks/report.go @@ -40,8 +40,11 @@ func reportComputedStack(appName string) string { return stack } - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_IMAGE"}...) - if dokkuImage := strings.TrimSpace(string(b[:])); dokkuImage != "" { + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_IMAGE"}, + }) + if dokkuImage := results.StdoutContents(); dokkuImage != "" { common.LogWarn("Deprecated: use buildpacks:set-property instead of specifying DOKKU_IMAGE environment variable") return dokkuImage } diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 9a49ffabc..24d3125ef 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -65,7 +65,7 @@ func CommandRemove(appName string, buildpack string, index int) (err error) { } buildpack, err = validBuildpackURL(buildpack) - if err != nil { + if index == 0 && err != nil { return err } @@ -149,7 +149,12 @@ func CommandSetProperty(appName string, property string, value string) error { common.CommandPropertySet("buildpacks", appName, property, value, DefaultProperties, GlobalProperties) if property == "stack" && oldStack != value { if appName != "--global" { - return common.PlugnTrigger("post-stack-set", []string{appName, value}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-stack-set", + Args: []string{appName, value}, + StreamStdio: true, + }) + return err } apps, err := common.DokkuApps() @@ -157,7 +162,12 @@ func CommandSetProperty(appName string, property string, value string) error { return err } for _, app := range apps { - if err := common.PlugnTrigger("post-stack-set", []string{app, value}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-stack-set", + Args: []string{app, value}, + StreamStdio: true, + }) + if err != nil { return err } } diff --git a/plugins/buildpacks/triggers.go b/plugins/buildpacks/triggers.go index 187a0f8e1..37f1c33d7 100644 --- a/plugins/buildpacks/triggers.go +++ b/plugins/buildpacks/triggers.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "path/filepath" - "strings" "github.com/dokku/dokku/plugins/common" ) @@ -22,8 +21,11 @@ func TriggerBuildpackStackName(appName string) error { return nil } - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_IMAGE"}...) - dokkuImage := strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_IMAGE"}, + }) + dokkuImage := results.StdoutContents() if dokkuImage != "" { common.LogWarn("Deprecated: use buildpacks:set-property instead of specifying DOKKU_IMAGE environment variable") fmt.Println(dokkuImage) diff --git a/plugins/common/common.go b/plugins/common/common.go index e0ffb613e..23e96c0f8 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -124,8 +124,11 @@ func GetAppScheduler(appName string) string { } func getAppScheduler(appName string) string { - b, _ := PlugnTriggerOutput("scheduler-detect", []string{appName}...) - value := strings.TrimSpace(string(b[:])) + results, _ := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "scheduler-detect", + Args: []string{appName}, + }) + value := results.StdoutContents() if value != "" { return value } @@ -134,8 +137,11 @@ func getAppScheduler(appName string) string { // GetGlobalScheduler fetchs the global scheduler func GetGlobalScheduler() string { - b, _ := PlugnTriggerOutput("scheduler-detect", []string{"--global"}...) - value := strings.TrimSpace(string(b[:])) + results, _ := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "scheduler-detect", + Args: []string{"--global"}, + }) + value := results.StdoutContents() if value != "" { return value } @@ -152,24 +158,34 @@ func GetDeployingAppImageName(appName, imageTag, imageRepo string) (string, erro ctx := context.Background() errs, ctx := errgroup.WithContext(ctx) errs.Go(func() error { - b, err := PlugnTriggerOutput("deployed-app-repository", []string{appName}...) + results, err := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "deployed-app-repository", + Args: []string{appName}, + }) if err == nil { - imageRemoteRepository = strings.TrimSpace(string(b[:])) + imageRemoteRepository = results.StdoutContents() } return err }) errs.Go(func() error { - b, err := PlugnTriggerOutput("deployed-app-image-tag", []string{appName}...) + results, err := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "deployed-app-image-tag", + Args: []string{appName}, + }) + if err == nil { - newImageTag = strings.TrimSpace(string(b[:])) + newImageTag = results.StdoutContents() } return err }) errs.Go(func() error { - b, err := PlugnTriggerOutput("deployed-app-image-repo", []string{appName}...) + results, err := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "deployed-app-image-repo", + Args: []string{appName}, + }) if err == nil { - newImageRepo = strings.TrimSpace(string(b[:])) + newImageRepo = results.StdoutContents() } return err }) @@ -251,11 +267,14 @@ func GetAppRunningContainerIDs(appName string, containerType string) ([]string, // GetRunningImageTag retrieves current deployed image tag for a given app func GetRunningImageTag(appName string, imageTag string) (string, error) { - b, err := PlugnTriggerOutput("deployed-app-image-tag", []string{appName}...) + results, err := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "deployed-app-image-tag", + Args: []string{appName}, + }) if err != nil { return imageTag, err } - newImageTag := strings.TrimSpace(string(b[:])) + newImageTag := results.StdoutContents() if newImageTag != "" { imageTag = newImageTag } @@ -326,7 +345,10 @@ func IsDeployed(appName string) bool { if deployed == "" { deployed = "false" scheduler := GetAppScheduler(appName) - _, err := PlugnTriggerOutput("scheduler-is-deployed", []string{scheduler, appName}...) + _, err := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "scheduler-is-deployed", + Args: []string{scheduler, appName}, + }) if err == nil { deployed = "true" } diff --git a/plugins/common/docker.go b/plugins/common/docker.go index 3ee17915f..e99fca680 100644 --- a/plugins/common/docker.go +++ b/plugins/common/docker.go @@ -182,9 +182,11 @@ func DockerCleanup(appName string, forceCleanup bool) error { triggerArgs = []string{"DOKKU_SKIP_CLEANUP"} } - b, _ := PlugnTriggerOutput(triggerName, triggerArgs...) - output := strings.TrimSpace(string(b[:])) - if output == "true" { + results, _ := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: triggerName, + Args: triggerArgs, + }) + if results.StdoutContents() == "true" { skipCleanup = true } } @@ -309,9 +311,12 @@ func IsImageHerokuishBased(image string, appName string) bool { dokkuAppUser := "" if len(appName) != 0 { - b, err := PlugnTriggerOutput("config-get", []string{appName, "DOKKU_APP_USER"}...) + results, err := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_APP_USER"}, + }) if err == nil { - dokkuAppUser = strings.TrimSpace(string(b)) + dokkuAppUser = results.StdoutContents() } } diff --git a/plugins/common/exec.go b/plugins/common/exec.go index 84eaa8954..c8471cc6f 100644 --- a/plugins/common/exec.go +++ b/plugins/common/exec.go @@ -77,6 +77,16 @@ func (ecr ExecCommandResponse) StderrContents() string { return strings.TrimSpace(ecr.Stderr) } +// StderrBytes returns the trimmed stderr of the command as bytes +func (ecr ExecCommandResponse) StderrBytes() []byte { + return []byte(ecr.StderrContents()) +} + +// StdoutBytes returns the trimmed stdout of the command as bytes +func (ecr ExecCommandResponse) StdoutBytes() []byte { + return []byte(ecr.StdoutContents()) +} + // CallExecCommand executes a command on the local host func CallExecCommand(input ExecCommandInput) (ExecCommandResponse, error) { ctx := context.Background() diff --git a/plugins/common/functions b/plugins/common/functions index c295ecdf1..358f8af23 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -944,7 +944,7 @@ acquire_app_deploy_lock() { declare desc="acquire advisory lock for use in deploys" local APP="$1" local LOCK_TYPE="${2:-waiting}" - local APP_DEPLOY_LOCK_FILE="$DOKKU_ROOT/$APP/.deploy.lock" + local APP_DEPLOY_LOCK_FILE="$DOKKU_LIB_ROOT/data/apps/$APP/.deploy.lock" local LOCK_WAITING_MSG="$APP currently has a deploy lock in place. Waiting..." local LOCK_FAILED_MSG="$APP currently has a deploy lock in place. Exiting..." @@ -954,7 +954,7 @@ acquire_app_deploy_lock() { release_app_deploy_lock() { declare desc="release advisory lock used in deploys" local APP="$1" - local APP_DEPLOY_LOCK_FILE="$DOKKU_ROOT/$APP/.deploy.lock" + local APP_DEPLOY_LOCK_FILE="$DOKKU_LIB_ROOT/data/apps/$APP/.deploy.lock" release_advisory_lock "$APP_DEPLOY_LOCK_FILE" } @@ -983,6 +983,7 @@ acquire_advisory_lock() { dokku_log_fail "Run 'apps:unlock' to release the existing deploy lock" fi fi + echo "$DOKKU_PID" >"$LOCK_FILE" } release_advisory_lock() { @@ -997,13 +998,14 @@ suppress_output() { declare desc="suppress all output from a given command unless there is an error" local TMP_COMMAND_OUTPUT TMP_COMMAND_OUTPUT=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") - trap "rm -rf '$TMP_COMMAND_OUTPUT' >/dev/null" RETURN "$@" >"$TMP_COMMAND_OUTPUT" 2>&1 || { local exit_code="$?" cat "$TMP_COMMAND_OUTPUT" + rm -rf "$TMP_COMMAND_OUTPUT" >/dev/null return "$exit_code" } + rm -rf "$TMP_COMMAND_OUTPUT" >/dev/null return 0 } diff --git a/plugins/common/functions.go b/plugins/common/functions.go index 185ddd9f5..0ae83bb9e 100644 --- a/plugins/common/functions.go +++ b/plugins/common/functions.go @@ -25,8 +25,11 @@ func filterApps(apps []string) ([]string, error) { } args := append([]string{sshUser, sshName}, apps...) - b, _ := PlugnTriggerOutput("user-auth-app", args...) - filteredApps := strings.Split(strings.TrimSpace(string(b[:])), "\n") + results, _ := CallPlugnTrigger(PlugnTriggerInput{ + Trigger: "user-auth-app", + Args: args, + }) + filteredApps := strings.Split(results.StdoutContents(), "\n") filteredApps = removeEmptyEntries(filteredApps) if len(filteredApps) == 0 { diff --git a/plugins/common/go.mod b/plugins/common/go.mod index 9d229cd93..5cb66aab9 100644 --- a/plugins/common/go.mod +++ b/plugins/common/go.mod @@ -4,7 +4,6 @@ go 1.21 require ( github.com/alexellis/go-execute/v2 v2.2.1 - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 github.com/fatih/color v1.16.0 github.com/hashicorp/go-multierror v1.1.1 github.com/melbahja/goph v1.4.0 @@ -17,7 +16,6 @@ require ( ) require ( - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/kr/fs v0.1.0 // indirect diff --git a/plugins/common/go.sum b/plugins/common/go.sum index ea3cd3d81..50c6f3e18 100644 --- a/plugins/common/go.sum +++ b/plugins/common/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/common/subprocess.go b/plugins/common/subprocess.go index 8a6187fb9..d47f320e3 100644 --- a/plugins/common/subprocess.go +++ b/plugins/common/subprocess.go @@ -1,158 +1,10 @@ package common import ( - "fmt" - "io" - "os" - "os/exec" "path/filepath" "strings" - - "github.com/codeskyblue/go-sh" ) -// ShellCmd represents a shell command to be run for dokku -type ShellCmd struct { - Env map[string]string - Command *exec.Cmd - CommandString string - Args []string - ShowOutput bool - ExitError *exec.ExitError -} - -// NewShellCmd returns a new ShellCmd struct -// -// Deprecated: use CallExecCommand instead -func NewShellCmd(command string) *ShellCmd { - items := strings.Split(command, " ") - cmd := items[0] - args := items[1:] - return NewShellCmdWithArgs(cmd, args...) -} - -// NewShellCmdWithArgs returns a new ShellCmd struct -// -// Deprecated: use CallExecCommand instead -func NewShellCmdWithArgs(cmd string, args ...string) *ShellCmd { - commandString := strings.Join(append([]string{cmd}, args...), " ") - - return &ShellCmd{ - Command: exec.Command(cmd, args...), - CommandString: commandString, - Args: args, - ShowOutput: true, - } -} - -func (sc *ShellCmd) setup() { - env := os.Environ() - for k, v := range sc.Env { - env = append(env, fmt.Sprintf("%s=%s", k, v)) - } - sc.Command.Env = env - if sc.ShowOutput { - sc.Command.Stdout = os.Stdout - sc.Command.Stderr = os.Stderr - } -} - -// Execute is a lightweight wrapper around exec.Command -func (sc *ShellCmd) Execute() bool { - sc.setup() - - if err := sc.Command.Run(); err != nil { - exitError, ok := err.(*exec.ExitError) - if ok { - sc.ExitError = exitError - } - return false - } - return true -} - -// Start is a wrapper around exec.Command.Start() -func (sc *ShellCmd) Start() error { - sc.setup() - - return sc.Command.Start() -} - -// Output is a lightweight wrapper around exec.Command.Output() -func (sc *ShellCmd) Output() ([]byte, error) { - sc.setup() - return sc.Command.Output() -} - -// CombinedOutput is a lightweight wrapper around exec.Command.CombinedOutput() -func (sc *ShellCmd) CombinedOutput() ([]byte, error) { - sc.setup() - return sc.Command.CombinedOutput() -} - -// PlugnTrigger fire the given plugn trigger with the given args -// -// Deprecated: use CallPlugnTrigger instead -func PlugnTrigger(triggerName string, args ...string) error { - LogDebug(fmt.Sprintf("plugn trigger %s %v", triggerName, args)) - return PlugnTriggerSetup(triggerName, args...).Run() -} - -// PlugnTriggerOutput fire the given plugn trigger with the given args -// -// Deprecated: use CallPlugnTrigger with CaptureOutput=true instead -func PlugnTriggerOutput(triggerName string, args ...string) ([]byte, error) { - LogDebug(fmt.Sprintf("plugn trigger %s %v", triggerName, args)) - rE, wE, _ := os.Pipe() - rO, wO, _ := os.Pipe() - session := PlugnTriggerSetup(triggerName, args...) - session.Stderr = wE - session.Stdout = wO - err := session.Run() - wE.Close() - wO.Close() - - readStderr, _ := io.ReadAll(rE) - readStdout, _ := io.ReadAll(rO) - - stderr := string(readStderr[:]) - if err != nil { - err = fmt.Errorf(stderr) - } - - if os.Getenv("DOKKU_TRACE") == "1" { - for _, line := range strings.Split(stderr, "\n") { - LogDebug(fmt.Sprintf("plugn trigger %s stderr: %s", triggerName, line)) - } - for _, line := range strings.Split(string(readStdout[:]), "\n") { - LogDebug(fmt.Sprintf("plugn trigger %s stdout: %s", triggerName, line)) - } - } - - return readStdout, err -} - -// PlugnTriggerOutputAsString fires the given plugn trigger with the given args and returns the string contents instead of bytes -// -// Deprecated: use CallPlugnTrigger with CaptureOutput=true instead -func PlugnTriggerOutputAsString(triggerName string, args ...string) (string, error) { - b, err := PlugnTriggerOutput(triggerName, args...) - return strings.TrimSpace(string(b[:])), err -} - -// PlugnTriggerSetup sets up a plugn trigger call -// -// Deprecated: use CallPlugnTrigger instead -func PlugnTriggerSetup(triggerName string, args ...string) *sh.Session { - shellArgs := make([]interface{}, len(args)+2) - shellArgs[0] = "trigger" - shellArgs[1] = triggerName - for i, arg := range args { - shellArgs[i+2] = arg - } - return sh.Command("plugn", shellArgs...) -} - // PlugnTriggerExists returns whether a plugin trigger exists (ignoring the existence of any within the 20_events plugin) func PlugnTriggerExists(triggerName string) bool { pluginPath := MustGetEnv("PLUGIN_PATH") diff --git a/plugins/config/.gitignore b/plugins/config/.gitignore index b79352e77..3b7e2f512 100644 --- a/plugins/config/.gitignore +++ b/plugins/config/.gitignore @@ -4,3 +4,4 @@ /triggers /config-* /config_sub +/post-* diff --git a/plugins/config/Makefile b/plugins/config/Makefile index e38a8f62d..86ffcb36b 100644 --- a/plugins/config/Makefile +++ b/plugins/config/Makefile @@ -1,6 +1,6 @@ GOARCH ?= amd64 SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset -TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global +TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/post-app-clone-setup triggers/post-app-rename-setup BUILD = commands config_sub subcommands triggers PLUGIN_NAME = config diff --git a/plugins/config/config.go b/plugins/config/config.go index 3bfbf59d6..90f04039d 100644 --- a/plugins/config/config.go +++ b/plugins/config/config.go @@ -129,14 +129,24 @@ func UnsetAll(appName string, restart bool) (err error) { func triggerRestart(appName string) { common.LogInfo1(fmt.Sprintf("Restarting app %s", appName)) - if err := common.PlugnTrigger("release-and-deploy", appName); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "release-and-deploy", + Args: []string{appName}, + StreamStdio: true, + }) + if err != nil { common.LogWarn(fmt.Sprintf("Failure while restarting app: %s", err)) } } func triggerUpdate(appName string, operation string, args []string) { args = append([]string{appName, operation}, args...) - if err := common.PlugnTrigger("post-config-update", args...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-config-update", + Args: args, + StreamStdio: true, + }) + if err != nil { common.LogWarn(fmt.Sprintf("Failure while triggering post-config-update: %s", err)) } } diff --git a/plugins/config/environment.go b/plugins/config/environment.go index 2f6ddf071..877939e5f 100644 --- a/plugins/config/environment.go +++ b/plugins/config/environment.go @@ -16,7 +16,7 @@ import ( "github.com/ryanuber/columnize" ) -//ExportFormat types of possible exports +// ExportFormat types of possible exports type ExportFormat int const ( @@ -40,14 +40,14 @@ const ( ExportFormatPackArgKeys ) -//Env is a representation for global or app environment +// Env is a representation for global or app environment type Env struct { name string filename string env map[string]string } -//newEnvFromString creates an env from the given ENVFILE contents representation +// newEnvFromString creates an env from the given ENVFILE contents representation func newEnvFromString(rep string) (env *Env, err error) { envMap, err := godotenv.Unmarshal(rep) env = &Env{ @@ -58,7 +58,7 @@ func newEnvFromString(rep string) (env *Env, err error) { return } -//LoadAppEnv loads an environment for the given app +// LoadAppEnv loads an environment for the given app func LoadAppEnv(appName string) (env *Env, err error) { appfile, err := getAppFile(appName) if err != nil { @@ -67,7 +67,7 @@ func LoadAppEnv(appName string) (env *Env, err error) { return loadFromFile(appName, appfile) } -//LoadMergedAppEnv loads an app environment merged with the global environment +// LoadMergedAppEnv loads an app environment merged with the global environment func LoadMergedAppEnv(appName string) (env *Env, err error) { env, err = LoadAppEnv(appName) if err != nil { @@ -83,7 +83,7 @@ func LoadMergedAppEnv(appName string) (env *Env, err error) { return global, err } -//LoadGlobalEnv loads the global environment +// LoadGlobalEnv loads the global environment func LoadGlobalEnv() (*Env, error) { return loadFromFile("", getGlobalFile()) } @@ -93,13 +93,13 @@ func (e *Env) Filename() string { return e.filename } -//Get an environment variable +// Get an environment variable func (e *Env) Get(key string) (value string, ok bool) { value, ok = e.env[key] return } -//GetDefault an environment variable or a default if it doesn't exist +// GetDefault an environment variable or a default if it doesn't exist func (e *Env) GetDefault(key string, defaultValue string) string { v, ok := e.env[key] if !ok { @@ -108,8 +108,8 @@ func (e *Env) GetDefault(key string, defaultValue string) string { return v } -//GetBoolDefault gets the bool value of the given key with the given default -//right now that is evaluated as `value != "0"` +// GetBoolDefault gets the bool value of the given key with the given default +// right now that is evaluated as `value != "0"` func (e *Env) GetBoolDefault(key string, defaultValue bool) bool { v, ok := e.Get(key) if !ok { @@ -118,17 +118,17 @@ func (e *Env) GetBoolDefault(key string, defaultValue bool) bool { return v != "0" } -//Set an environment variable +// Set an environment variable func (e *Env) Set(key string, value string) { e.env[key] = value } -//Unset an environment variable +// Unset an environment variable func (e *Env) Unset(key string) { delete(e.env, key) } -//Keys gets the keys in this environment +// Keys gets the keys in this environment func (e *Env) Keys() (keys []string) { keys = make([]string, 0, len(e.env)) for k := range e.env { @@ -138,12 +138,12 @@ func (e *Env) Keys() (keys []string) { return } -//Len returns the number of items in this environment +// Len returns the number of items in this environment func (e *Env) Len() int { return len(e.env) } -//Map returns the Env as a map +// Map returns the Env as a map func (e *Env) Map() map[string]string { return e.env } @@ -152,14 +152,14 @@ func (e *Env) String() string { return e.EnvfileString() } -//Merge merges the given environment on top of the receiver +// Merge merges the given environment on top of the receiver func (e *Env) Merge(other *Env) { for _, k := range other.Keys() { e.Set(k, other.GetDefault(k, "")) } } -//Write an Env back to the file it was read from as an exportfile +// Write an Env back to the file it was read from as an exportfile func (e *Env) Write() error { if e.filename == "" { return errors.New("this Env was created unbound to a file") @@ -167,7 +167,7 @@ func (e *Env) Write() error { return godotenv.Write(e.Map(), e.filename) } -//Export the Env in the given format +// Export the Env in the given format func (e *Env) Export(format ExportFormat) string { switch format { case ExportFormatExports: @@ -194,23 +194,23 @@ func (e *Env) Export(format ExportFormat) string { } } -//EnvfileString returns the contents of this Env in dotenv format +// EnvfileString returns the contents of this Env in dotenv format func (e *Env) EnvfileString() string { rep, _ := godotenv.Marshal(e.Map()) return rep } -//ExportfileString returns the contents of this Env as bash exports +// ExportfileString returns the contents of this Env as bash exports func (e *Env) ExportfileString() string { return e.stringWithPrefixAndSeparator("export ", "\n") } -//DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env... +// DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env... func (e *Env) DockerArgsString() string { return e.stringWithPrefixAndSeparator("--env=", " ") } -//DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env... +// DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env... func (e *Env) DockerArgsKeysString() string { keys := e.Keys() entries := make([]string, len(keys)) @@ -220,7 +220,7 @@ func (e *Env) DockerArgsKeysString() string { return strings.Join(entries, " ") } -//JSONString returns the contents of this Env as a key/value json object +// JSONString returns the contents of this Env as a key/value json object func (e *Env) JSONString() string { data, err := json.Marshal(e.Map()) if err != nil { @@ -230,7 +230,7 @@ func (e *Env) JSONString() string { return string(data) } -//JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var +// JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var func (e *Env) JSONListString() string { var list []map[string]string for _, key := range e.Keys() { @@ -249,7 +249,7 @@ func (e *Env) JSONListString() string { return string(data) } -//PackArgKeysAsString gets the contents of this Env in the form -env KEY --env... +// PackArgKeysAsString gets the contents of this Env in the form -env KEY --env... func (e *Env) PackArgKeysAsString() string { keys := e.Keys() entries := make([]string, len(keys)) @@ -259,13 +259,13 @@ func (e *Env) PackArgKeysAsString() string { return strings.Join(entries, " ") } -//ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'" +// ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'" // for passing the environment in the shell func (e *Env) ShellString() string { return e.stringWithPrefixAndSeparator("", " ") } -//ExportBundle writes a tarfile of the environment to the given io.Writer. +// ExportBundle writes a tarfile of the environment to the given io.Writer. // for every environment variable there is a file with the variable's key // with its content set to the variable's value func (e *Env) ExportBundle(dest io.Writer) error { @@ -287,7 +287,7 @@ func (e *Env) ExportBundle(dest io.Writer) error { return nil } -//stringWithPrefixAndSeparator makes a string of the environment +// stringWithPrefixAndSeparator makes a string of the environment // with the given prefix and separator for each entry func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) string { keys := e.Keys() @@ -299,12 +299,12 @@ func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) stri return strings.Join(entries, separator) } -//singleQuoteEscape escapes the value as if it were shell-quoted in single quotes +// singleQuoteEscape escapes the value as if it were shell-quoted in single quotes func singleQuoteEscape(value string) string { // so that 'esc'aped' -> 'esc'\''aped' return strings.Replace(value, "'", "'\\''", -1) } -//prettyPrintEnvEntries in columns +// prettyPrintEnvEntries in columns func prettyPrintEnvEntries(prefix string, entries map[string]string) string { colConfig := columnize.DefaultConfig() colConfig.Prefix = prefix diff --git a/plugins/config/go.mod b/plugins/config/go.mod index f024bb7eb..ebafb4695 100644 --- a/plugins/config/go.mod +++ b/plugins/config/go.mod @@ -12,8 +12,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect diff --git a/plugins/config/go.sum b/plugins/config/go.sum index 76515bbb1..60dc76b24 100644 --- a/plugins/config/go.sum +++ b/plugins/config/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/config/src/triggers/triggers.go b/plugins/config/src/triggers/triggers.go index eec123a48..1f8f58732 100644 --- a/plugins/config/src/triggers/triggers.go +++ b/plugins/config/src/triggers/triggers.go @@ -36,6 +36,14 @@ func main() { case "config-get-global": key := flag.Arg(0) err = config.TriggerConfigGetGlobal(key) + case "post-app-clone-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = config.TriggerPostAppCloneSetup(oldAppName, newAppName) + case "post-app-rename-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = config.TriggerPostAppRenameSetup(oldAppName, newAppName) default: err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) } diff --git a/plugins/config/triggers.go b/plugins/config/triggers.go index 3014f6d26..af96d114c 100644 --- a/plugins/config/triggers.go +++ b/plugins/config/triggers.go @@ -44,3 +44,43 @@ func TriggerConfigGetGlobal(key string) error { return nil } + +// TriggerPostAppCloneSetup creates new buildpacks files +func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { + oldEnv, err := LoadAppEnv(oldAppName) + if err != nil { + return fmt.Errorf("Unable to load old environment: %s", err.Error()) + } + + newEnv, err := LoadAppEnv(newAppName) + if err != nil { + return fmt.Errorf("Unable to load new environment: %s", err.Error()) + } + + newEnv.Merge(oldEnv) + if err := newEnv.Write(); err != nil { + return fmt.Errorf("Unable to write new environment: %s", err.Error()) + } + + return nil +} + +// TriggerPostAppRenameSetup renames buildpacks files +func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { + oldEnv, err := LoadAppEnv(oldAppName) + if err != nil { + return fmt.Errorf("Unable to load old environment: %s", err.Error()) + } + + newEnv, err := LoadAppEnv(newAppName) + if err != nil { + return fmt.Errorf("Unable to load new environment: %s", err.Error()) + } + + newEnv.Merge(oldEnv) + if err := newEnv.Write(); err != nil { + return fmt.Errorf("Unable to write new environment: %s", err.Error()) + } + + return nil +} diff --git a/plugins/cron/go.mod b/plugins/cron/go.mod index 7fab44cd3..37acb73ba 100644 --- a/plugins/cron/go.mod +++ b/plugins/cron/go.mod @@ -14,8 +14,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/cron/go.sum b/plugins/cron/go.sum index 3dad92380..1d1317b5f 100644 --- a/plugins/cron/go.sum +++ b/plugins/cron/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/plugins/cron/src/triggers/triggers.go b/plugins/cron/src/triggers/triggers.go index 063d35425..083cbb25b 100644 --- a/plugins/cron/src/triggers/triggers.go +++ b/plugins/cron/src/triggers/triggers.go @@ -14,6 +14,7 @@ import ( func main() { parts := strings.Split(os.Args[0], "/") trigger := parts[len(parts)-1] + global := flag.Bool("global", false, "--global: Whether global or app-specific") flag.Parse() var err error @@ -21,6 +22,10 @@ func main() { case "cron-get-property": appName := flag.Arg(0) property := flag.Arg(1) + if *global { + appName = "--global" + property = flag.Arg(0) + } err = cron.TriggerCronGetProperty(appName, property) case "install": err = cron.TriggerInstall() diff --git a/plugins/cron/subcommands.go b/plugins/cron/subcommands.go index 4a85a01e3..981f1deab 100644 --- a/plugins/cron/subcommands.go +++ b/plugins/cron/subcommands.go @@ -110,7 +110,12 @@ func CommandRun(appName string, cronID string, detached bool) error { os.Setenv("DOKKU_RM_CONTAINER", "1") scheduler := common.GetAppScheduler(appName) args := append([]string{scheduler, appName, "0", "--"}, fields...) - return common.PlugnTrigger("scheduler-run", args...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-run", + Args: args, + StreamStdio: true, + }) + return err } // CommandSet set or clear a cron property for an app @@ -120,5 +125,9 @@ func CommandSet(appName string, property string, value string) error { } common.CommandPropertySet("cron", appName, property, value, DefaultProperties, GlobalProperties) - return common.PlugnTrigger("cron-write") + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "cron-write", + StreamStdio: true, + }) + return err } diff --git a/plugins/docker-options/go.mod b/plugins/docker-options/go.mod index 6bd85a923..7b3e42735 100644 --- a/plugins/docker-options/go.mod +++ b/plugins/docker-options/go.mod @@ -6,8 +6,6 @@ require github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000 require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/docker-options/go.sum b/plugins/docker-options/go.sum index d37bea445..6b2aed785 100644 --- a/plugins/docker-options/go.sum +++ b/plugins/docker-options/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/docker-options/post-app-clone-setup b/plugins/docker-options/post-app-clone-setup new file mode 100755 index 000000000..9b36b329d --- /dev/null +++ b/plugins/docker-options/post-app-clone-setup @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/docker-options/functions" + +trigger-docker-options-post-app-clone-setup() { + declare desc="copies docker options over" + declare trigger="post-app-clone-setup" + declare OLD_APP="$1" NEW_APP="$2" + + declare -a phases + phases=("build" "deploy" "run") + for phase in "${phases[@]}"; do + if [[ -f "$(fn-get-phase-file-path "$OLD_APP" "$phase")" ]]; then + cp "$(fn-get-phase-file-path "$OLD_APP" "$phase")" "$(fn-get-phase-file-path "$NEW_APP" "$phase")" + fi + done +} + +trigger-docker-options-post-app-clone-setup "$@" diff --git a/plugins/docker-options/post-app-rename-setup b/plugins/docker-options/post-app-rename-setup new file mode 100755 index 000000000..0688252a6 --- /dev/null +++ b/plugins/docker-options/post-app-rename-setup @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/docker-options/functions" + +trigger-docker-options-post-app-rename-setup() { + declare desc="copies docker options over" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + + declare -a phases + phases=("build" "deploy" "run") + for phase in "${phases[@]}"; do + if [[ -f "$(fn-get-phase-file-path "$OLD_APP" "$phase")" ]]; then + cp "$(fn-get-phase-file-path "$OLD_APP" "$phase")" "$(fn-get-phase-file-path "$NEW_APP" "$phase")" + fi + done +} + +trigger-docker-options-post-app-rename-setup "$@" diff --git a/plugins/domains/post-app-rename-setup b/plugins/domains/post-app-rename-setup index 7cbce6a11..3ec256a9c 100755 --- a/plugins/domains/post-app-rename-setup +++ b/plugins/domains/post-app-rename-setup @@ -7,9 +7,9 @@ trigger-domains-post-app-rename-setup() { declare trigger="post-app-rename-setup" declare OLD_APP="$1" NEW_APP="$2" - if [[ -f "$DOKKU_ROOT/$NEW_APP/VHOST" ]]; then + if [[ -f "$DOKKU_ROOT/$OLD_APP/VHOST" ]]; then while read -r VHOST || [[ -n "$VHOST" ]]; do - sed -i -e "s/$OLD_APP.$VHOST/$NEW_APP.$VHOST/g" "$DOKKU_ROOT/$NEW_APP/VHOST" + sed -e "s/$OLD_APP.$VHOST/$NEW_APP.$VHOST/g" "$DOKKU_ROOT/$OLD_APP/VHOST" >"$DOKKU_ROOT/$NEW_APP/VHOST" done <"$DOKKU_ROOT/VHOST" fi } diff --git a/plugins/git/git-from-directory b/plugins/git/git-from-directory index 03e7058de..771a7bba9 100755 --- a/plugins/git/git-from-directory +++ b/plugins/git/git-from-directory @@ -17,10 +17,9 @@ trigger-git-git-from-directory() { local TMP_WORK_DIR_2=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_WORK_DIR' '$TMP_WORK_DIR_2' >/dev/null" RETURN INT TERM EXIT - local has_code=true - local git_objects="$(fn-git-cmd "$APP_ROOT" count-objects 2>/dev/null || true)" - if [[ -z "$git_objects" ]] || [[ "$git_objects" == "0 objects, 0 kilobytes" ]]; then - local has_code=false + local has_code=false + if fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" >/dev/null 2>&1; then + has_code=true fi dokku_log_info1 "Updating git repository with specified build context" diff --git a/plugins/git/help-functions b/plugins/git/help-functions index 49b34ad41..c0fd67da8 100755 --- a/plugins/git/help-functions +++ b/plugins/git/help-functions @@ -38,7 +38,6 @@ fn-help-content() { git:public-key, Outputs the dokku public deploy key git:report [] [], Displays a git report for one or more apps git:set (), Set or clear a git property for an app - git:unlock [--force], Removes previous git clone folder for new deployment git:status , show the working tree status for an app help_content } diff --git a/plugins/git/internal-functions b/plugins/git/internal-functions index a38a41f53..f5fb38507 100755 --- a/plugins/git/internal-functions +++ b/plugins/git/internal-functions @@ -179,6 +179,7 @@ cmd-git-sync() { local cmd="git:sync" [[ "$1" == "$cmd" ]] && shift 1 declare APP GIT_REMOTE GIT_REF FLAG + local CURRENT_REF DOKKU_DEPLOY_BRANCH SHOULD_BUILD UPDATED_REF ARGS=() for arg in "$@"; do @@ -187,6 +188,11 @@ cmd-git-sync() { continue fi + if [[ "$arg" == "--build-if-changes" ]]; then + FLAG="--build-if-changes" + continue + fi + ARGS+=("$arg") done @@ -196,32 +202,37 @@ cmd-git-sync() { verify_app_name "$APP" - if [[ -d "$DOKKU_LIB_ROOT/data/git/$APP" ]]; then - if has_tty eq 0; then - cmd-git-unlock "$APP" - if [[ -d "$DOKKU_LIB_ROOT/data/git/$APP" ]]; then - dokku_log_fail "Failed to delete existing clone folder" - exit 15 - fi - else - dokku_log_fail "Run 'git:unlock' to remove the existing temporary clone" - fi - fi - if [[ -z "$GIT_REMOTE" ]]; then dokku_log_fail "Missing GIT_REMOTE parameter" return fi local APP_ROOT="$DOKKU_ROOT/$APP" - if [[ "$(fn-git-cmd "$APP_ROOT" count-objects)" == "0 objects, 0 kilobytes" ]]; then + DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")" + CURRENT_REF="$(fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true)" + + if ! fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" >/dev/null 2>&1; then dokku_log_info1_quiet "Cloning $APP from $GIT_REMOTE#$GIT_REF" fn-git-clone "$APP" "$GIT_REMOTE" "$GIT_REF" else + dokku_log_verbose "Fetching remote code for $APP from $GIT_REMOTE#$GIT_REF" fn-git-fetch "$APP" "$GIT_REMOTE" "$GIT_REF" fi + UPDATED_REF="$(fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true)" + local SHOULD_BUILD=false if [[ "$FLAG" == "--build" ]]; then + SHOULD_BUILD=true + elif [[ "$FLAG" == "--build-if-changes" ]]; then + if [[ "$CURRENT_REF" == "$UPDATED_REF" ]]; then + dokku_log_verbose "Skipping build as no changes were detected" + return + fi + + SHOULD_BUILD=true + fi + + if [[ "$SHOULD_BUILD" == "true" ]]; then if [[ -n "$GIT_REF" ]]; then GIT_REF="$(fn-git-cmd "$APP_ROOT" rev-parse "$GIT_REF")" plugn trigger receive-app "$APP" "$GIT_REF" @@ -232,40 +243,6 @@ cmd-git-sync() { fi } -cmd-git-unlock() { - declare desc="removes the clone folder for an app" - local cmd="git:unlock" - [[ "$1" == "$cmd" ]] && shift 1 - declare APP="$1" FLAG - - for arg in "$@"; do - if [[ "$arg" == "--force" ]]; then - FLAG="--force" - continue - fi - - ARGS+=("$arg") - done - - local APP_CLONE_ROOT="$DOKKU_LIB_ROOT/data/git/$APP" - - if [[ -d "$APP_CLONE_ROOT" ]]; then - if [[ "$FLAG" == "--force" ]]; then - fn-git-remove-clone-folder "$APP_CLONE_ROOT" - else - read -rp "Are you sure that want to delete clone folder (y/n)?" choice - case "$choice" in - y | Y) - fn-git-remove-clone-folder "$APP_CLONE_ROOT" - ;; - n | N) echo "no" ;; - *) echo "please answer with yes or no" ;; - esac - fi - else - dokku_log_info1 "No clone folder exists app already unlocked" - fi -} cmd-git-public-key() { declare desc="outputs the dokku public deploy key" local cmd="git:public-key" @@ -396,11 +373,11 @@ EOF fn-git-clone() { declare desc="creates an app from remote git repo" declare APP="$1" GIT_REMOTE="$2" GIT_REF="$3" - local APP_CLONE_ROOT="$DOKKU_LIB_ROOT/data/git/$APP" local APP_ROOT="$DOKKU_ROOT/$APP" [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on" - if [[ "$(fn-git-cmd "$APP_ROOT" count-objects)" != "0 objects, 0 kilobytes" ]]; then + local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")" + if fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" >/dev/null 2>&1; then dokku_log_fail "The clone subcommand can only be executed for new applications" fi @@ -408,20 +385,24 @@ fn-git-clone() { GIT_REF="$(fn-git-deploy-branch "$APP")" fi - trap "rm -rf '$APP_CLONE_ROOT' > /dev/null" RETURN INT TERM EXIT + local TMP_IS_REF_DIR=$(mktemp -d "/tmp/dokku-ref-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") + trap "rm -rf '$TMP_IS_REF_DIR' >/dev/null" RETURN INT TERM EXIT is_ref=true - if GIT_TERMINAL_PROMPT=0 git clone --depth 1 -n --branch "$GIT_REF" "$GIT_REMOTE" "$APP_CLONE_ROOT" 2>/dev/null; then + if GIT_TERMINAL_PROMPT=0 git clone --depth 1 -n --branch "$GIT_REF" "$GIT_REMOTE" "$TMP_IS_REF_DIR" 2>/dev/null; then is_ref=false fi - rm -rf "$APP_CLONE_ROOT" + rm -rf "$TMP_IS_REF_DIR" + + local TMP_CLONE_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") + trap "rm -rf '$TMP_CLONE_DIR' >/dev/null" RETURN INT TERM EXIT if [[ "$is_ref" == "true" ]]; then - GIT_TERMINAL_PROMPT=0 suppress_output git clone -n "$GIT_REMOTE" "$APP_CLONE_ROOT" - fn-git-cmd "$APP_CLONE_ROOT" checkout -qq "$GIT_REF" + GIT_TERMINAL_PROMPT=0 suppress_output git clone -n "$GIT_REMOTE" "$TMP_CLONE_DIR" + fn-git-cmd "$TMP_CLONE_DIR" checkout -qq "$GIT_REF" else - GIT_TERMINAL_PROMPT=0 suppress_output git clone -n --branch "$GIT_REF" "$GIT_REMOTE" "$APP_CLONE_ROOT" - if fn-git-cmd "$APP_CLONE_ROOT" show-ref --verify "refs/heads/$GIT_REF" &>/dev/null; then + GIT_TERMINAL_PROMPT=0 suppress_output git clone -n --branch "$GIT_REF" "$GIT_REMOTE" "$TMP_CLONE_DIR" + if fn-git-cmd "$TMP_CLONE_DIR" show-ref --verify "refs/heads/$GIT_REF" &>/dev/null; then dokku_log_verbose "Detected branch, setting deploy-branch to $GIT_REF" fn-plugin-property-write "git" "$APP" "deploy-branch" "$GIT_REF" fi @@ -430,13 +411,13 @@ fn-git-clone() { DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")" if [[ "$GIT_REF" != "$DOKKU_DEPLOY_BRANCH" ]]; then if [[ "$is_ref" == "true" ]]; then - fn-git-cmd "$APP_CLONE_ROOT" branch -qq -D "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true + fn-git-cmd "$TMP_CLONE_DIR" branch -qq -D "$DOKKU_DEPLOY_BRANCH" 2>/dev/null || true fi - fn-git-cmd "$APP_CLONE_ROOT" checkout -qq -b "$DOKKU_DEPLOY_BRANCH" + fn-git-cmd "$TMP_CLONE_DIR" checkout -qq -b "$DOKKU_DEPLOY_BRANCH" fi - rsync -a "$APP_CLONE_ROOT/.git/" "$APP_ROOT" + rsync -a "$TMP_CLONE_DIR/.git/" "$APP_ROOT" fn-git-create-hook "$APP" fn-git-cmd "$APP_ROOT" config --add core.bare true } @@ -458,7 +439,8 @@ fn-git-fetch() { local DOKKU_DEPLOY_BRANCH local APP_ROOT="$DOKKU_ROOT/$APP" - if [[ "$(fn-git-cmd "$APP_ROOT" count-objects)" == "0 objects, 0 kilobytes" ]]; then + local DOKKU_DEPLOY_BRANCH="$(fn-git-deploy-branch "$APP")" + if ! fn-git-cmd "$APP_ROOT" rev-parse "$DOKKU_DEPLOY_BRANCH" >/dev/null 2>&1; then dokku_log_fail "The fetch subcommand can only be executed for existing applications" fi diff --git a/plugins/git/post-delete b/plugins/git/post-delete index dad74439a..490782dd8 100755 --- a/plugins/git/post-delete +++ b/plugins/git/post-delete @@ -7,8 +7,10 @@ trigger-git-post-delete() { declare desc="destroys the git properties for a given app" declare trigger="post-delete" declare APP="$1" + local APP_CLONE_ROOT="$DOKKU_LIB_ROOT/data/git/$APP" fn-plugin-property-destroy "git" "$APP" + rm -rf "$APP_CLONE_ROOT" } trigger-git-post-delete "$@" diff --git a/plugins/logs/go.mod b/plugins/logs/go.mod index 2b7a13f1c..f0cee1bf4 100644 --- a/plugins/logs/go.mod +++ b/plugins/logs/go.mod @@ -11,8 +11,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/logs/go.sum b/plugins/logs/go.sum index 418e80d53..de72fbf95 100644 --- a/plugins/logs/go.sum +++ b/plugins/logs/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/logs/logs.go b/plugins/logs/logs.go index d0122957e..6d24d8755 100644 --- a/plugins/logs/logs.go +++ b/plugins/logs/logs.go @@ -40,9 +40,11 @@ var templates embed.FS // GetFailedLogs outputs failed deploy logs for a given app func GetFailedLogs(appName string) error { common.LogInfo2Quiet(fmt.Sprintf("%s failed deploy logs", appName)) - s := common.GetAppScheduler(appName) - if err := common.PlugnTrigger("scheduler-logs-failed", s, appName); err != nil { - return err - } - return nil + scheduler := common.GetAppScheduler(appName) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-logs-failed", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + return err } diff --git a/plugins/logs/triggers.go b/plugins/logs/triggers.go index c0d35ea8a..87962efb3 100644 --- a/plugins/logs/triggers.go +++ b/plugins/logs/triggers.go @@ -134,7 +134,7 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { return common.CloneAppData("logs", oldAppName, newAppName) } -// TriggerPostCreate ensures apps the correct data directory structure +// TriggerPostCreate ensures apps have the correct data directory structure func TriggerPostCreate(appName string) error { return common.CreateAppDataDirectory("logs", appName) } diff --git a/plugins/network/go.mod b/plugins/network/go.mod index 6c4f630e5..438ca7390 100644 --- a/plugins/network/go.mod +++ b/plugins/network/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/network/go.sum b/plugins/network/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/network/go.sum +++ b/plugins/network/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/network/network.go b/plugins/network/network.go index f8bf2d1dc..4c0254e61 100644 --- a/plugins/network/network.go +++ b/plugins/network/network.go @@ -43,12 +43,15 @@ func BuildConfig(appName string) error { } appRoot := common.AppRoot(appName) - s, err := common.PlugnTriggerOutput("ps-current-scale", []string{appName}...) + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "ps-current-scale", + Args: []string{appName}, + }) if err != nil { return err } - scale, err := common.ParseScaleOutput(s) + scale, err := common.ParseScaleOutput(results.StdoutBytes()) if err != nil { return err } @@ -78,7 +81,10 @@ func BuildConfig(appName string) error { ipAddress := GetContainerIpaddress(appName, processType, containerID) if ipAddress != "" { args := []string{appName, processType, containerIndexString, ipAddress} - _, err := common.PlugnTriggerOutput("network-write-ipaddr", args...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "network-write-ipaddr", + Args: args, + }) if err != nil { common.LogWarn(err.Error()) } diff --git a/plugins/network/triggers.go b/plugins/network/triggers.go index 3f5bd99ff..6ad20bd0c 100644 --- a/plugins/network/triggers.go +++ b/plugins/network/triggers.go @@ -40,7 +40,12 @@ func TriggerInstall() error { if common.PropertyExists("network", appName, "bind-all-interfaces") { continue } - if err := common.PlugnTrigger("proxy-is-enabled", []string{appName}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-is-enabled", + Args: []string{appName}, + StreamStdio: true, + }) + if err != nil { common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to false") if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false"); err != nil { common.LogWarn(err.Error()) diff --git a/plugins/nginx-vhosts/.gitignore b/plugins/nginx-vhosts/.gitignore index f0565e7af..ee69b9339 100644 --- a/plugins/nginx-vhosts/.gitignore +++ b/plugins/nginx-vhosts/.gitignore @@ -1 +1,2 @@ /pagesize +/nginx-property diff --git a/plugins/nginx-vhosts/go.mod b/plugins/nginx-vhosts/go.mod index a72c65d5a..0db352073 100644 --- a/plugins/nginx-vhosts/go.mod +++ b/plugins/nginx-vhosts/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/nginx-vhosts/go.sum b/plugins/nginx-vhosts/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/nginx-vhosts/go.sum +++ b/plugins/nginx-vhosts/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/ports/functions.go b/plugins/ports/functions.go index 938cba1de..29ca80b0d 100644 --- a/plugins/ports/functions.go +++ b/plugins/ports/functions.go @@ -33,13 +33,19 @@ func clearPorts(appName string) error { // doesCertExist checks if a cert exists for an app func doesCertExist(appName string) bool { - certsExists, _ := common.PlugnTriggerOutputAsString("certs-exists", []string{appName}...) - if certsExists == "true" { + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "certs-exists", + Args: []string{appName}, + }) + if results.StdoutContents() == "true" { return true } - certsForce, _ := common.PlugnTriggerOutputAsString("certs-force", []string{appName}...) - return certsForce == "true" + results, _ = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "certs-force", + Args: []string{appName}, + }) + return results.StdoutContents() == "true" } // filterAppPortMaps filters the port mappings for an app @@ -156,8 +162,11 @@ func getDetectedPortMaps(appName string) []PortMap { // getGlobalProxyPort gets the global proxy port func getGlobalProxyPort() int { port := 0 - b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_PROXY_PORT"}...) - if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil { + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_PROXY_PORT"}, + }) + if intVar, err := strconv.Atoi(results.StdoutContents()); err == nil { port = intVar } @@ -167,8 +176,11 @@ func getGlobalProxyPort() int { // getGlobalProxySSLPort gets the global proxy ssl port func getGlobalProxySSLPort() int { port := 0 - b, _ := common.PlugnTriggerOutput("config-get-global", []string{"DOKKU_PROXY_SSL_PORT"}...) - if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil { + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_PROXY_SSL_PORT"}, + }) + if intVar, err := strconv.Atoi(results.StdoutContents()); err == nil { port = intVar } @@ -189,8 +201,11 @@ func getPortMaps(appName string) []PortMap { // getProxyPort gets the proxy port for an app func getProxyPort(appName string) int { port := 0 - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_PROXY_PORT"}...) - if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil { + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_PROXY_PORT"}, + }) + if intVar, err := strconv.Atoi(results.StdoutContents()); err == nil { port = intVar } @@ -200,8 +215,11 @@ func getProxyPort(appName string) int { // getProxySSLPort gets the proxy ssl port for an app func getProxySSLPort(appName string) int { port := 0 - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_PROXY_SSL_PORT"}...) - if intVar, err := strconv.Atoi(strings.TrimSpace(string(b[:]))); err == nil { + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_PROXY_SSL_PORT"}, + }) + if intVar, err := strconv.Atoi(results.StdoutContents()); err == nil { port = intVar } @@ -268,10 +286,12 @@ func inRange(value int, min int, max int) bool { // isAppVhostEnabled checks if the app vhost is enabled func isAppVhostEnabled(appName string) bool { - if err := common.PlugnTrigger("domains-vhost-enabled", []string{appName}...); err != nil { - return false - } - return true + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "domains-vhost-enabled", + Args: []string{appName}, + StreamStdio: true, + }) + return err == nil } // listAppPortMaps lists the port mappings for an app diff --git a/plugins/ports/go.mod b/plugins/ports/go.mod index 6e5b795d0..6d7895562 100644 --- a/plugins/ports/go.mod +++ b/plugins/ports/go.mod @@ -11,8 +11,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/ports/go.sum b/plugins/ports/go.sum index a2e5d436b..bf77a3bf1 100644 --- a/plugins/ports/go.sum +++ b/plugins/ports/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/ports/subcommands.go b/plugins/ports/subcommands.go index 51f9564f8..6f4f3793f 100644 --- a/plugins/ports/subcommands.go +++ b/plugins/ports/subcommands.go @@ -46,7 +46,12 @@ func CommandAdd(appName string, portMapStrings []string) error { return err } - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "add"}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-proxy-ports-update", + Args: []string{appName, "add"}, + StreamStdio: true, + }) + return err } // CommandClear clears all port mappings for an app @@ -59,7 +64,12 @@ func CommandClear(appName string) error { return err } - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "clear"}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-proxy-ports-update", + Args: []string{appName, "clear"}, + StreamStdio: true, + }) + return err } // CommandRemove removes specific port mappings from an app @@ -81,7 +91,12 @@ func CommandRemove(appName string, portMapStrings []string) error { return err } - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "remove"}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-proxy-ports-update", + Args: []string{appName, "remove"}, + StreamStdio: true, + }) + return err } // CommandSet sets port mappings for an app @@ -107,7 +122,12 @@ func CommandSet(appName string, portMapStrings []string) error { return err } - return common.PlugnTrigger("post-proxy-ports-update", []string{appName, "set"}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-proxy-ports-update", + Args: []string{appName, "set"}, + StreamStdio: true, + }) + return err } // CommandReport displays a ports report for one or more apps diff --git a/plugins/proxy/go.mod b/plugins/proxy/go.mod index e44834cba..3a6fdbf10 100644 --- a/plugins/proxy/go.mod +++ b/plugins/proxy/go.mod @@ -10,8 +10,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/proxy/go.sum b/plugins/proxy/go.sum index a2e5d436b..bf77a3bf1 100644 --- a/plugins/proxy/go.sum +++ b/plugins/proxy/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/proxy/proxy.go b/plugins/proxy/proxy.go index 26cfee2ff..57a7bfba6 100644 --- a/plugins/proxy/proxy.go +++ b/plugins/proxy/proxy.go @@ -11,12 +11,22 @@ const RunInSerial = 0 // BuildConfig rebuilds the proxy config for the specified app func BuildConfig(appName string) error { - return common.PlugnTrigger("proxy-build-config", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-build-config", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // ClearConfig clears the proxy config for the specified app func ClearConfig(appName string) error { - return common.PlugnTrigger("proxy-clear-config", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-clear-config", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // Disable disables proxy implementations for the specified app @@ -35,7 +45,12 @@ func Disable(appName string) error { return err } - return common.PlugnTrigger("proxy-disable", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-disable", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // Enable enables proxy implementations for the specified app @@ -50,8 +65,12 @@ func Enable(appName string) error { if err := config.UnsetMany(appName, keys, false); err != nil { return err } - - return common.PlugnTrigger("proxy-enable", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-enable", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // IsAppProxyEnabled returns true if proxy is enabled; otherwise return false diff --git a/plugins/ps/functions.go b/plugins/ps/functions.go index c77475c0f..3bb7f1235 100644 --- a/plugins/ps/functions.go +++ b/plugins/ps/functions.go @@ -69,15 +69,21 @@ func getRestartPolicy(appName string) (string, error) { func getProcessCount(appName string) (int, error) { scheduler := common.GetAppScheduler(appName) - b, _ := common.PlugnTriggerOutput("scheduler-app-status", []string{scheduler, appName}...) - count := strings.Split(strings.TrimSpace(string(b[:])), " ")[0] + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-app-status", + Args: []string{scheduler, appName}, + }) + count := strings.Split(results.StdoutContents(), " ")[0] return strconv.Atoi(count) } func getRunningState(appName string) string { scheduler := common.GetAppScheduler(appName) - b, _ := common.PlugnTriggerOutput("scheduler-app-status", []string{scheduler, appName}...) - return strings.Split(strings.TrimSpace(string(b[:])), " ")[1] + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-app-status", + Args: []string{scheduler, appName}, + }) + return strings.Split(results.StdoutContents(), " ")[1] } func hasProcfile(appName string) bool { @@ -204,7 +210,12 @@ func getFormations(appName string) (FormationSlice, error) { } func restorePrep() error { - if err := common.PlugnTrigger("proxy-clear-config", []string{"--all"}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-clear-config", + Args: []string{"--all"}, + StreamStdio: true, + }) + if err != nil { return fmt.Errorf("Error clearing proxy config: %s", err) } @@ -260,7 +271,12 @@ func scaleSet(appName string, skipDeploy bool, clearExisting bool, processTuples } for _, formation := range formations { - if err := common.PlugnTrigger("deploy", []string{appName, imageTag, formation.ProcessType}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "deploy", + Args: []string{appName, imageTag, formation.ProcessType}, + StreamStdio: true, + }) + if err != nil { return err } } diff --git a/plugins/ps/go.mod b/plugins/ps/go.mod index 3105295f4..3ee49a0d8 100644 --- a/plugins/ps/go.mod +++ b/plugins/ps/go.mod @@ -12,8 +12,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/ps/go.sum b/plugins/ps/go.sum index 5a4997fa4..3d4afc513 100644 --- a/plugins/ps/go.sum +++ b/plugins/ps/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/ps/ps.go b/plugins/ps/ps.go index 75e6f3c93..7e1e2f4d9 100644 --- a/plugins/ps/ps.go +++ b/plugins/ps/ps.go @@ -2,7 +2,6 @@ package ps import ( "fmt" - "strings" "github.com/dokku/dokku/plugins/common" ) @@ -69,7 +68,12 @@ func (d FormationSlice) Less(i, j int) bool { // Rebuild rebuilds app from base image func Rebuild(appName string) error { - return common.PlugnTrigger("receive-app", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "receive-app", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // Restart restarts the app @@ -86,10 +90,20 @@ func Restart(appName string) error { if imageTag == "" { common.LogWarn("No deployed-image-tag property saved, falling back to full release-and-deploy") - return common.PlugnTrigger("release-and-deploy", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "release-and-deploy", + Args: []string{appName}, + StreamStdio: true, + }) + return err } - return common.PlugnTrigger("deploy", []string{appName, imageTag}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "deploy", + Args: []string{appName, imageTag}, + StreamStdio: true, + }) + return err } // RestartProcess restarts a process type within an app @@ -106,21 +120,41 @@ func RestartProcess(appName string, processName string) error { if imageTag == "" { common.LogWarn("No deployed-image-tag property saved, falling back to full release-and-deploy") - return common.PlugnTrigger("release-and-deploy", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "release-and-deploy", + Args: []string{appName}, + StreamStdio: true, + }) + return err } - return common.PlugnTrigger("deploy", []string{appName, imageTag, processName}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "deploy", + Args: []string{appName, imageTag, processName}, + StreamStdio: true, + }) + return err } // Restore ensures an app that should be running is running on boot func Restore(appName string) error { scheduler := common.GetAppScheduler(appName) - if err := common.PlugnTrigger("scheduler-pre-restore", []string{scheduler, appName}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-pre-restore", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + if err != nil { return fmt.Errorf("Error running scheduler-pre-restore: %s", err) } common.LogInfo1("Clearing potentially invalid proxy configuration") - if err := common.PlugnTrigger("proxy-clear-config", []string{appName}...); err != nil { + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-clear-config", + Args: []string{appName}, + StreamStdio: true, + }) + if err != nil { common.LogWarn(fmt.Sprintf("Error clearing proxy config: %s", err)) } @@ -129,8 +163,11 @@ func Restore(appName string) error { return nil } - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_APP_RESTORE"}...) - restore := strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_APP_RESTORE"}, + }) + restore := results.StdoutContents() if restore == "0" { common.LogWarn(fmt.Sprintf("Skipping ps:restore for %s as DOKKU_APP_RESTORE=%s", appName, restore)) return nil @@ -149,7 +186,12 @@ func Start(appName string) error { return nil } - if err := common.PlugnTrigger("pre-start", []string{appName}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "pre-start", + Args: []string{appName}, + StreamStdio: true, + }) + if err != nil { return fmt.Errorf("Failure in pre-start hook: %s", err) } @@ -162,18 +204,24 @@ func Start(appName string) error { } if runningState != "true" { - if err := common.PlugnTrigger("release-and-deploy", []string{appName, imageTag}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "release-and-deploy", + Args: []string{appName, imageTag}, + StreamStdio: true, + }) + if err != nil { return err } } else { common.LogWarn(fmt.Sprintf("App %s already running", appName)) } - if err := common.PlugnTrigger("proxy-build-config", []string{appName}...); err != nil { - return err - } - - return nil + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "proxy-build-config", + Args: []string{appName}, + StreamStdio: true, + }) + return err } // Stop stops the app @@ -186,13 +234,19 @@ func Stop(appName string) error { common.LogInfo1Quiet(fmt.Sprintf("Stopping %s", appName)) scheduler := common.GetAppScheduler(appName) - if err := common.PlugnTrigger("scheduler-stop", []string{scheduler, appName}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-stop", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + if err != nil { return err } - if err := common.PlugnTrigger("post-stop", []string{appName}...); err != nil { - return err - } - - return nil + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "post-stop", + Args: []string{appName}, + StreamStdio: true, + }) + return err } diff --git a/plugins/ps/report.go b/plugins/ps/report.go index af78b7263..5e0ddfe40 100644 --- a/plugins/ps/report.go +++ b/plugins/ps/report.go @@ -129,8 +129,11 @@ func reportRestartPolicy(appName string) string { } func reportRestore(appName string) string { - b, _ := common.PlugnTriggerOutput("config-get", []string{appName, "DOKKU_APP_RESTORE"}...) - restore := strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_APP_RESTORE"}, + }) + restore := results.StdoutContents() if restore == "0" { restore = "false" } else { diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index f818d8140..2d5302403 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -18,7 +18,12 @@ func CommandInspect(appName string) error { } scheduler := common.GetAppScheduler(appName) - return common.PlugnTrigger("scheduler-inspect", []string{scheduler, appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-inspect", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + return err } // CommandRebuild rebuilds an app from source @@ -74,7 +79,11 @@ func CommandRestart(appName string, processName string, allApps bool, parallelCo // CommandRestore starts previously running apps e.g. after reboot func CommandRestore(appName string, allApps bool, parallelCount int) error { - if err := common.PlugnTrigger("pre-restore", []string{}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "pre-restore", + StreamStdio: true, + }) + if err != nil { return fmt.Errorf("Error running pre-restore: %s", err) } @@ -124,7 +133,12 @@ func CommandRetire(appName string) error { } common.LogInfo1("Retiring old containers and images") - return common.PlugnTrigger("scheduler-retire", []string{scheduler, appName}...) + _, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "scheduler-retire", + Args: []string{scheduler, appName}, + StreamStdio: true, + }) + return err } // CommandScale gets or sets how many instances of a given process to run diff --git a/plugins/ps/triggers.go b/plugins/ps/triggers.go index c91b6c67f..c21e68a89 100644 --- a/plugins/ps/triggers.go +++ b/plugins/ps/triggers.go @@ -72,8 +72,11 @@ func TriggerCorePostExtract(appName string, sourceWorkDir string) error { } processSpecificProcfile := fmt.Sprintf("%s.%s", existingProcfile, os.Getenv("DOKKU_PID")) - b, _ := common.PlugnTriggerOutput("git-get-property", []string{appName, "source-image"}...) - appSourceImage := strings.TrimSpace(string(b[:])) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "git-get-property", + Args: []string{appName, "source-image"}, + }) + appSourceImage := results.StdoutContents() repoDefaultProcfilePath := path.Join(sourceWorkDir, "Procfile") if appSourceImage == "" { diff --git a/plugins/registry/go.mod b/plugins/registry/go.mod index b67077c8c..75c6adcc2 100644 --- a/plugins/registry/go.mod +++ b/plugins/registry/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/registry/go.sum b/plugins/registry/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/registry/go.sum +++ b/plugins/registry/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/registry/triggers.go b/plugins/registry/triggers.go index fa8cb5f07..5579a8b74 100644 --- a/plugins/registry/triggers.go +++ b/plugins/registry/triggers.go @@ -90,7 +90,12 @@ func TriggerPostDelete(appName string) error { func TriggerPostReleaseBuilder(appName string, image string) error { parts := strings.Split(image, ":") imageTag := parts[len(parts)-1] - if err := common.PlugnTrigger("pre-deploy", []string{appName, imageTag}...); err != nil { + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "pre-deploy", + Args: []string{appName, imageTag}, + StreamStdio: true, + }) + if err != nil { return err } diff --git a/plugins/repo/go.mod b/plugins/repo/go.mod index 48194e2be..791f1e826 100644 --- a/plugins/repo/go.mod +++ b/plugins/repo/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/repo/go.sum b/plugins/repo/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/repo/go.sum +++ b/plugins/repo/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/resource/go.mod b/plugins/resource/go.mod index 1fb2ef53f..3a1926766 100644 --- a/plugins/resource/go.mod +++ b/plugins/resource/go.mod @@ -9,8 +9,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/resource/go.sum b/plugins/resource/go.sum index 82ead0675..d1dda89b5 100644 --- a/plugins/resource/go.sum +++ b/plugins/resource/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/scheduler-docker-local/bin/scheduler-deploy-process b/plugins/scheduler-docker-local/bin/scheduler-deploy-process index fce53481b..b84ef7827 100755 --- a/plugins/scheduler-docker-local/bin/scheduler-deploy-process +++ b/plugins/scheduler-docker-local/bin/scheduler-deploy-process @@ -47,6 +47,33 @@ fn-scheduler-deploy-process() { fi fi + local DOCKER_ARGS + DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" "$PROC_TYPE") + DOCKER_ARGS+=$(: | plugn trigger docker-args-process-deploy "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE_TAG" "$PROC_TYPE") + DOCKER_ARGS=" $DOCKER_ARGS " + declare -a ARG_ARRAY + eval "ARG_ARRAY=($DOCKER_ARGS)" + + local port_published=false + for arg in "${ARG_ARRAY[@]}"; do + if [[ "$arg" == "-p "* ]] || [[ "$arg" =~ "--publish "* ]] || [[ "$arg" == "-P" ]] || [[ "$arg" =~ "--publish-all"* ]]; then + port_published=true + break + fi + done + + if [[ "$port_published" == "true" ]]; then + local warned_on_publish=false + if [[ "$PROC_COUNT" -gt 1 ]]; then + warned_on_publish=true + dokku_log_warn "Deploys may fail when publishing ports and scaling to multiple containers. Consider scaling process type $PROC_TYPE to 1." + fi + if [[ "$DOKKU_CHECKS_DISABLED" != "true" ]] && [[ "$warned_on_publish" == "false" ]]; then + warned_on_publish=true + dokku_log_warn "Deploys may fail when publishing ports and enabling zero downtime. Consider disabling zero downtime for process type $PROC_TYPE." + fi + fi + PARALLEL_DEPLOY_COUNT="$(plugn trigger "app-json-process-deploy-parallelism" "$APP" "$PROC_TYPE")" DOKKU_CHECKS_DISABLED="$DOKKU_CHECKS_DISABLED" INJECT_INIT_FLAG="$INJECT_INIT_FLAG" parallel --will-cite --halt soon,fail=1 --jobs "$PARALLEL_DEPLOY_COUNT" --ungroup <"$PROCESS_TMP_FILE" diff --git a/plugins/scheduler-docker-local/functions.go b/plugins/scheduler-docker-local/functions.go index 9b9da83a3..c9ade0be7 100644 --- a/plugins/scheduler-docker-local/functions.go +++ b/plugins/scheduler-docker-local/functions.go @@ -65,8 +65,11 @@ func generateCronEntries() ([]cron.TemplateCommand, error) { g.Go(func() error { commands := []cron.TemplateCommand{} - b, _ := common.PlugnTriggerOutput("cron-entries", "docker-local") - for _, line := range strings.Split(strings.TrimSpace(string(b[:])), "\n") { + response, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "cron-entries", + Args: []string{"docker-local"}, + }) + for _, line := range strings.Split(response.StdoutContents(), "\n") { if strings.TrimSpace(line) == "" { results <- []cron.TemplateCommand{} return nil @@ -121,7 +124,11 @@ func writeCronEntries() error { return deleteCrontab() } - mailto, _ := common.PlugnTriggerOutputAsString("cron-get-property", []string{"--global", "mailto"}...) + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "cron-get-property", + Args: []string{"--global", "mailto"}, + }) + mailto := results.StdoutContents() data := map[string]interface{}{ "Commands": commands, diff --git a/plugins/scheduler-docker-local/go.mod b/plugins/scheduler-docker-local/go.mod index db86c77b1..236d6dbb1 100644 --- a/plugins/scheduler-docker-local/go.mod +++ b/plugins/scheduler-docker-local/go.mod @@ -11,8 +11,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/dokku/dokku/plugins/app-json v0.0.0-00010101000000-000000000000 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect diff --git a/plugins/scheduler-docker-local/go.sum b/plugins/scheduler-docker-local/go.sum index c231b0109..775646bc7 100644 --- a/plugins/scheduler-docker-local/go.sum +++ b/plugins/scheduler-docker-local/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/plugins/scheduler-docker-local/internal-functions b/plugins/scheduler-docker-local/internal-functions index 33f16100e..ebce46b95 100755 --- a/plugins/scheduler-docker-local/internal-functions +++ b/plugins/scheduler-docker-local/internal-functions @@ -36,7 +36,6 @@ cmd-scheduler-docker-local-report-single() { fi verify_app_name "$APP" local flag_map=( - "--scheduler-docker-local-disable-chown: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "disable-chown" "")" "--scheduler-docker-local-init-process: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "init-process" "true")" "--scheduler-docker-local-parallel-schedule-count: $(fn-plugin-property-get "scheduler-docker-local" "$APP" "parallel-schedule-count" "")" ) diff --git a/plugins/scheduler-docker-local/pre-deploy b/plugins/scheduler-docker-local/pre-deploy index 65bff7a5b..04abd3d92 100755 --- a/plugins/scheduler-docker-local/pre-deploy +++ b/plugins/scheduler-docker-local/pre-deploy @@ -16,52 +16,9 @@ trigger-scheduler-docker-local-pre-deploy() { return fi - scheduler-docker-local-pre-deploy-chown-app "$APP" "$IMAGE_TAG" scheduler-docker-local-pre-deploy-precheck "$APP" } -scheduler-docker-local-pre-deploy-chown-app() { - declare desc="Runs chown against the /app directory for herokuish images" - declare APP="$1" IMAGE_TAG="$2" - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$APP" - local IMAGE DISABLE_CHOWN DOCKER_ARGS DOKKU_APP_TYPE DOKKU_APP_USER APP_PATHS CONTAINER_PATHS - declare -a ARG_ARRAY - - IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") - - DOKKU_APP_TYPE=$(config_get "$APP" DOKKU_APP_TYPE || true) - DOKKU_APP_USER=$(config_get "$APP" DOKKU_APP_USER || true) - DOKKU_APP_USER=${DOKKU_APP_USER:="herokuishuser"} - APP_PATHS=$(plugn trigger storage-list "$APP" "deploy") - - if [[ -n "$APP_PATHS" ]]; then - CONTAINER_PATHS=$(echo "$APP_PATHS" | awk -F ':' '{ print $2 }' | xargs) - DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG") - - filterdArgs=("--cpus" "--gpus" "--memory" "--memory-reservation" "--memory-swap" "--publish" "--publish-all" "-p" "-P" "--restart") - for filteredArg in "${filterdArgs[@]}"; do - # shellcheck disable=SC2001 - DOCKER_ARGS=$(sed -e "s/$filteredArg=[[:graph:]]\+[[:blank:]]\?//g" <<<"$DOCKER_ARGS") - - # shellcheck disable=SC2001 - DOCKER_ARGS=$(sed -e "s/$filteredArg\+[[:blank:]][[:graph:]]\+[[:blank:]]\?//g" <<<"$DOCKER_ARGS") - done - - eval "ARG_ARRAY=($DOCKER_ARGS)" - fi - - if [[ "$DOKKU_APP_TYPE" != "herokuish" ]] || [[ -z "$CONTAINER_PATHS" ]]; then - return - fi - - DISABLE_CHOWN="$(fn-plugin-property-get "scheduler-docker-local" "$APP" "disable-chown" "")" - if [[ "$DISABLE_CHOWN" == "true" ]]; then - return - fi - - "$DOCKER_BIN" container run --rm "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "${ARG_ARRAY[@]}" $IMAGE /bin/bash -c "find $CONTAINER_PATHS -not -user $DOKKU_APP_USER -print0 | xargs -0 -r chown -R $DOKKU_APP_USER" || true -} - scheduler-docker-local-pre-deploy-precheck() { declare desc="Outputs the checks messages if necessary" declare APP="$1" diff --git a/plugins/scheduler-docker-local/subcommands/set b/plugins/scheduler-docker-local/subcommands/set index 8f2230126..eade01b3a 100755 --- a/plugins/scheduler-docker-local/subcommands/set +++ b/plugins/scheduler-docker-local/subcommands/set @@ -9,13 +9,13 @@ cmd-scheduler-docker-local-set() { declare cmd="scheduler-docker-local:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("disable-chown" "init-process" "parallel-schedule-count") + local VALID_KEYS=("init-process" "parallel-schedule-count") verify_app_name "$APP" [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: disable-chown, init-process, parallel-schedule-count" + dokku_log_fail "Invalid key specified, valid keys include: init-process, parallel-schedule-count" fi if [[ -n "$VALUE" ]]; then diff --git a/plugins/scheduler-k3s/functions.go b/plugins/scheduler-k3s/functions.go index aad634c0e..20eaa7512 100644 --- a/plugins/scheduler-k3s/functions.go +++ b/plugins/scheduler-k3s/functions.go @@ -473,10 +473,11 @@ func extractStartCommand(input StartCommandInput) string { } if command == "" { - procfileStartCommand, _ := common.PlugnTriggerOutputAsString("procfile-get-command", []string{input.AppName, input.ProcessType, fmt.Sprint(input.Port)}...) - if procfileStartCommand != "" { - command = procfileStartCommand - } + results, _ := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "procfile-get-command", + Args: []string{input.AppName, input.ProcessType, fmt.Sprint(input.Port)}, + }) + command = results.StdoutContents() } return command @@ -1238,7 +1239,11 @@ func getProcessResources(appName string, processType string) (ProcessResourcesMa processResources.Limits.CPU = "" } } - nvidiaGpuLimit, err := common.PlugnTriggerOutputAsString("resource-get-property", []string{appName, processType, "limit", "nvidia-gpu"}...) + response, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "resource-get-property", + Args: []string{appName, processType, "limit", "nvidia-gpu"}, + }) + nvidiaGpuLimit := response.StdoutContents() if err == nil && nvidiaGpuLimit != "" && nvidiaGpuLimit != "0" { _, err := resource.ParseQuantity(nvidiaGpuLimit) if err != nil { diff --git a/plugins/scheduler-k3s/go.mod b/plugins/scheduler-k3s/go.mod index 62348ff5a..4895bf9f3 100644 --- a/plugins/scheduler-k3s/go.mod +++ b/plugins/scheduler-k3s/go.mod @@ -13,6 +13,7 @@ require ( github.com/go-openapi/jsonpointer v0.20.2 github.com/go-resty/resty/v2 v2.11.0 github.com/gofrs/flock v0.8.1 + github.com/gosimple/slug v1.14.0 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kedacore/keda/v2 v2.13.0 github.com/ryanuber/columnize v2.1.2+incompatible @@ -46,8 +47,6 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/containerd/containerd v1.7.11 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -86,6 +85,7 @@ require ( github.com/google/uuid v1.5.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect + github.com/gosimple/unidecode v1.0.1 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -165,7 +165,7 @@ require ( google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/evanphx/json-patch.v5 v5.8.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/plugins/scheduler-k3s/go.sum b/plugins/scheduler-k3s/go.sum index e613ee475..beac6a835 100644 --- a/plugins/scheduler-k3s/go.sum +++ b/plugins/scheduler-k3s/go.sum @@ -51,10 +51,6 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -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/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/containerd v1.7.11 h1:lfGKw3eU35sjV0aG2eYZTiwFEY1pCzxdzicHP3SZILw= @@ -195,6 +191,10 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es= +github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= +github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= @@ -547,8 +547,8 @@ google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/plugins/scheduler-k3s/helm.go b/plugins/scheduler-k3s/helm.go index b0cc95fcb..098bf3ad1 100644 --- a/plugins/scheduler-k3s/helm.go +++ b/plugins/scheduler-k3s/helm.go @@ -1,6 +1,7 @@ package scheduler_k3s import ( + "bytes" "context" "errors" "fmt" @@ -291,6 +292,16 @@ func (h *HelmAgent) ListRevisions(ctx context.Context, releaseName string) ([]Re return releases, nil } +type DebugRenderer struct { +} + +func (p *DebugRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { + for _, line := range strings.Split(renderedManifests.String(), "\n") { + common.LogWarn(line) + } + return renderedManifests, nil +} + func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error { namespace := input.Namespace if namespace == "" { @@ -311,8 +322,11 @@ func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error { client.Atomic = input.RollbackOnFailure client.ChartPathOptions = action.ChartPathOptions{} client.CleanupOnFail = true - client.DryRun = false client.MaxHistory = 10 + if os.Getenv("DOKKU_TRACE") == "1" { + client.DryRun = true + client.PostRenderer = &DebugRenderer{} + } client.Namespace = namespace client.Timeout = input.Timeout client.Wait = input.Wait diff --git a/plugins/scheduler-k3s/k8s.go b/plugins/scheduler-k3s/k8s.go index f7f13245e..6cc5835f5 100644 --- a/plugins/scheduler-k3s/k8s.go +++ b/plugins/scheduler-k3s/k8s.go @@ -12,6 +12,7 @@ import ( autoscalingv1 "k8s.io/api/autoscaling/v1" batchv1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -229,6 +230,20 @@ func (k KubernetesClient) CreateNamespace(ctx context.Context, input CreateNames return *namespace, err } +// DeleteIngressInput contains all the information needed to delete a Kubernetes ingress +type DeleteIngressInput struct { + // Name is the Kubernetes ingress name + Name string + + // Namespace is the Kubernetes namespace + Namespace string +} + +// DeleteIngress deletes a Kubernetes ingress +func (k KubernetesClient) DeleteIngress(ctx context.Context, input DeleteIngressInput) error { + return k.Client.NetworkingV1().Ingresses(input.Namespace).Delete(ctx, input.Name, metav1.DeleteOptions{}) +} + // DeleteJobInput contains all the information needed to delete a Kubernetes job type DeleteJobInput struct { // Name is the Kubernetes job name @@ -438,6 +453,30 @@ func (k KubernetesClient) ListDeployments(ctx context.Context, input ListDeploym return deployments.Items, nil } +// ListIngressesInput contains all the information needed to list Kubernetes ingresses +type ListIngressesInput struct { + // Namespace is the Kubernetes namespace + Namespace string + + // LabelSelector is the Kubernetes label selector + LabelSelector string +} + +// ListIngresses lists Kubernetes ingresses +func (k KubernetesClient) ListIngresses(ctx context.Context, input ListIngressesInput) ([]networkingv1.Ingress, error) { + listOptions := metav1.ListOptions{LabelSelector: input.LabelSelector} + ingresses, err := k.Client.NetworkingV1().Ingresses(input.Namespace).List(ctx, listOptions) + if err != nil { + return []networkingv1.Ingress{}, err + } + + if ingresses == nil { + return []networkingv1.Ingress{}, errors.New("ingresses is nil") + } + + return ingresses.Items, nil +} + // ListNamespaces lists Kubernetes namespaces func (k KubernetesClient) ListNamespaces(ctx context.Context) ([]v1.Namespace, error) { namespaces, err := k.Client.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) diff --git a/plugins/scheduler-k3s/portmap.go b/plugins/scheduler-k3s/portmap.go index 6e012d888..e25b09337 100644 --- a/plugins/scheduler-k3s/portmap.go +++ b/plugins/scheduler-k3s/portmap.go @@ -29,12 +29,15 @@ func getPortMaps(appName string) (map[string]PortMap, error) { portMaps := []PortMap{} allowedMappings := map[string]PortMap{} - output, err := common.PlugnTriggerOutputAsString("ports-get", []string{appName, "json"}...) + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "ports-get", + Args: []string{appName, "json"}, + }) if err != nil { return allowedMappings, err } - err = json.Unmarshal([]byte(output), &portMaps) + err = json.Unmarshal([]byte(results.StdoutContents()), &portMaps) if err != nil { return allowedMappings, err } diff --git a/plugins/scheduler-k3s/scheduler_k3s.go b/plugins/scheduler-k3s/scheduler_k3s.go index f03bc6ffc..d72005b22 100644 --- a/plugins/scheduler-k3s/scheduler_k3s.go +++ b/plugins/scheduler-k3s/scheduler_k3s.go @@ -42,7 +42,7 @@ var ( } ) -const DefaultIngressClass = "traefik" +const DefaultIngressClass = "nginx" const GlobalProcessType = "--global" const KubeConfigPath = "/etc/rancher/k3s/k3s.yaml" const DefaultKubeContext = "" diff --git a/plugins/scheduler-k3s/template.go b/plugins/scheduler-k3s/template.go index d5fb94ba3..6622ba17b 100644 --- a/plugins/scheduler-k3s/template.go +++ b/plugins/scheduler-k3s/template.go @@ -238,11 +238,16 @@ type ProcessLabels struct { } type ProcessWeb struct { - Domains []string `yaml:"domains,omitempty"` + Domains []ProcessDomains `yaml:"domains,omitempty"` PortMaps []ProcessPortMap `yaml:"port_maps,omitempty"` TLS ProcessTls `yaml:"tls"` } +type ProcessDomains struct { + Name string `yaml:"name"` + Slug string `yaml:"slug"` +} + type ProcessResourcesMap struct { Limits ProcessResources `yaml:"limits,omitempty"` Requests ProcessResources `yaml:"requests,omitempty"` diff --git a/plugins/scheduler-k3s/templates/chart/_helpers.tpl b/plugins/scheduler-k3s/templates/chart/_helpers.tpl index 3f340c56c..6fb5ee787 100644 --- a/plugins/scheduler-k3s/templates/chart/_helpers.tpl +++ b/plugins/scheduler-k3s/templates/chart/_helpers.tpl @@ -15,3 +15,35 @@ {{- end }} {{- end }} {{- end }} + +{{- define "primary.port" -}} +{{- $found := dict -}} +{{- range $idx, $port_map := . -}} +{{- if hasPrefix "https-443-" $port_map.name -}} +{{- $found := set $found "https-443" $port_map.name -}} +{{- end -}} +{{- if hasPrefix "http-80-" $port_map.name -}} +{{- $found := set $found "http-80" $port_map.name -}} +{{- end -}} +{{- if and (eq "https" $port_map.scheme) (not (hasKey $found "https")) -}} +{{- $found := set $found "https" $port_map.name -}} +{{- end -}} +{{- if and (eq "http" $port_map.scheme) (not (hasKey $found "http")) -}} +{{- $found := set $found "http" $port_map.name -}} +{{- end -}} +{{- if not (hasKey $found "any") -}} +{{- $found := set $found "any" $port_map.name -}} +{{- end -}} +{{- end -}} +{{- if hasKey $found "https-443" -}} +{{- get $found "https-443" -}} +{{- else if hasKey $found "http-80" -}} +{{- get $found "http-80" -}} +{{- else if hasKey $found "https" -}} +{{- get $found "https" -}} +{{- else if hasKey $found "http" -}} +{{- get $found "http" -}} +{{- else if hasKey $found "any" -}} +{{- get $found "any" -}} +{{- end -}} +{{- end -}} diff --git a/plugins/scheduler-k3s/templates/chart/certificate.yaml b/plugins/scheduler-k3s/templates/chart/certificate.yaml index 1ffc42a92..029230020 100644 --- a/plugins/scheduler-k3s/templates/chart/certificate.yaml +++ b/plugins/scheduler-k3s/templates/chart/certificate.yaml @@ -30,7 +30,7 @@ spec: {{ include "print.labels" (dict "config" $.Values.global "key" "secret") | indent 6 }} {{ include "print.labels" (dict "config" $config "key" "secret") | indent 6 }} dnsNames: - {{- range $config.web.domains }} - - {{ . }} + {{- range $idx, $domain := $config.web.domains }} + - {{ $domain.name }} {{- end }} {{- end }} diff --git a/plugins/scheduler-k3s/templates/chart/ingress-route.yaml b/plugins/scheduler-k3s/templates/chart/ingress-route.yaml index e61c48063..306e4a7a3 100644 --- a/plugins/scheduler-k3s/templates/chart/ingress-route.yaml +++ b/plugins/scheduler-k3s/templates/chart/ingress-route.yaml @@ -34,7 +34,7 @@ spec: routes: {{- range $ddx, $domain := $config.web.domains }} - kind: Rule - match: Host(`{{ $domain }}`) + match: Host(`{{ $domain.name }}`) {{- if $config.web.tls.enabled }} middlewares: - name: {{ $.Values.global.app_name}}-{{ $processName }}-redirect-to-https diff --git a/plugins/scheduler-k3s/templates/chart/ingress.yaml b/plugins/scheduler-k3s/templates/chart/ingress.yaml index cfbf519df..b0eaa6c57 100644 --- a/plugins/scheduler-k3s/templates/chart/ingress.yaml +++ b/plugins/scheduler-k3s/templates/chart/ingress.yaml @@ -1,20 +1,14 @@ {{- $processName := "PROCESS_NAME" }} {{- $config := index .Values.processes "PROCESS_NAME" }} {{- if and $config.web.domains (eq $.Values.global.network.ingress_class "nginx") }} -{{- $mappings := dict }} -{{- range $pdx, $port_map := $config.web.port_maps }} -{{- $mappings := set $mappings $port_map.name "true" }} -{{- end }} -{{- range $pdx, $port_map := $config.web.port_maps }} -{{- if and (eq $port_map.scheme "https") (hasKey $mappings (printf "http-80-%.0f" $port_map.container_port)) }} -{{- continue }} -{{- end }} +{{- range $pdx, $domain := $config.web.domains }} --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: dokku.com/managed: "true" + dokku.com/ingress-method: "domains" {{- if $config.web.tls.enabled }} nginx.ingress.kubernetes.io/force-ssl-redirect: "true" {{- end }} @@ -26,30 +20,28 @@ metadata: app.kubernetes.io/part-of: {{ $.Values.global.app_name }} {{ include "print.labels" (dict "config" $.Values.global "key" "ingress") | indent 4 }} {{ include "print.labels" (dict "config" $config "key" "ingress") | indent 4 }} - name: {{ $.Values.global.app_name }}-{{ $processName }}-{{ $port_map.name }} + name: {{ $.Values.global.app_name }}-{{ $processName }}-{{ $domain.slug }} namespace: {{ $.Values.global.namespace }} spec: ingressClassName: nginx {{- if $config.web.tls.enabled }} tls: - hosts: - {{- range $ddx, $domain := $config.web.domains }} - - {{ $domain | quote }} - {{- end }} + - {{ $domain.name | quote }} secretName: tls-{{ $.Values.global.app_name }}-{{ $processName }} {{- end }} rules: - {{- range $ddx, $domain := $config.web.domains }} - - host: {{ $domain | quote }} + - host: {{ $domain.name | quote }} http: paths: + {{- if $config.web.port_maps }} - backend: service: name: {{ $.Values.global.app_name }}-{{ $processName }} port: - name: {{ $port_map.name }} + name: {{ include "primary.port" $config.web.port_maps }} pathType: ImplementationSpecific path: / - {{- end }} + {{- end }} {{- end }} {{- end }} diff --git a/plugins/scheduler-k3s/triggers.go b/plugins/scheduler-k3s/triggers.go index 827380869..86a5cb6c6 100644 --- a/plugins/scheduler-k3s/triggers.go +++ b/plugins/scheduler-k3s/triggers.go @@ -23,6 +23,7 @@ import ( "github.com/dokku/dokku/plugins/config" "github.com/dokku/dokku/plugins/cron" "github.com/fatih/color" + "github.com/gosimple/slug" "github.com/kballard/go-shellquote" "github.com/ryanuber/columnize" corev1 "k8s.io/api/core/v1" @@ -36,7 +37,6 @@ func TriggerInstall() error { if err := common.PropertySetup("scheduler-k3s"); err != nil { return fmt.Errorf("Unable to install the scheduler-k3s plugin: %s", err.Error()) } - return nil } @@ -80,12 +80,15 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e if scheduler != "k3s" { return nil } - s, err := common.PlugnTriggerOutput("ps-current-scale", []string{appName}...) + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "ps-current-scale", + Args: []string{appName}, + }) if err != nil { return err } - processes, err := common.ParseScaleOutput(s) + processes, err := common.ParseScaleOutput(results.StdoutBytes()) if err != nil { return err } @@ -224,14 +227,21 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e domains := []string{} if _, ok := processes["web"]; ok { - err = common.PlugnTrigger("domains-vhost-enabled", []string{appName}...) + _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "domains-vhost-enabled", + Args: []string{appName}, + StreamStdio: true, + }) if err == nil { - b, err := common.PlugnTriggerOutput("domains-list", []string{appName}...) + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "domains-list", + Args: []string{appName}, + }) if err != nil { return fmt.Errorf("Error getting domains for deployment: %w", err) } - for _, domain := range strings.Split(string(b), "\n") { + for _, domain := range strings.Split(results.StdoutContents(), "\n") { domain = strings.TrimSpace(domain) if domain != "" { domains = append(domains, domain) @@ -385,8 +395,17 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e } if processType == "web" { + sort.Strings(domains) + domainValues := []ProcessDomains{} + for _, domain := range domains { + domainValues = append(domainValues, ProcessDomains{ + Name: domain, + Slug: slug.Make(domain), + }) + } + processValues.Web = ProcessWeb{ - Domains: domains, + Domains: domainValues, PortMaps: []ProcessPortMap{}, TLS: ProcessTls{ Enabled: tlsEnabled, @@ -435,7 +454,6 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e } sort.Sort(NameSorter(processValues.Web.PortMaps)) - sort.Strings(processValues.Web.Domains) } values.Processes[processType] = processValues @@ -587,7 +605,39 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e return fmt.Errorf("Error parsing deploy timeout duration: %w", err) } - common.LogExclaim(fmt.Sprintf("Installing %s", appName)) + ingresses, err := clientset.ListIngresses(ctx, ListIngressesInput{ + Namespace: namespace, + LabelSelector: fmt.Sprintf("app.kubernetes.io/instance=%s-web", appName), + }) + if err != nil { + return fmt.Errorf("Error listing ingresses: %w", err) + } + + ingressesToDelete := []string{} + + for _, ingress := range ingresses { + ingressIngressMethod := ingress.Annotations["dokku.com/ingress-method"] + if ingressIngressMethod != "domains" { + ingressesToDelete = append(ingressesToDelete, ingress.Name) + } + } + + if len(ingressesToDelete) > 0 { + common.LogWarn("Manually removing non-matching ingress resources") + } + for _, ingressName := range ingressesToDelete { + common.LogVerboseQuiet(fmt.Sprintf("Removing non-matching ingress resource: %s", ingressName)) + err := clientset.DeleteIngress(ctx, DeleteIngressInput{ + Name: ingressName, + Namespace: namespace, + }) + + if err != nil { + return fmt.Errorf("Error deleting ingress: %w", err) + } + } + + common.LogInfo2(fmt.Sprintf("Installing %s", appName)) err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{ ChartPath: chartPath, Namespace: namespace, @@ -695,10 +745,21 @@ func TriggerSchedulerEnter(scheduler string, appName string, processType string, command := args if len(args) == 0 { command = []string{"/bin/bash"} - if globalShell, err := common.PlugnTriggerOutputAsString("config-get-global", []string{"DOKKU_APP_SHELL"}...); err == nil && globalShell != "" { + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_APP_SHELL"}, + }) + globalShell := results.StdoutContents() + if err == nil && globalShell != "" { command = []string{globalShell} } - if appShell, err := common.PlugnTriggerOutputAsString("config-get", []string{appName, "DOKKU_APP_SHELL"}...); err == nil && appShell != "" { + + results, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_APP_SHELL"}, + }) + appShell := results.StdoutContents() + if err == nil && appShell != "" { command = []string{appShell} } } @@ -927,10 +988,21 @@ func TriggerSchedulerRun(scheduler string, appName string, envCount int, args [] command := args if len(args) == 0 { command = []string{"/bin/bash"} - if globalShell, err := common.PlugnTriggerOutputAsString("config-get-global", []string{"DOKKU_APP_SHELL"}...); err == nil && globalShell != "" { + results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get-global", + Args: []string{"DOKKU_APP_SHELL"}, + }) + globalShell := results.StdoutContents() + if err == nil && globalShell != "" { command = []string{globalShell} } - if appShell, err := common.PlugnTriggerOutputAsString("config-get", []string{appName, "DOKKU_APP_SHELL"}...); err == nil && appShell != "" { + + results, err = common.CallPlugnTrigger(common.PlugnTriggerInput{ + Trigger: "config-get", + Args: []string{appName, "DOKKU_APP_SHELL"}, + }) + appShell := results.StdoutContents() + if err == nil && appShell != "" { command = []string{appShell} } } else if len(args) == 1 { diff --git a/plugins/scheduler/go.mod b/plugins/scheduler/go.mod index 570da73bc..4bdadd218 100644 --- a/plugins/scheduler/go.mod +++ b/plugins/scheduler/go.mod @@ -10,8 +10,6 @@ require ( require ( github.com/alexellis/go-execute/v2 v2.2.1 // indirect - github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect - github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 // indirect github.com/fatih/color v1.16.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/plugins/scheduler/go.sum b/plugins/scheduler/go.sum index a2e5d436b..bf77a3bf1 100644 --- a/plugins/scheduler/go.sum +++ b/plugins/scheduler/go.sum @@ -1,9 +1,5 @@ github.com/alexellis/go-execute/v2 v2.2.1 h1:4Ye3jiCKQarstODOEmqDSRCqxMHLkC92Bhse743RdOI= github.com/alexellis/go-execute/v2 v2.2.1/go.mod h1:FMdRnUTiFAmYXcv23txrp3VYZfLo24nMpiIneWgKHTQ= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= diff --git a/plugins/traefik-vhosts/command-functions b/plugins/traefik-vhosts/command-functions index 68f194d5b..c37a19f8c 100755 --- a/plugins/traefik-vhosts/command-functions +++ b/plugins/traefik-vhosts/command-functions @@ -44,7 +44,6 @@ cmd-traefik-report-single() { "--traefik-letsencrypt-email: $(fn-traefik-letsencrypt-email)" "--traefik-letsencrypt-server: $(fn-traefik-letsencrypt-server)" "--traefik-log-level: $(fn-traefik-log-level)" - "--traefik-priority: $(fn-traefik-priority "$APP")" ) if [[ -z "$INFO_FLAG" ]]; then diff --git a/plugins/traefik-vhosts/docker-args-process-deploy b/plugins/traefik-vhosts/docker-args-process-deploy index f9d94ffa4..6cb1c8da4 100755 --- a/plugins/traefik-vhosts/docker-args-process-deploy +++ b/plugins/traefik-vhosts/docker-args-process-deploy @@ -8,7 +8,7 @@ trigger-traefik-vhosts-docker-args-process-deploy() { declare desc="nginx-vhosts core-post-deploy plugin trigger" declare trigger="docker-args-process-deploy" declare APP="$1" IMAGE_SOURCE_TYPE="$2" IMAGE_TAG="$3" PROC_TYPE="$4" CONTAINER_INDEX="$5" - local app_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map priority proxy_scheme proxy_schemes traefik_domains + local app_domains is_app_listening letsencrypt_email output proxy_container_port proxy_host_port port_map proxy_scheme proxy_schemes traefik_domains local proxy_container_http_port proxy_container_http_port_candidate proxy_host_http_port_candidate local proxy_container_https_port proxy_container_https_port_candidate proxy_host_https_port_candidate local STDIN=$(cat) @@ -87,11 +87,6 @@ trigger-traefik-vhosts-docker-args-process-deploy() { traefik_domains="${traefik_domains// /\\\`,\\\`}" fi - priority="$(fn-traefik-priority "$APP")" - if [[ -z "$priority" ]]; then - priority="$(date +%s)" - fi - output="--label traefik.enable=true" if [[ -n "$proxy_container_http_port" ]] || [[ -n "$proxy_container_http_port_candidate" ]]; then if [[ -z "$proxy_container_http_port" ]]; then @@ -102,7 +97,6 @@ trigger-traefik-vhosts-docker-args-process-deploy() { output="$output --label traefik.http.services.$APP-$PROC_TYPE-http.loadbalancer.server.port=$proxy_container_http_port" output="$output --label traefik.http.routers.$APP-$PROC_TYPE-http.entrypoints=http" - output="$output --label traefik.http.routers.$APP-$PROC_TYPE-http.priority=$priority" output="$output --label traefik.http.routers.$APP-$PROC_TYPE-http.service=$APP-$PROC_TYPE-http" if [[ -n "$traefik_domains" ]]; then output="$output --label \"traefik.http.routers.$APP-$PROC_TYPE-http.rule=Host(\\\`$traefik_domains\\\`)\"" @@ -118,7 +112,6 @@ trigger-traefik-vhosts-docker-args-process-deploy() { output="$output --label traefik.http.services.$APP-$PROC_TYPE-https.loadbalancer.server.port=$proxy_container_https_port" output="$output --label traefik.http.routers.$APP-$PROC_TYPE-https.entrypoints=https" - output="$output --label traefik.http.routers.$APP-$PROC_TYPE-https.priority=$priority" output="$output --label traefik.http.routers.$APP-$PROC_TYPE-https.service=$APP-$PROC_TYPE-https" output="$output --label traefik.http.routers.$APP-$PROC_TYPE-https.tls.certresolver=leresolver" if [[ -n "$traefik_domains" ]]; then diff --git a/plugins/traefik-vhosts/internal-functions b/plugins/traefik-vhosts/internal-functions index f2e7e4134..ce981215d 100755 --- a/plugins/traefik-vhosts/internal-functions +++ b/plugins/traefik-vhosts/internal-functions @@ -92,8 +92,3 @@ fn-traefik-log-level() { log_level="$(fn-plugin-property-get-default "traefik" "--global" "log-level" "ERROR")" echo "${log_level^^}" } - -fn-traefik-priority() { - declare APP="$1" - fn-plugin-property-get-default "traefik" "$APP" "priority" "" -} diff --git a/plugins/traefik-vhosts/subcommands/set b/plugins/traefik-vhosts/subcommands/set index 0c51777b2..c9a10476b 100755 --- a/plugins/traefik-vhosts/subcommands/set +++ b/plugins/traefik-vhosts/subcommands/set @@ -9,13 +9,13 @@ cmd-traefik-set() { declare cmd="traefik:set" [[ "$1" == "$cmd" ]] && shift 1 declare APP="$1" KEY="$2" VALUE="$3" - local VALID_KEYS=("api-enabled" "api-vhost" "dashboard-enabled" "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "letsencrypt-server" "log-level" "priority") + local VALID_KEYS=("api-enabled" "api-vhost" "dashboard-enabled" "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "letsencrypt-server" "log-level") local GLOBAL_KEYS=("api-enabled" "api-vhost" "dashboard"-enabled "basic-auth-username" "basic-auth-password" "image" "letsencrypt-email" "letsencrypt-server" "log-level") [[ -z "$KEY" ]] && dokku_log_fail "No key specified" if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then - dokku_log_fail "Invalid key specified, valid keys include: api-enabled api-vhost dashboard-enabled basic-auth-username basic-auth-password image letsencrypt-email letsencrypt-server log-level priority" + dokku_log_fail "Invalid key specified, valid keys include: api-enabled api-vhost dashboard-enabled basic-auth-username basic-auth-password image letsencrypt-email letsencrypt-server log-level" fi if ! fn-in-array "$KEY" "${GLOBAL_KEYS[@]}"; then diff --git a/plugins/traefik-vhosts/templates/compose.yml.sigil b/plugins/traefik-vhosts/templates/compose.yml.sigil index 6bddb9938..d06854484 100644 --- a/plugins/traefik-vhosts/templates/compose.yml.sigil +++ b/plugins/traefik-vhosts/templates/compose.yml.sigil @@ -12,6 +12,7 @@ services: - --entrypoints.https.address=:443 {{ end }} - --providers.docker + - --providers.docker.exposedByDefault=false - --api={{ $.TRAEFIK_API_ENABLED }} - --api.dashboard={{ $.TRAEFIK_DASHBOARD_ENABLED }} @@ -33,6 +34,7 @@ services: {{ if eq $.TRAEFIK_API_ENABLED "true" }} # Dashboard + - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`{{ $.TRAEFIK_API_VHOST }}`)" - "traefik.http.routers.api.service=api@internal" - "traefik.http.routers.api.entrypoints={{ if $.TRAEFIK_LETSENCRYPT_EMAIL }}https{{ else }}http{{ end }}" diff --git a/tests/unit/apps_1.bats b/tests/unit/apps_1.bats index 7b415606f..5b85ffacd 100644 --- a/tests/unit/apps_1.bats +++ b/tests/unit/apps_1.bats @@ -178,6 +178,14 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + run /bin/bash -c "dokku config:set --no-restart $TEST_APP KEY=VALUE-$TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --no-healthcheck" + echo "output: $output" + echo "status: $status" + assert_success run /bin/bash -c "dokku git:set $TEST_APP deploy-branch SOME_BRANCH_NAME" echo "output: $output" echo "status: $status" @@ -194,10 +202,6 @@ teardown() { echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku scheduler-docker-local:set $TEST_APP disable-chown true" - echo "output: $output" - echo "status: $status" - assert_success run /bin/bash -c "dokku apps:rename $TEST_APP great-test-name" echo "output: $output" @@ -208,6 +212,16 @@ teardown() { echo "status: $status" assert_success assert_output "https://github.com/heroku/heroku-buildpack-ruby.git" + run /bin/bash -c "dokku config:get great-test-name KEY" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "VALUE-$TEST_APP" + run /bin/bash -c "dokku docker-options:report great-test-name --docker-options-deploy" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "--no-healthcheck" run /bin/bash -c "dokku git:report great-test-name --git-deploy-branch" echo "output: $output" echo "status: $status" @@ -228,11 +242,6 @@ teardown() { echo "status: $status" assert_success assert_output "100" - run /bin/bash -c "dokku scheduler-docker-local:report great-test-name --scheduler-docker-local-disable-chown" - echo "output: $output" - echo "status: $status" - assert_success - assert_output "true" run /bin/bash -c "dokku --force apps:destroy great-test-name" echo "output: $output" diff --git a/tests/unit/apps_2.bats b/tests/unit/apps_2.bats index eb7ddcbb7..a176cece0 100644 --- a/tests/unit/apps_2.bats +++ b/tests/unit/apps_2.bats @@ -59,10 +59,6 @@ teardown() { echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku scheduler-docker-local:set $TEST_APP disable-chown true" - echo "output: $output" - echo "status: $status" - assert_success run /bin/bash -c "dokku apps:clone $TEST_APP great-test-name" echo "output: $output" @@ -103,11 +99,6 @@ teardown() { echo "status: $status" assert_success assert_output "100" - run /bin/bash -c "dokku scheduler-docker-local:report great-test-name --scheduler-docker-local-disable-chown" - echo "output: $output" - echo "status: $status" - assert_success - assert_output "true" run /bin/bash -c "dokku --force apps:destroy great-test-name" echo "output: $output" diff --git a/tests/unit/buildpacks.bats b/tests/unit/buildpacks.bats index acef76307..e4d24fb39 100644 --- a/tests/unit/buildpacks.bats +++ b/tests/unit/buildpacks.bats @@ -205,7 +205,7 @@ teardown() { run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs" echo "output: $output" echo "status: $status" - assert_output_contains "https://github.com/heroku/heroku-buildpack-nodejs.git https://github.com/heroku/heroku-buildpack-ruby.git" + assert_output "https://github.com/heroku/heroku-buildpack-nodejs.git https://github.com/heroku/heroku-buildpack-ruby.git" run /bin/bash -c "dokku buildpacks:remove $TEST_APP heroku/nodejs" echo "output: $output" @@ -215,7 +215,7 @@ teardown() { run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs" echo "output: $output" echo "status: $status" - assert_output_contains "https://github.com/heroku/heroku-buildpack-ruby.git" + assert_output "https://github.com/heroku/heroku-buildpack-ruby.git" run /bin/bash -c "dokku buildpacks:remove $TEST_APP heroku/php" echo "output: $output" @@ -231,6 +231,36 @@ teardown() { echo "output: $output" echo "status: $status" assert_output_not_exists + + run /bin/bash -c "dokku buildpacks:add $TEST_APP https://github.com/heroku/heroku-buildpack-nodejs.git" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku buildpacks:add $TEST_APP https://github.com/heroku/heroku-buildpack-ruby.git" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku buildpacks:add $TEST_APP https://github.com/yespark/heroku-imagemagick-buildpack" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "https://github.com/heroku/heroku-buildpack-nodejs.git https://github.com/heroku/heroku-buildpack-ruby.git https://github.com/yespark/heroku-imagemagick-buildpack" + + run /bin/bash -c "dokku buildpacks:remove $TEST_APP --index 1" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs" + echo "output: $output" + echo "status: $status" + assert_output "https://github.com/heroku/heroku-buildpack-ruby.git https://github.com/yespark/heroku-imagemagick-buildpack" } @test "(buildpacks) buildpacks:clear" { diff --git a/tests/unit/client.bats b/tests/unit/client.bats index bfb51a64d..0c0610ea9 100644 --- a/tests/unit/client.bats +++ b/tests/unit/client.bats @@ -6,9 +6,11 @@ setup() { global_setup export "DOKKU_HOST=${DOKKU_DOMAIN}" create_app + clone_test_plugin } teardown() { + remove_test_plugin || true destroy_app unset DOKKU_HOST global_teardown @@ -311,3 +313,22 @@ teardown() { assert_success assert_output "dokku" } + +@test "(client) test-args" { + run /bin/bash -c "dokku plugin:install $TEST_PLUGIN_GIT_REPO --name $TEST_PLUGIN_NAME" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku smoke-test-plugin:args bash -c 'echo Hello'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "triggered smoke-test-plugin:args with args: smoke-test-plugin:args, bash, -c, echo Hello" + + run /bin/bash -c "${BATS_TEST_DIRNAME}/../../contrib/dokku_client.sh 'smoke-test-plugin:args bash -c \"echo Hello\"'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "triggered smoke-test-plugin:args with args: smoke-test-plugin:args, bash, -c, echo Hello" +} diff --git a/tests/unit/git_3.bats b/tests/unit/git_3.bats index 1cec55596..1361181f0 100644 --- a/tests/unit/git_3.bats +++ b/tests/unit/git_3.bats @@ -2,6 +2,12 @@ load test_helper +SMOKE_TEST_APP_1_0_0_SHA=9cf71bba639c4f1671dfd42685338b762d3354f2 +SMOKE_TEST_APP_2_0_0_SHA=5c8a5e42bbd7fae98bd657fb17f41c6019b303f9 +SMOKE_TEST_APP_ANOTHER_BRANCH_SHA=5c8a5e42bbd7fae98bd657fb17f41c6019b303f9 +SMOKE_TEST_APP_MASTER_SHA=af1b02052199b8ca8115f80ff8676a7c7744a45f +SMOKE_TEST_APP_COMMIT_SHA=5c8a5e42bbd7fae98bd657fb17f41c6019b303f9 + setup() { global_setup create_app @@ -121,6 +127,12 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_MASTER_SHA" } @test "(git) git:sync new [--no-build branch]" { @@ -128,6 +140,12 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/another-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_ANOTHER_BRANCH_SHA" } @test "(git) git:sync new [--no-build tag]" { @@ -135,13 +153,25 @@ teardown() { echo "output: $output" echo "status: $status" assert_success -} -@test "(git) git:sync new [--no-build commit]" { - run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git 5c8a5e42bbd7fae98bd657fb17f41c6019b303f9" + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" echo "output: $output" echo "status: $status" assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" +} + +@test "(git) git:sync new [--no-build commit]" { + run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git $SMOKE_TEST_APP_COMMIT_SHA" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_COMMIT_SHA" } @test "(git) git:sync new [--build noarg]" { @@ -150,6 +180,24 @@ teardown() { echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_MASTER_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_MASTER_SHA" } @test "(git) git:sync new [--build branch]" { @@ -158,6 +206,24 @@ teardown() { echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/another-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_ANOTHER_BRANCH_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git another-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/another-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_ANOTHER_BRANCH_SHA" } @test "(git) git:sync new [--build tag]" { @@ -166,14 +232,50 @@ teardown() { echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git 1.0.0" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" } @test "(git) git:sync new [--build commit]" { - run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git 5c8a5e42bbd7fae98bd657fb17f41c6019b303f9" + run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git $SMOKE_TEST_APP_COMMIT_SHA" echo "output: $output" echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_COMMIT_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git $SMOKE_TEST_APP_COMMIT_SHA" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_COMMIT_SHA" } @test "(git) git:sync existing [errors]" { @@ -204,15 +306,28 @@ teardown() { } @test "(git) git:sync existing [--no-build noarg]" { - run /bin/bash -c "dokku --trace git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git 1.0.0" + run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git 1.0.0" echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku --trace git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git" + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" echo "output: $output" echo "status: $status" assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + + run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Fetching remote code for" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_MASTER_SHA" } @test "(git) git:sync existing [--no-build branch]" { @@ -221,10 +336,22 @@ teardown() { echo "status: $status" assert_success + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git another-branch" echo "output: $output" echo "status: $status" assert_success + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/another-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_ANOTHER_BRANCH_SHA" } @test "(git) git:sync existing [--no-build tag]" { @@ -233,10 +360,22 @@ teardown() { echo "status: $status" assert_success + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git 2.0.0" echo "output: $output" echo "status: $status" assert_success + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_2_0_0_SHA" } @test "(git) git:sync existing [--no-build commit]" { @@ -245,10 +384,22 @@ teardown() { echo "status: $status" assert_success - run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git 5c8a5e42bbd7fae98bd657fb17f41c6019b303f9" + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" echo "output: $output" echo "status: $status" assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + + run /bin/bash -c "dokku git:sync $TEST_APP https://github.com/dokku/smoke-test-app.git $SMOKE_TEST_APP_COMMIT_SHA" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_COMMIT_SHA" } @test "(git) git:sync existing [--build noarg]" { @@ -257,11 +408,35 @@ teardown() { echo "status: $status" assert_success + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git" echo "output: $output" echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_MASTER_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_MASTER_SHA" } @test "(git) git:sync existing [--build branch]" { @@ -270,11 +445,35 @@ teardown() { echo "status: $status" assert_success + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_2_0_0_SHA" + run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git another-branch" echo "output: $output" echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_ANOTHER_BRANCH_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git another-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_ANOTHER_BRANCH_SHA" } @test "(git) git:sync existing [--build tag]" { @@ -283,11 +482,35 @@ teardown() { echo "status: $status" assert_success + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git 2.0.0" echo "output: $output" echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_2_0_0_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git 2.0.0" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_2_0_0_SHA" } @test "(git) git:sync existing [--build commit]" { @@ -296,11 +519,35 @@ teardown() { echo "status: $status" assert_success - run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git 5c8a5e42bbd7fae98bd657fb17f41c6019b303f9" + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_1_0_0_SHA" + + run /bin/bash -c "dokku git:sync --build $TEST_APP https://github.com/dokku/smoke-test-app.git $SMOKE_TEST_APP_COMMIT_SHA" echo "output: $output" echo "status: $status" assert_success assert_output_contains "Application deployed" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_COMMIT_SHA" + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app.git $SMOKE_TEST_APP_COMMIT_SHA" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" + + run /bin/bash -c "cat /home/dokku/$TEST_APP/refs/heads/master" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "$SMOKE_TEST_APP_COMMIT_SHA" } @test "(git) git:sync private" { @@ -328,6 +575,12 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + + run /bin/bash -c "dokku git:sync --build-if-changes $TEST_APP https://github.com/dokku/smoke-test-app-private.git" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Skipping build as no changes were detected" } @test "(git) git:public-key" { diff --git a/tests/unit/git_6.bats b/tests/unit/git_6.bats index ab706a575..03c81f264 100644 --- a/tests/unit/git_6.bats +++ b/tests/unit/git_6.bats @@ -4,27 +4,286 @@ load test_helper setup() { global_setup + create_app touch /home/dokku/.ssh/known_hosts chown dokku:dokku /home/dokku/.ssh/known_hosts - mkdir -p "$DOKKU_LIB_ROOT/data/git/$TEST_APP" - chown dokku:dokku "$DOKKU_LIB_ROOT/data/git/$TEST_APP" } teardown() { + docker image rm linuxserver/foldingathome:7.6.21 || true + docker image rm dokku/node-js-getting-started:latest || true + docker image rm dokku-test/$TEST_APP:latest || true + docker image rm dokku-test/$TEST_APP:v2 || true + docker image rm gliderlabs/logspout:v3.2.13 || true + rm -f /tmp/image.tar /tmp/image-2.tar rm -f /home/dokku/.ssh/id_rsa.pub || true + destroy_app global_teardown } -@test "(git) git:unlock [success]" { - run /bin/bash -c "dokku git:unlock $TEST_APP --force" +@test "(git) git:load-image [normal]" { + run /bin/bash -c "docker image pull linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image.tar linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP linuxserver/foldingathome:7.6.21" echo "output: $output" echo "status: $status" assert_success } -@test "(git) git:unlock [missing arg]" { - run /bin/bash -c "dokku git:unlock" +@test "(git) git:load-image [normal-git-init]" { + run rm -rf "/home/dokku/$TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run mkdir "/home/dokku/$TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run chown -R dokku:dokku "/home/dokku/$TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image pull linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image.tar linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success +} + +@test "(git) git:load-image [normal-cnb]" { + run /bin/bash -c "docker image pull dokku/node-js-getting-started:latest" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image.tar dokku/node-js-getting-started:latest" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image rm dokku/node-js-getting-started:latest" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP dokku/node-js-getting-started:latest" + echo "output: $output" + echo "status: $status" + assert_success +} + +@test "(git) git:load-image [failing deploy]" { + local CUSTOM_TMP=$(mktemp -d "/tmp/${DOKKU_DOMAIN}.XXXXX") + trap 'popd &>/dev/null || true; rm -rf "$CUSTOM_TMP"' INT TERM + rmdir "$CUSTOM_TMP" && cp -r "${BATS_TEST_DIRNAME}/../../tests/apps/python" "$CUSTOM_TMP" + + run /bin/bash -c "docker image build -t dokku-test/$TEST_APP:latest -f $CUSTOM_TMP/alt.Dockerfile $CUSTOM_TMP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image build -t dokku-test/$TEST_APP:v2 --build-arg BUILD_ARG=value -f $CUSTOM_TMP/alt.Dockerfile $CUSTOM_TMP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image.tar dokku-test/$TEST_APP:latest" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image-2.tar dokku-test/$TEST_APP:v2" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image rm dokku-test/$TEST_APP:latest dokku-test/$TEST_APP:v2" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:latest" + echo "output: $output" + echo "status: $status" + assert_failure + + run /bin/bash -c "dokku config:get $TEST_APP FAIL_ON_STARTUP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "true" + + run /bin/bash -c "dokku git:status $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output "fatal: this operation must be run in a work tree" + + run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=false" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:latest" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image-2.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:v2" + echo "output: $output" + echo "status: $status" + assert_failure + + run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=false" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image-2.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:v2" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "No changes detected, skipping git commit" 0 +} + +@test "(git) git:load-image [onbuild]" { + local TMP=$(mktemp -d "/tmp/${DOKKU_DOMAIN}.XXXXX") + trap 'popd &>/dev/null || true; rm -rf "$TMP"' INT TERM + + run /bin/bash -c "dokku storage:mount $TEST_APP /var/run/docker.sock:/var/run/docker.sock" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image pull gliderlabs/logspout:v3.2.13" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image.tar gliderlabs/logspout:v3.2.13" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image rm gliderlabs/logspout:v3.2.13" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP gliderlabs/logspout:v3.2.13" + echo "output: $output" + echo "status: $status" + assert_failure + + cat <"$TMP/build.sh" +#!/bin/sh +set -e +apk add --update go build-base git mercurial ca-certificates +cd /src +go build -ldflags "-X main.Version=\$1" -o /bin/logspout +apk del go git mercurial build-base +rm -rf /root/go /var/cache/apk/* + +# backwards compatibility +ln -fs /tmp/docker.sock /var/run/docker.sock +EOF + + cat <"$TMP/modules.go" +package main + +import ( + _ "github.com/gliderlabs/logspout/adapters/multiline" + _ "github.com/gliderlabs/logspout/adapters/raw" + _ "github.com/gliderlabs/logspout/adapters/syslog" + _ "github.com/gliderlabs/logspout/healthcheck" + _ "github.com/gliderlabs/logspout/httpstream" + _ "github.com/gliderlabs/logspout/routesapi" + _ "github.com/gliderlabs/logspout/transports/tcp" + _ "github.com/gliderlabs/logspout/transports/tls" + _ "github.com/gliderlabs/logspout/transports/udp" +) +EOF + + run sudo chown -R dokku:dokku "$TMP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image --build-dir $TMP $TEST_APP gliderlabs/logspout:v3.2.13" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP gliderlabs/logspout:v3.2.13" echo "output: $output" echo "status: $status" assert_failure } + +@test "(git) git:load-image labels correctly" { + run /bin/bash -c "docker image pull linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image save -o /tmp/image.tar linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP linuxserver/foldingathome:7.6.21" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "docker image inspect dokku/$TEST_APP:latest --format '{{ index .Config.Labels \"com.dokku.docker-image-labeler/alternate-tags\" }}'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "linuxserver/foldingathome:7.6.21" +} diff --git a/tests/unit/git_7.bats b/tests/unit/git_7.bats index 03c81f264..be9ae8888 100644 --- a/tests/unit/git_7.bats +++ b/tests/unit/git_7.bats @@ -2,288 +2,50 @@ load test_helper +TEST_PLUGIN_APP=smoke-test-app +TEST_PLUGIN_GIT_REPO=https://github.com/dokku/${TEST_PLUGIN_APP}.git +TEST_PLUGIN_LOCAL_REPO="$(mktemp -d)/$TEST_PLUGIN_APP" + +clone_test_app() { + git clone "$TEST_PLUGIN_GIT_REPO" "$TEST_PLUGIN_LOCAL_REPO" +} + +remove_test_app() { + rm -rf $TEST_PLUGIN_LOCAL_REPO +} + setup() { global_setup create_app - touch /home/dokku/.ssh/known_hosts - chown dokku:dokku /home/dokku/.ssh/known_hosts + clone_test_app } teardown() { - docker image rm linuxserver/foldingathome:7.6.21 || true - docker image rm dokku/node-js-getting-started:latest || true - docker image rm dokku-test/$TEST_APP:latest || true - docker image rm dokku-test/$TEST_APP:v2 || true - docker image rm gliderlabs/logspout:v3.2.13 || true - rm -f /tmp/image.tar /tmp/image-2.tar - rm -f /home/dokku/.ssh/id_rsa.pub || true + remove_test_app || true destroy_app global_teardown } -@test "(git) git:load-image [normal]" { - run /bin/bash -c "docker image pull linuxserver/foldingathome:7.6.21" +@test "(git) push tags and branches" { + # https://github.com/dokku/dokku/issues/5188 + local GIT_REMOTE=${GIT_REMOTE:="dokku@${DOKKU_DOMAIN}:$TEST_APP"} + run git -C "$TEST_PLUGIN_LOCAL_REPO" remote add target "$GIT_REMOTE" echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "docker image save -o /tmp/image.tar linuxserver/foldingathome:7.6.21" + run git -C "$TEST_PLUGIN_LOCAL_REPO" push target 1.0.0:master echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21" + run git -C "$TEST_PLUGIN_LOCAL_REPO" push target 2.0.0:master -f echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP linuxserver/foldingathome:7.6.21" + run git -C "$TEST_PLUGIN_LOCAL_REPO" push target master -f echo "output: $output" echo "status: $status" assert_success } - -@test "(git) git:load-image [normal-git-init]" { - run rm -rf "/home/dokku/$TEST_APP" - echo "output: $output" - echo "status: $status" - assert_success - - run mkdir "/home/dokku/$TEST_APP" - echo "output: $output" - echo "status: $status" - assert_success - - run chown -R dokku:dokku "/home/dokku/$TEST_APP" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image pull linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image save -o /tmp/image.tar linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success -} - -@test "(git) git:load-image [normal-cnb]" { - run /bin/bash -c "docker image pull dokku/node-js-getting-started:latest" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image save -o /tmp/image.tar dokku/node-js-getting-started:latest" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image rm dokku/node-js-getting-started:latest" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP dokku/node-js-getting-started:latest" - echo "output: $output" - echo "status: $status" - assert_success -} - -@test "(git) git:load-image [failing deploy]" { - local CUSTOM_TMP=$(mktemp -d "/tmp/${DOKKU_DOMAIN}.XXXXX") - trap 'popd &>/dev/null || true; rm -rf "$CUSTOM_TMP"' INT TERM - rmdir "$CUSTOM_TMP" && cp -r "${BATS_TEST_DIRNAME}/../../tests/apps/python" "$CUSTOM_TMP" - - run /bin/bash -c "docker image build -t dokku-test/$TEST_APP:latest -f $CUSTOM_TMP/alt.Dockerfile $CUSTOM_TMP" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image build -t dokku-test/$TEST_APP:v2 --build-arg BUILD_ARG=value -f $CUSTOM_TMP/alt.Dockerfile $CUSTOM_TMP" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image save -o /tmp/image.tar dokku-test/$TEST_APP:latest" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image save -o /tmp/image-2.tar dokku-test/$TEST_APP:v2" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image rm dokku-test/$TEST_APP:latest dokku-test/$TEST_APP:v2" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=true" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:latest" - echo "output: $output" - echo "status: $status" - assert_failure - - run /bin/bash -c "dokku config:get $TEST_APP FAIL_ON_STARTUP" - echo "output: $output" - echo "status: $status" - assert_success - assert_output "true" - - run /bin/bash -c "dokku git:status $TEST_APP" - echo "output: $output" - echo "status: $status" - assert_failure - assert_output "fatal: this operation must be run in a work tree" - - run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=false" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:latest" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=true" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image-2.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:v2" - echo "output: $output" - echo "status: $status" - assert_failure - - run /bin/bash -c "dokku config:set --no-restart $TEST_APP FAIL_ON_STARTUP=false" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image-2.tar | dokku git:load-image $TEST_APP dokku-test/$TEST_APP:v2" - echo "output: $output" - echo "status: $status" - assert_success - assert_output_contains "No changes detected, skipping git commit" 0 -} - -@test "(git) git:load-image [onbuild]" { - local TMP=$(mktemp -d "/tmp/${DOKKU_DOMAIN}.XXXXX") - trap 'popd &>/dev/null || true; rm -rf "$TMP"' INT TERM - - run /bin/bash -c "dokku storage:mount $TEST_APP /var/run/docker.sock:/var/run/docker.sock" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image pull gliderlabs/logspout:v3.2.13" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image save -o /tmp/image.tar gliderlabs/logspout:v3.2.13" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image rm gliderlabs/logspout:v3.2.13" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP gliderlabs/logspout:v3.2.13" - echo "output: $output" - echo "status: $status" - assert_failure - - cat <"$TMP/build.sh" -#!/bin/sh -set -e -apk add --update go build-base git mercurial ca-certificates -cd /src -go build -ldflags "-X main.Version=\$1" -o /bin/logspout -apk del go git mercurial build-base -rm -rf /root/go /var/cache/apk/* - -# backwards compatibility -ln -fs /tmp/docker.sock /var/run/docker.sock -EOF - - cat <"$TMP/modules.go" -package main - -import ( - _ "github.com/gliderlabs/logspout/adapters/multiline" - _ "github.com/gliderlabs/logspout/adapters/raw" - _ "github.com/gliderlabs/logspout/adapters/syslog" - _ "github.com/gliderlabs/logspout/healthcheck" - _ "github.com/gliderlabs/logspout/httpstream" - _ "github.com/gliderlabs/logspout/routesapi" - _ "github.com/gliderlabs/logspout/transports/tcp" - _ "github.com/gliderlabs/logspout/transports/tls" - _ "github.com/gliderlabs/logspout/transports/udp" -) -EOF - - run sudo chown -R dokku:dokku "$TMP" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image --build-dir $TMP $TEST_APP gliderlabs/logspout:v3.2.13" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP gliderlabs/logspout:v3.2.13" - echo "output: $output" - echo "status: $status" - assert_failure -} - -@test "(git) git:load-image labels correctly" { - run /bin/bash -c "docker image pull linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image save -o /tmp/image.tar linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image rm linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "cat /tmp/image.tar | dokku git:load-image $TEST_APP linuxserver/foldingathome:7.6.21" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker image inspect dokku/$TEST_APP:latest --format '{{ index .Config.Labels \"com.dokku.docker-image-labeler/alternate-tags\" }}'" - echo "output: $output" - echo "status: $status" - assert_success - assert_output_contains "linuxserver/foldingathome:7.6.21" -} diff --git a/tests/unit/git_8.bats b/tests/unit/git_8.bats deleted file mode 100644 index be9ae8888..000000000 --- a/tests/unit/git_8.bats +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bats - -load test_helper - -TEST_PLUGIN_APP=smoke-test-app -TEST_PLUGIN_GIT_REPO=https://github.com/dokku/${TEST_PLUGIN_APP}.git -TEST_PLUGIN_LOCAL_REPO="$(mktemp -d)/$TEST_PLUGIN_APP" - -clone_test_app() { - git clone "$TEST_PLUGIN_GIT_REPO" "$TEST_PLUGIN_LOCAL_REPO" -} - -remove_test_app() { - rm -rf $TEST_PLUGIN_LOCAL_REPO -} - -setup() { - global_setup - create_app - clone_test_app -} - -teardown() { - remove_test_app || true - destroy_app - global_teardown -} - -@test "(git) push tags and branches" { - # https://github.com/dokku/dokku/issues/5188 - local GIT_REMOTE=${GIT_REMOTE:="dokku@${DOKKU_DOMAIN}:$TEST_APP"} - run git -C "$TEST_PLUGIN_LOCAL_REPO" remote add target "$GIT_REMOTE" - echo "output: $output" - echo "status: $status" - assert_success - - run git -C "$TEST_PLUGIN_LOCAL_REPO" push target 1.0.0:master - echo "output: $output" - echo "status: $status" - assert_success - - run git -C "$TEST_PLUGIN_LOCAL_REPO" push target 2.0.0:master -f - echo "output: $output" - echo "status: $status" - assert_success - - run git -C "$TEST_PLUGIN_LOCAL_REPO" push target master -f - echo "output: $output" - echo "status: $status" - assert_success -} diff --git a/tests/unit/plugin.bats b/tests/unit/plugin.bats index 10761acf8..9323bb417 100644 --- a/tests/unit/plugin.bats +++ b/tests/unit/plugin.bats @@ -1,24 +1,12 @@ #!/usr/bin/env bats load test_helper -TEST_PLUGIN_NAME=smoke-test-plugin -TEST_PLUGIN_GIT_REPO=https://github.com/dokku/${TEST_PLUGIN_NAME}.git -TEST_PLUGIN_LOCAL_REPO="$(mktemp -d)/$TEST_PLUGIN_NAME" - -clone_test_plugin() { - git clone "$TEST_PLUGIN_GIT_REPO" "$TEST_PLUGIN_LOCAL_REPO" -} setup() { global_setup clone_test_plugin } -remove_test_plugin() { - rm -rf $PLUGIN_ENABLED_PATH/$TEST_PLUGIN_NAME $PLUGIN_AVAILABLE_PATH/$TEST_PLUGIN_NAME - rm -rf $TEST_PLUGIN_LOCAL_REPO -} - teardown() { remove_test_plugin || true global_teardown diff --git a/tests/unit/ps-general-2.bats b/tests/unit/ps-general-2.bats index 70a869e43..379d7727d 100644 --- a/tests/unit/ps-general-2.bats +++ b/tests/unit/ps-general-2.bats @@ -111,7 +111,7 @@ teardown() { echo "output: $output" echo "status: $status" assert_failure - assert_output_contains "Could not start due to" + assert_output_contains "Could not start due to" 2 run /bin/bash -c "dokku ps:set $TEST_APP procfile-path second.Procfile" echo "output: $output" diff --git a/tests/unit/scheduler-docker-local.bats b/tests/unit/scheduler-docker-local.bats index ba3199a3b..d14ea9ed4 100644 --- a/tests/unit/scheduler-docker-local.bats +++ b/tests/unit/scheduler-docker-local.bats @@ -119,3 +119,59 @@ teardown() { assert_success assert_output_contains "docker-init" 0 } + +@test "(scheduler-docker-local) publish ports" { + run create_app + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Deploys may fail when publishing ports and scaling to multiple containers" 0 + assert_output_contains "Deploys may fail when publishing ports and enabling zero downtime" 0 + + run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '--publish 5000:5000'" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:scale --skip-deploy $TEST_APP web=2" + echo "output: $output" + echo "status: $status" + assert_success + + # the expected output will be seen twice due to how parallel re-outputs stderr in its own output... + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Deploys may fail when publishing ports and scaling to multiple containers" 2 + assert_output_contains "Deploys may fail when publishing ports and enabling zero downtime" 0 + + run /bin/bash -c "dokku ps:scale --skip-deploy $TEST_APP web=1" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_failure + assert_output_contains "Deploys may fail when publishing ports and scaling to multiple containers" 0 + assert_output_contains "Deploys may fail when publishing ports and enabling zero downtime" 2 + + run /bin/bash -c "dokku checks:disable $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "Deploys may fail when publishing ports and scaling to multiple containers" 0 + assert_output_contains "Deploys may fail when publishing ports and enabling zero downtime" 0 +} diff --git a/tests/unit/scheduler-k3s-1.bats b/tests/unit/scheduler-k3s-1.bats index b8a62e8d8..f9fbcd455 100644 --- a/tests/unit/scheduler-k3s-1.bats +++ b/tests/unit/scheduler-k3s-1.bats @@ -32,3 +32,33 @@ teardown_() { INGRESS_CLASS=nginx TAINT_SCHEDULING=true install_k3s } + +@test "(scheduler-k3s) deploy dockerfile exposed port" { + if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then + skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN" + fi + + INGRESS_CLASS=nginx install_k3s + + run /bin/bash -c "dokku apps:create $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku domains:set $TEST_APP $TEST_APP.dokku.me" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku git:from-image $TEST_APP metabase/metabase:latest" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "sleep 30" + echo "output: $output" + echo "status: $status" + assert_success + + assert_http_localhost_response_contains "http" "$TEST_APP.dokku.me" "80" "" "Metabase" +} diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index 831f94aa9..cb5af752b 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -15,6 +15,9 @@ UUID=$(uuidgen) TEST_APP="rdmtestapp-${UUID}" TEST_NETWORK="test-network-${UUID}" SKIPPED_TEST_ERR_MSG="previous test failed! skipping remaining tests..." +TEST_PLUGIN_NAME=smoke-test-plugin +TEST_PLUGIN_GIT_REPO=https://github.com/dokku/${TEST_PLUGIN_NAME}.git +TEST_PLUGIN_LOCAL_REPO="$(mktemp -d)/$TEST_PLUGIN_NAME" # global setup() and teardown() # skips remaining tests on first failure @@ -45,6 +48,15 @@ cleanup_containers() { fi } +clone_test_plugin() { + git clone "$TEST_PLUGIN_GIT_REPO" "$TEST_PLUGIN_LOCAL_REPO" +} + +remove_test_plugin() { + rm -rf "${PLUGIN_ENABLED_PATH:?}/$TEST_PLUGIN_NAME" "${PLUGIN_AVAILABLE_PATH:?}/$TEST_PLUGIN_NAME" + rm -rf "$TEST_PLUGIN_LOCAL_REPO" +} + # test functions flunk() { { @@ -238,6 +250,22 @@ assert_http_localhost_response() { fi } +assert_http_localhost_response_contains() { + local scheme="$1" domain="$2" port="${3:-80}" path="${4:-}" content="${5:-}" status_code="${6:-200}" + run curl --connect-to "$domain:$port:localhost:$port" -kSso /dev/null -w "%{http_code}" "$scheme://$domain:$port$path" + echo "curl: curl --connect-to $domain:$port:localhost:$port -kSso /dev/null -w %{http_code} $scheme://$domain:$port$path" + echo "output: $output" + echo "status: $status" + assert_output "$status_code" + + if [[ -n "$content" ]]; then + run curl --connect-to "$domain:$port:localhost:$port" -kSs "$scheme://$domain:$port$path" + echo "output: $output" + echo "status: $status" + assert_output_contains "$content" + fi +} + assert_ssl_domain() { local domain=$1 assert_app_domain "${domain}" diff --git a/tests/unit/traefik.bats b/tests/unit/traefik.bats index 835b974cd..efebbedcd 100644 --- a/tests/unit/traefik.bats +++ b/tests/unit/traefik.bats @@ -140,34 +140,6 @@ teardown() { assert_success } -@test "(traefik) traefik:set priority" { - run /bin/bash -c "dokku proxy:set $TEST_APP traefik" - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "dokku traefik:set $TEST_APP priority 12345" - echo "output: $output" - echo "status: $status" - assert_success - - run deploy_app - echo "output: $output" - echo "status: $status" - assert_success - - run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-http.loadbalancer.server.port\" }}'" - echo "output: $output" - echo "status: $status" - assert_output "5000" - - run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.routers.$TEST_APP-web-http.priority\" }}'" - echo "output: $output" - echo "status: $status" - assert_success - assert_output "12345" -} - @test "(traefik) ssl" { run /bin/bash -c "dokku builder-herokuish:set $TEST_APP allowed true" echo "output: $output"