diff --git a/docs/appendices/0.29.0-migration-guide.md b/docs/appendices/0.29.0-migration-guide.md index b02e83673..ee8cb8578 100644 --- a/docs/appendices/0.29.0-migration-guide.md +++ b/docs/appendices/0.29.0-migration-guide.md @@ -5,6 +5,8 @@ - The output of `run:detached` now uses the container name - eg. `node-js-app.run.1` - vs the container id. - The ID of `cron` tasks is now base36-encoded instead of base64-encoded. - The `nginx.conf.sigil` is now extracted when source code is extracted for a build and not from the built image. Users can specify alternative paths via the `nginx-conf-sigil-path` property of the `nginx` plugin. See the [nginx documentation](/docs/networking/proxies/nginx.md#customizing-the-nginx-configuration) for more information on how to configure the `nginx.conf.sigil` path for your application. +- The existing `pre-restore` hook has been renamed to `scheduler-pre-restore`. There is a new `pre-restore` hook that is triggered within the `ps:restore` command prior to restoring any apps. +- Nginx init commands are now performed via systemctl on Ubuntu systems when `/usr/bin/systemctl` is available. ## Removals diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 72293c3a3..eca55a663 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -1753,7 +1753,7 @@ APP="$1"; IMAGE_TAG="$2"; IMAGE=$(get_app_image_name $APP $IMAGE_TAG) - Description: Allows you to run commands before all containers are restored - Invoked by: `dokku ps:restore` -- Arguments: `$DOKKU_SCHEDULER $APP` +- Arguments: - Example: ```shell @@ -2187,6 +2187,25 @@ DOKKU_SCHEDULER="$1"; APP="$2"; # TODO ``` +### `scheduler-pre-restore` + +> Warning: The scheduler plugin trigger apis are under development and may change +> between minor releases until the 1.0 release. + +- Description: Allows you to run commands before an app is restored +- Invoked by: `dokku ps:restore` +- Arguments: `$DOKU_SCHEDULER $APP` +- Example: + +```shell +#!/usr/bin/env bash + +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +DOKKU_SCHEDULER="$1"; APP="$2"; + +# TODO +``` + ### `scheduler-post-delete` > Warning: The scheduler plugin trigger apis are under development and may change diff --git a/plugins/20_events/scheduler-pre-restore b/plugins/20_events/scheduler-pre-restore new file mode 120000 index 000000000..5178a749f --- /dev/null +++ b/plugins/20_events/scheduler-pre-restore @@ -0,0 +1 @@ +hook \ No newline at end of file diff --git a/plugins/caddy-vhosts/command-functions b/plugins/caddy-vhosts/command-functions index d7409da1e..9636ef451 100755 --- a/plugins/caddy-vhosts/command-functions +++ b/plugins/caddy-vhosts/command-functions @@ -131,6 +131,7 @@ cmd-caddy-start() { local TMP_COMPOSE_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_COMPOSE_FILE' >/dev/null" RETURN INT TERM EXIT + fn-plugin-property-write "caddy" "--global" "proxy-status" "started" fn-caddy-template-compose-file "$TMP_COMPOSE_FILE" "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p caddy up -d --quiet-pull } @@ -147,6 +148,7 @@ cmd-caddy-stop() { local TMP_COMPOSE_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_COMPOSE_FILE' >/dev/null" RETURN INT TERM EXIT + fn-plugin-property-write "caddy" "--global" "proxy-status" "stopped" fn-caddy-template-compose-file "$TMP_COMPOSE_FILE" "$DOCKER_BIN" compose -f "$TMP_COMPOSE_FILE" -p caddy down --remove-orphans } diff --git a/plugins/caddy-vhosts/pre-restore b/plugins/caddy-vhosts/pre-restore new file mode 100755 index 000000000..78f5cae59 --- /dev/null +++ b/plugins/caddy-vhosts/pre-restore @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/caddy-vhosts/command-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-caddy-pre-restore() { + declare desc="pre-restore the caddy proxy" + declare trigger="install" + + if [[ "$(fn-plugin-property-get "caddy" "--global" "proxy-status")" == "stopped" ]]; then + return + fi + + if ! cmd-caddy-start; then + dokku_log_warn "Failed to restore caddy proxy, requests may not route as expected" + fi +} + +trigger-caddy-pre-restore "$@" diff --git a/plugins/nginx-vhosts/command-functions b/plugins/nginx-vhosts/command-functions index e13b31652..215aaccc1 100755 --- a/plugins/nginx-vhosts/command-functions +++ b/plugins/nginx-vhosts/command-functions @@ -110,24 +110,26 @@ cmd-nginx-show-config() { cat "$DOKKU_ROOT/$APP/nginx.conf" } -cmd-nginx-stop() { - declare desc="stops the nginx server" - declare cmd="nginx:stop" - [[ "$1" == "$cmd" ]] && shift 1 - - touch "${DOKKU_LIB_ROOT}/data/nginx-vhosts/nginx.stopped" - fn-nginx-vhosts-nginx-init-cmd "stop" -} - cmd-nginx-start() { declare desc="starts the nginx server" declare cmd="nginx:start" [[ "$1" == "$cmd" ]] && shift 1 - rm -f "${DOKKU_LIB_ROOT}/data/nginx-vhosts/nginx.stopped" + fn-plugin-property-write "nginx" "--global" "proxy-status" "started" + fn-nginx-vhosts-nginx-init-cmd "enable" fn-nginx-vhosts-nginx-init-cmd "start" } +cmd-nginx-stop() { + declare desc="stops the nginx server" + declare cmd="nginx:stop" + [[ "$1" == "$cmd" ]] && shift 1 + + fn-plugin-property-write "nginx" "--global" "proxy-status" "stopped" + fn-nginx-vhosts-nginx-init-cmd "stop" + fn-nginx-vhosts-nginx-init-cmd "disable" +} + cmd-nginx-validate-config() { declare desc="validates and optionally cleans up invalid nginx configurations" declare cmd="nginx:validate-config" diff --git a/plugins/nginx-vhosts/install b/plugins/nginx-vhosts/install index 8713fc128..e5f0e7af4 100755 --- a/plugins/nginx-vhosts/install +++ b/plugins/nginx-vhosts/install @@ -69,19 +69,21 @@ trigger-nginx-vhosts-install() { local mode="0440" case "$DOKKU_DISTRO" in debian | raspbian) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d $NGINX_INIT_NAME reload, /usr/sbin/invoke-rc.d $NGINX_INIT_NAME start, /usr/sbin/invoke-rc.d $NGINX_INIT_NAME stop, $NGINX_BIN -t, ${NGINX_BIN} -t -c *" >"$NGINX_SUDOERS_FILE" + echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d $NGINX_INIT_NAME enable, /usr/sbin/invoke-rc.d $NGINX_INIT_NAME disable, /usr/sbin/invoke-rc.d $NGINX_INIT_NAME reload, /usr/sbin/invoke-rc.d $NGINX_INIT_NAME start, /usr/sbin/invoke-rc.d $NGINX_INIT_NAME stop, $NGINX_BIN -t, ${NGINX_BIN} -t -c *" >"$NGINX_SUDOERS_FILE" ;; ubuntu) if [[ -x /usr/bin/sv ]]; then - echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/sv reload $NGINX_INIT_NAME, /usr/bin/sv start $NGINX_INIT_NAME, /usr/bin/sv stop $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/sv enable $NGINX_INIT_NAME, /usr/bin/sv disable $NGINX_INIT_NAME, /usr/bin/sv reload $NGINX_INIT_NAME, /usr/bin/sv start $NGINX_INIT_NAME, /usr/bin/sv stop $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + elif [[ -x /usr/bin/systemctl ]]; then + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl enable $NGINX_INIT_NAME, /usr/bin/systemctl disable $NGINX_INIT_NAME, /usr/bin/systemctl reload $NGINX_INIT_NAME, /usr/bin/systemctl start $NGINX_INIT_NAME, /usr/bin/systemctl stop $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" else - echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/$NGINX_INIT_NAME reload, /etc/init.d/$NGINX_INIT_NAME start, /etc/init.d/$NGINX_INIT_NAME stop, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/$NGINX_INIT_NAME enable, /etc/init.d/$NGINX_INIT_NAME disable, /etc/init.d/$NGINX_INIT_NAME reload, /etc/init.d/$NGINX_INIT_NAME start, /etc/init.d/$NGINX_INIT_NAME stop, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" fi ;; arch) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, /usr/bin/systemctl start $NGINX_INIT_NAME, /usr/bin/systemctl stop $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl enable $NGINX_INIT_NAME, /usr/bin/systemctl disable $NGINX_INIT_NAME, /usr/bin/systemctl reload $NGINX_INIT_NAME, /usr/bin/systemctl start $NGINX_INIT_NAME, /usr/bin/systemctl stop $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" ;; esac @@ -130,10 +132,15 @@ trigger-nginx-vhosts-install() { fn-nginx-vhosts-migrate-env-vars fn-nginx-vhosts-migrate-nginx-conf-sigil + if [[ -f "${DOKKU_LIB_ROOT}/data/nginx-vhosts/nginx.stopped" ]]; then + rm -f "${DOKKU_LIB_ROOT}/data/nginx-vhosts/nginx.stopped" + fn-plugin-property-write "nginx" "--global" "proxy-status" "stopped" + fi + # avoid failing runit init calls on install # the runit binaries are not yet available during dockerfile building # and therefore both these calls will fail - if [[ ! -x /usr/bin/sv ]] && [[ ! -f "${DOKKU_LIB_ROOT}/data/nginx-vhosts/nginx.stopped" ]]; then + if [[ ! -x /usr/bin/sv ]] && [[ "$(fn-plugin-property-get "nginx" "--global" "proxy-status")" != "stopped" ]]; then fn-nginx-vhosts-nginx-init-cmd start || fn-nginx-vhosts-nginx-init-cmd reload fi } diff --git a/plugins/nginx-vhosts/internal-functions b/plugins/nginx-vhosts/internal-functions index e8eba5f71..7a6ae1e79 100755 --- a/plugins/nginx-vhosts/internal-functions +++ b/plugins/nginx-vhosts/internal-functions @@ -132,6 +132,10 @@ fn-nginx-vhosts-nginx-init-cmd() { # support docker-based installations if [[ -x /usr/bin/sv ]]; then sudo /usr/bin/sv "$CMD" "$NGINX_INIT_NAME" + elif [[ -x /usr/bin/systemctl ]]; then + sudo /usr/bin/systemctl "$CMD" "$NGINX_INIT_NAME" + elif [[ "$CMD" == "enable" ]] || [[ "$CMD" == "disable" ]]; then + dokku_log_warn "Running $CMD is not possible for init.d managed services" else sudo "/etc/init.d/$NGINX_INIT_NAME" "$CMD" fi diff --git a/plugins/nginx-vhosts/pre-restore b/plugins/nginx-vhosts/pre-restore new file mode 100755 index 000000000..b7de63b37 --- /dev/null +++ b/plugins/nginx-vhosts/pre-restore @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/command-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-nginx-pre-restore() { + declare desc="pre-restore the nginx proxy" + declare trigger="install" + + if [[ "$(fn-plugin-property-get "nginx" "--global" "proxy-status")" == "stopped" ]]; then + return + fi + + if ! cmd-nginx-start; then + dokku_log_warn "Failed to restore nginx proxy, requests may not route as expected" + fi +} + +trigger-nginx-pre-restore "$@" diff --git a/plugins/ps/ps.go b/plugins/ps/ps.go index 9d86e297b..0428edaa0 100644 --- a/plugins/ps/ps.go +++ b/plugins/ps/ps.go @@ -115,8 +115,8 @@ func RestartProcess(appName string, processName string) error { // 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("pre-restore", []string{scheduler, appName}...); err != nil { - return fmt.Errorf("Error running pre-restore: %s", err) + if err := common.PlugnTrigger("scheduler-pre-restore", []string{scheduler, appName}...); err != nil { + return fmt.Errorf("Error running scheduler-pre-restore: %s", err) } common.LogInfo1("Clearing potentially invalid proxy configuration") diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index 442ffe062..02aeb2058 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -74,6 +74,10 @@ 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 { + return fmt.Errorf("Error running pre-restore: %s", err) + } + if allApps { if err := restorePrep(); err != nil { return err diff --git a/plugins/scheduler-docker-local/pre-restore b/plugins/scheduler-docker-local/scheduler-pre-restore similarity index 67% rename from plugins/scheduler-docker-local/pre-restore rename to plugins/scheduler-docker-local/scheduler-pre-restore index db4e8f34f..6a88d8ea4 100755 --- a/plugins/scheduler-docker-local/pre-restore +++ b/plugins/scheduler-docker-local/scheduler-pre-restore @@ -3,9 +3,9 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -trigger-scheduler-docker-local-pre-restore() { - declare desc="scheduler-docker-local pre-restore plugin trigger" - declare trigger="pre-restore" +trigger-scheduler-docker-local-scheduler-pre-restore() { + declare desc="scheduler-docker-local scheduler-pre-restore plugin trigger" + declare trigger="scheduler-pre-restore" declare DOKKU_SCHEDULER="$1" if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then @@ -17,4 +17,4 @@ trigger-scheduler-docker-local-pre-restore() { "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --format "{{.Names}}" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet | grep -E '(.+\..+\.[0-9]+\.[0-9]+$)') &>/dev/null || true } -trigger-scheduler-docker-local-pre-restore "$@" +trigger-scheduler-docker-local-scheduler-pre-restore "$@" diff --git a/plugins/traefik-vhosts/command-functions b/plugins/traefik-vhosts/command-functions index af59aaaef..6136fd178 100755 --- a/plugins/traefik-vhosts/command-functions +++ b/plugins/traefik-vhosts/command-functions @@ -135,6 +135,7 @@ cmd-traefik-start() { local TMP_COMPOSE_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_COMPOSE_FILE' >/dev/null" RETURN INT TERM EXIT + fn-plugin-property-write "traefik" "--global" "proxy-status" "started" touch "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" chmod 600 "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" fn-traefik-template-compose-file "$TMP_COMPOSE_FILE" @@ -153,6 +154,7 @@ cmd-traefik-stop() { local TMP_COMPOSE_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_COMPOSE_FILE' >/dev/null" RETURN INT TERM EXIT + fn-plugin-property-write "traefik" "--global" "proxy-status" "stopped" touch "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" chmod 600 "${DOKKU_LIB_ROOT}/data/traefik/traefik-acme.json" fn-traefik-template-compose-file "$TMP_COMPOSE_FILE" diff --git a/plugins/traefik-vhosts/pre-restore b/plugins/traefik-vhosts/pre-restore new file mode 100755 index 000000000..7b522d76f --- /dev/null +++ b/plugins/traefik-vhosts/pre-restore @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/traefik-vhosts/command-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-traefik-pre-restore() { + declare desc="pre-restore the traefik proxy" + declare trigger="install" + + if [[ "$(fn-plugin-property-get "traefik" "--global" "proxy-status")" == "stopped" ]]; then + return + fi + + if ! cmd-traefik-start; then + dokku_log_warn "Failed to restore traefik proxy, requests may not route as expected" + fi +} + +trigger-traefik-pre-restore "$@" diff --git a/tests/unit/traefik.bats b/tests/unit/traefik.bats index 5901a01e3..4c3b0e82c 100644 --- a/tests/unit/traefik.bats +++ b/tests/unit/traefik.bats @@ -104,6 +104,12 @@ teardown() { 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" { @@ -112,11 +118,6 @@ teardown() { 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 /bin/bash -c "dokku proxy:set $TEST_APP traefik" echo "output: $output" echo "status: $status" @@ -127,13 +128,13 @@ teardown() { 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-12345.loadbalancer.server.port\" }}'" + 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_success assert_output "5000" - run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-https-12345.loadbalancer.server.port\" }}'" + run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-https.loadbalancer.server.port\" }}'" echo "output: $output" echo "status: $status" assert_success @@ -164,13 +165,13 @@ teardown() { 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-12345.loadbalancer.server.port\" }}'" + 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_success assert_output "5000" - run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-https-12345.loadbalancer.server.port\" }}'" + run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-https.loadbalancer.server.port\" }}'" echo "output: $output" echo "status: $status" assert_success