Merge branch 'upcoming' of github.com:dokku/dokku into upcoming

This commit is contained in:
Jose Diaz-Gonzalez
2019-10-07 18:55:29 -05:00
154 changed files with 1998 additions and 1494 deletions

View File

@@ -1,14 +1,15 @@
#!/usr/bin/env bash
[[ " help help:help run:help trace:help url:help urls:help version:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
[[ " help help:help cleanup:help run:help trace:help url:help urls:help version:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
case "$1" in
help | run:help | trace:help | url:help | urls:help | version:help)
help | cleanup:help | run:help | trace:help | url:help | urls:help | version:help)
[[ $(echo "$1" | sed '/.*:help/!d') ]] && help_topic="${1%\:help}"
help_content_func() {
declare desc="return standard plugin help content"
cat <<help_content
cleanup [<app>], Cleans up exited/dead Docker containers and removes dangling images
run [--env KEY=VALUE] <app> <cmd>, Run a command in a new container using the current application image
url <app>, Show the first URL for an application (compatibility)
urls <app>, Show all URLs for an application

View File

@@ -14,10 +14,10 @@ dokku_report_cmd() {
dokku_log_info1 "docker version: "
"$DOCKER_BIN" version | sed "s/^/ /"
dokku_log_info1 "docker daemon info: "
"$DOCKER_BIN" -D info | sed "s/^/ /"
"$DOCKER_BIN" -D system info | sed "s/^/ /"
dokku_log_info1 "sigil version: $(sigil -v)"
dokku_log_info1 "herokuish version: "
"$DOCKER_BIN" run $DOKKU_GLOBAL_RUN_ARGS --rm "$DOKKU_IMAGE" herokuish version | sed "s/^/ /"
"$DOCKER_BIN" container run $DOKKU_GLOBAL_RUN_ARGS --rm "$DOKKU_IMAGE" herokuish version | sed "s/^/ /"
dokku_log_info1 "dokku version: $(dokku version)"
dokku_log_info1 "dokku plugins: "
dokku plugin:list | sed "s/^/ /"

View File

@@ -17,7 +17,7 @@ get_phase_script() {
return 0
fi
get_json_value "scripts.dokku.${PHASE_SCRIPT_KEY}" <"$APP_JSON_FILE"
get_json_value ".scripts.dokku.${PHASE_SCRIPT_KEY}" <"$APP_JSON_FILE"
}
get_release_cmd() {
@@ -98,8 +98,8 @@ execute_script() {
DOKKU_APP_SHELL="$(config_get "$APP" DOKKU_APP_SHELL || echo "$DOKKU_APP_SHELL")"
[[ -z "$DOKKU_APP_SHELL" ]] && DOKKU_APP_SHELL="/bin/bash"
id=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -e DOKKU_TRACE="$DOKKU_TRACE" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_HOST_DIR:/cache" "${ARG_ARRAY[@]}" "$IMAGE" "$DOKKU_APP_SHELL" -c "$COMMAND")
if test "$("$DOCKER_BIN" wait "$id")" -ne 0; then
id=$("$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --env DOKKU_TRACE="$DOKKU_TRACE" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_HOST_DIR:/cache" "${ARG_ARRAY[@]}" "$IMAGE" "$DOKKU_APP_SHELL" -c "$COMMAND")
if test "$("$DOCKER_BIN" container wait "$id")" -ne 0; then
dokku_container_log_verbose_quiet "$id"
dokku_log_fail "execution of '$SCRIPT_CMD' failed!"
fi
@@ -121,5 +121,5 @@ execute_script() {
local DOCKER_COMMIT_ARGS="$DOCKER_COMMIT_ENTRYPOINT_CHANGE_ARG $DOCKER_COMMIT_CMD_CHANGE_ARG"
fi
eval "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "${DOCKER_COMMIT_ARGS[@]}" "$id" "$IMAGE" >/dev/null
eval "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "${DOCKER_COMMIT_ARGS[@]}" "$id" "$IMAGE" >/dev/null
}

View File

@@ -34,7 +34,7 @@ apps_destroy() {
fi
fi
echo "Destroying $APP (including all add-ons)"
dokku_log_info1 "Destroying $APP (including all add-ons)"
plugn trigger pre-delete "$APP" "$IMAGE_TAG"
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")

View File

@@ -16,7 +16,7 @@ app_post_delete() {
fi
# shellcheck disable=SC2046
"$DOCKER_BIN" rmi $("$DOCKER_BIN" images -q "$IMAGE_REPO" | xargs) &>/dev/null || true
"$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --quiet "$IMAGE_REPO" | xargs) &>/dev/null || true
}
app_post_delete "$@"

View File

@@ -46,7 +46,7 @@ apps_clone_cmd() {
plugn trigger post-app-clone-setup "$OLD_APP" "$NEW_APP"
if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then
"$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm -v "$NEW_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache
"$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"

View File

@@ -18,7 +18,7 @@ apps_rename_cmd() {
local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$OLD_APP"
if [[ -d "$OLD_CACHE_DIR" ]] && ! rmdir "$OLD_CACHE_DIR" >/dev/null 2>&1; then
"$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm -v "$OLD_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache
"$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"
apps_create "$NEW_APP"

View File

@@ -37,7 +37,7 @@ trigger-builder-build-builder-dockerfile() {
declare -a ARG_ARRAY
eval "ARG_ARRAY=($DOCKER_ARGS)"
"$DOCKER_BIN" build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE .
"$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE .
plugn trigger post-build-dockerfile "$APP"
}

View File

@@ -28,13 +28,13 @@ trigger-builder-build-builder-herokuish() {
NEW_DOKKU_IMAGE=$(plugn trigger builder-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE")
[[ -n "$NEW_DOKKU_IMAGE" ]] && DOKKU_IMAGE="$NEW_DOKKU_IMAGE"
CID=$(tar -c . | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app")
if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then
CID=$(tar -c . | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app")
if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then
dokku_log_warn "Failure extracting app code"
return 1
fi
"$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
[[ -d $DOKKU_APP_CACHE_DIR ]] || mkdir -p "$DOKKU_APP_CACHE_DIR"
plugn trigger pre-build-buildpack "$APP" "$SOURCECODE_WORK_DIR"
@@ -45,14 +45,14 @@ trigger-builder-build-builder-herokuish() {
declare -a ARG_ARRAY
eval "ARG_ARRAY=($DOCKER_ARGS)"
# shellcheck disable=SC2086
CID=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d -v $DOKKU_APP_HOST_CACHE_DIR:/cache -e CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build)
"$DOCKER_BIN" attach "$CID"
if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then
CID=$("$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d -v $DOKKU_APP_HOST_CACHE_DIR:/cache -e CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build)
"$DOCKER_BIN" container attach "$CID"
if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then
dokku_log_warn "Failure during app build"
return 1
fi
"$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
plugn trigger post-build-buildpack "$APP" "$SOURCECODE_WORK_DIR"
}

View File

@@ -19,22 +19,22 @@ trigger-builder-release-builder-herokuish() {
plugn trigger pre-release-buildpack "$APP" "$IMAGE_TAG"
if [[ -n $(config_export global) ]]; then
CID=$(config_export global | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh")
if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then
CID=$(config_export global | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh")
if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then
dokku_log_warn "Failure injecting global environment variables"
return 1
fi
"$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
fi
if [[ -n $(config_export app "$APP") ]]; then
CID=$(config_export app "$APP" | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh")
if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then
CID=$(config_export app "$APP" | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh")
if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then
dokku_log_warn "Failure injecting app environment variables"
return 1
fi
"$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
fi
plugn trigger post-release-buildpack "$APP" "$IMAGE_TAG"
}

View File

@@ -22,22 +22,22 @@ trigger-pre-build-buildpack-builder-herokuish() {
dokku_log_info1 "Adding BUILD_ENV to build environment..."
# create build env files for use in buildpacks like this:
# https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34
CID=$(config_bundle --merged "$APP" | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; cat | tar -x -C /tmp/env")
if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then
CID=$(config_bundle --merged "$APP" | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; cat | tar -x -C /tmp/env")
if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then
dokku_log_warn "Failure injecting BUILD_ENV into build environment"
return 1
fi
"$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
# create build env for 'old style' buildpacks and dokku plugins
CID=$(config_export app "$APP" --format envfile --merged | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env")
if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then
CID=$(config_export app "$APP" --format envfile --merged | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env")
if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then
dokku_log_warn "Failure injecting old-style BUILD_ENV"
return 1
fi
"$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
"$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null
}
trigger-pre-build-buildpack-builder-herokuish "$@"

View File

@@ -1,6 +1,7 @@
/commands
/subcommands/*
/triggers/*
/triggers
/install
/post-delete
/post-extract

View File

@@ -1,37 +1,6 @@
include ../../common.mk
GO_ARGS ?= -a
SUBCOMMANDS = subcommands/add subcommands/clear subcommands/list subcommands/remove subcommands/report subcommands/set
TRIGGERS = triggers/install triggers/post-delete triggers/post-extract triggers/report
build-in-docker: clean
docker run --rm \
-v $$PWD/../..:$(GO_REPO_ROOT) \
-w $(GO_REPO_ROOT)/plugins/buildpacks \
$(BUILD_IMAGE) \
bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$?
BUILD = commands subcommands triggers
PLUGIN_NAME = buildpacks
build: commands subcommands triggers
$(MAKE) triggers-copy
commands: **/**/commands.go
go build $(GO_ARGS) -o commands src/commands/commands.go
subcommands: $(SUBCOMMANDS)
subcommands/%: src/subcommands/*/%.go
go build $(GO_ARGS) -o $@ $<
clean:
rm -rf commands subcommands triggers install post-delete post-extract report
src-clean:
rm -rf .gitignore src triggers vendor Makefile *.go glide.*
triggers: $(TRIGGERS)
triggers/%: src/triggers/*/%.go
go build $(GO_ARGS) -o $@ $<
triggers-copy:
cp triggers/* .
include ../../common.mk

View File

@@ -1,19 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
func main() {
args := flag.NewFlagSet("buildpacks:add", flag.ExitOnError)
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
args.Parse(os.Args[2:])
err := buildpacks.CommandAdd(args.Args(), *index)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
func main() {
args := flag.NewFlagSet("buildpacks:clear", flag.ExitOnError)
args.Parse(os.Args[2:])
err := buildpacks.CommandClear(args.Args())
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,14 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/buildpacks"
)
func main() {
args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError)
args.Parse(os.Args[2:])
buildpacks.CommandList(args.Args())
}

View File

@@ -1,19 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
func main() {
args := flag.NewFlagSet("buildpacks:remove", flag.ExitOnError)
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
args.Parse(os.Args[2:])
err := buildpacks.CommandRemove(args.Args(), *index)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,34 +0,0 @@
package main
import (
"flag"
"strings"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
// displays a buildpacks report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
if strings.HasPrefix(appName, "--") {
infoFlag = appName
appName = ""
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
buildpacks.ReportSingleApp(appName, infoFlag)
}
return
}
buildpacks.ReportSingleApp(appName, infoFlag)
}

View File

@@ -1,19 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
func main() {
args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError)
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
args.Parse(os.Args[2:])
err := buildpacks.CommandSet(args.Args(), *index)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -0,0 +1,55 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
// main entrypoint to all subcommands
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
var err error
switch subcommand {
case "add":
args := flag.NewFlagSet("buildpacks:add", flag.ExitOnError)
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
args.Parse(os.Args[2:])
err = buildpacks.CommandAdd(args.Args(), *index)
case "clear":
args := flag.NewFlagSet("buildpacks:clear", flag.ExitOnError)
args.Parse(os.Args[2:])
err = buildpacks.CommandClear(args.Args())
case "list":
args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError)
args.Parse(os.Args[2:])
buildpacks.CommandList(args.Args())
case "remove":
args := flag.NewFlagSet("buildpacks:remove", flag.ExitOnError)
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
args.Parse(os.Args[2:])
err = buildpacks.CommandRemove(args.Args(), *index)
case "report":
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
buildpacks.CommandReport(appName, infoFlag)
case "set":
args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError)
index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs")
args.Parse(os.Args[2:])
err = buildpacks.CommandSet(args.Args(), *index)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,14 +0,0 @@
package main
import (
"fmt"
"github.com/dokku/dokku/plugins/common"
)
// runs the install step for the buildpacks plugin
func main() {
if err := common.PropertySetup("buildpacks"); err != nil {
common.LogFail(fmt.Sprintf("Unable to install the buildpacks plugin: %s", err.Error()))
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
)
// destroys the buildpacks property for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
err := common.PropertyDestroy("buildpacks", appName)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,15 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/buildpacks"
)
// displays a buildpacks report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(0)
buildpacks.ReportSingleApp(appName, "")
}

View File

@@ -0,0 +1,35 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/buildpacks"
"github.com/dokku/dokku/plugins/common"
)
// main entrypoint to all triggers
func main() {
parts := strings.Split(os.Args[0], "/")
trigger := parts[len(parts)-1]
flag.Parse()
switch trigger {
case "install":
buildpacks.TriggerInstall()
case "post-delete":
appName := flag.Arg(0)
buildpacks.TriggerPostDelete(appName)
case "post-extract":
appName := flag.Arg(0)
sourceWorkDir := flag.Arg(1)
buildpacks.TriggerPostExtract(appName, sourceWorkDir)
case "report":
appName := flag.Arg(0)
buildpacks.ReportSingleApp(appName, "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}
}

View File

@@ -3,6 +3,7 @@ package buildpacks
import (
"errors"
"fmt"
"strings"
"github.com/dokku/dokku/plugins/common"
)
@@ -115,6 +116,27 @@ func CommandRemove(args []string, index int) (err error) {
return
}
// CommandReport displays a buildpacks report for one or more apps
func CommandReport(appName string, infoFlag string) {
if strings.HasPrefix(appName, "--") {
infoFlag = appName
appName = ""
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
ReportSingleApp(appName, infoFlag)
}
return
}
ReportSingleApp(appName, infoFlag)
}
// CommandSet implements buildpacks:set
func CommandSet(args []string, index int) (err error) {
var appName string

View File

@@ -1,8 +1,7 @@
package main
package buildpacks
import (
"bufio"
"flag"
"fmt"
"os"
"path"
@@ -10,12 +9,23 @@ import (
"github.com/dokku/dokku/plugins/common"
)
// writes a .buildpacks file into the app
func main() {
flag.Parse()
appName := flag.Arg(0)
tmpWorkDir := flag.Arg(1)
// TriggerInstall runs the install step for the buildpacks plugin
func TriggerInstall() {
if err := common.PropertySetup("buildpacks"); err != nil {
common.LogFail(fmt.Sprintf("Unable to install the buildpacks plugin: %s", err.Error()))
}
}
// TriggerPostDelete destroys the buildpacks property for a given app container
func TriggerPostDelete(appName string) {
err := common.PropertyDestroy("buildpacks", appName)
if err != nil {
common.LogFail(err.Error())
}
}
// TriggerPostExtract writes a .buildpacks file into the app
func TriggerPostExtract(appName string, sourceWorkDir string) {
buildpacks, err := common.PropertyListGet("buildpacks", appName, "buildpacks")
if err != nil {
return
@@ -25,7 +35,7 @@ func main() {
return
}
buildpacksPath := path.Join(tmpWorkDir, ".buildpacks")
buildpacksPath := path.Join(sourceWorkDir, ".buildpacks")
file, err := os.OpenFile(buildpacksPath, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0600)
if err != nil {
common.LogFail(fmt.Sprintf("Error writing .buildpacks file: %s", err.Error()))

View File

@@ -325,7 +325,7 @@ func VerifyAppName(appName string) (err error) {
// VerifyImage returns true if docker image exists in local repo
func VerifyImage(image string) bool {
imageCmd := NewShellCmd(strings.Join([]string{DockerBin(), "inspect", image}, " "))
imageCmd := NewShellCmd(strings.Join([]string{DockerBin(), "image", "inspect", image}, " "))
imageCmd.ShowOutput = false
return imageCmd.Execute()
}

View File

@@ -171,7 +171,7 @@ dokku_container_log_verbose_quiet() {
OIFS=$IFS
IFS=$'\n'
local line
for line in $("$DOCKER_BIN" logs "$CID" 2>&1); do
for line in $("$DOCKER_BIN" container logs "$CID" 2>&1); do
dokku_log_verbose_quiet "$line"
done
IFS=$OIFS
@@ -203,7 +203,7 @@ verify_app_name() {
verify_image() {
declare desc="verify image existence"
local IMAGE="$1"
if "$DOCKER_BIN" inspect "$IMAGE" &>/dev/null; then
if "$DOCKER_BIN" image inspect "$IMAGE" &>/dev/null; then
return 0
else
return 1
@@ -286,7 +286,7 @@ get_running_image_tag() {
verify_app_name "$APP"
local CIDS=($(get_app_container_ids "$APP"))
local RUNNING_IMAGE_TAG=$("$DOCKER_BIN" inspect -f '{{ .Config.Image }}' "${CIDS[0]}" 2>/dev/null | awk -F: '{ print $2 }' || echo '')
local RUNNING_IMAGE_TAG=$("$DOCKER_BIN" container inspect --format '{{ .Config.Image }}' "${CIDS[0]}" 2>/dev/null | awk -F: '{ print $2 }' || echo '')
echo "$RUNNING_IMAGE_TAG"
}
@@ -300,13 +300,13 @@ is_image_herokuish_based() {
fi
# due to how the build process works, all herokuish images have the Environment variable USER=herokuishuser
USER_VALUE="$("$DOCKER_BIN" inspect -f '{{range .Config.Env}}{{if eq . "USER=herokuishuser" }}{{println .}}{{end}}{{end}}' "$IMAGE")"
USER_VALUE="$("$DOCKER_BIN" image inspect --format '{{range .Config.Env}}{{if eq . "USER=herokuishuser" }}{{println .}}{{end}}{{end}}' "$IMAGE")"
[[ "$USER_VALUE" == "" ]] && return 1
return 0
}
get_docker_version() {
CLIENT_VERSION_STRING="$("$DOCKER_BIN" version -f="{{ .Client.Version }}")"
CLIENT_VERSION_STRING="$("$DOCKER_BIN" version --format "{{ .Client.Version }}")"
echo "$CLIENT_VERSION_STRING"
}
@@ -336,6 +336,8 @@ parse_args() {
local next_index=1
local skip=false
local args=("$@")
local flags
for arg in "$@"; do
if [[ "$skip" == "true" ]]; then
next_index=$((next_index + 1))
@@ -364,8 +366,22 @@ parse_args() {
skip=true
;;
esac
if [[ "$skip" == "true" ]]; then
flags="${flags} ${arg}"
elif [[ "$arg" == "--app" ]]; then
flags="${flags} ${arg}=${args[$next_index]}"
elif [[ "$arg" =~ ^--.* ]]; then
flags="${flags} ${arg}"
fi
next_index=$((next_index + 1))
done
if [[ -z "$DOKKU_GLOBAL_FLAGS" ]]; then
export DOKKU_GLOBAL_FLAGS="$(echo -e "${flags}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
fi
return 0
}
@@ -382,7 +398,7 @@ copy_from_image() {
if is_image_herokuish_based "$IMAGE"; then
WORKDIR="/app"
else
WORKDIR="$("$DOCKER_BIN" inspect -f '{{.Config.WorkingDir}}' "$IMAGE")"
WORKDIR="$("$DOCKER_BIN" image inspect --format '{{.Config.WorkingDir}}' "$IMAGE")"
fi
if [[ -n "$WORKDIR" ]]; then
@@ -393,9 +409,9 @@ copy_from_image() {
TMP_FILE_COMMAND_OUTPUT=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
trap "rm -rf '$TMP_FILE_COMMAND_OUTPUT' >/dev/null 2>&1 || true" RETURN
local CID=$("$DOCKER_BIN" create "${DOCKER_CREATE_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "$IMAGE")
"$DOCKER_BIN" cp "$CID:$SRC_FILE" "$TMP_FILE_COMMAND_OUTPUT" 2>/dev/null || true
"$DOCKER_BIN" rm -f "$CID" &>/dev/null
local CID=$("$DOCKER_BIN" container create "${DOCKER_CREATE_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "$IMAGE")
"$DOCKER_BIN" container cp "$CID:$SRC_FILE" "$TMP_FILE_COMMAND_OUTPUT" 2>/dev/null || true
"$DOCKER_BIN" container rm --force "$CID" &>/dev/null
# docker cp exits with status 1 when run as non-root user when it tries to chown the file
# after successfully copying the file. Thus, we suppress stderr.
@@ -492,7 +508,7 @@ is_container_running() {
local CONTAINER_STATUS
dokku_log_warn "Deprecated: common#is_container_status"
CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f '{{.State.Running}}' "$CID" || true)
CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Running}}' "$CID" || true)
if [[ "$CONTAINER_STATUS" == "true" ]]; then
return 0
@@ -505,7 +521,7 @@ is_container_status() {
declare desc="return 0 if given docker container id is in given state"
local CID=$1
local TEMPLATE="{{.State.$2}}"
local CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f "$TEMPLATE" "$CID" 2>/dev/null || true)
local CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format "$TEMPLATE" "$CID" 2>/dev/null || true)
if [[ "$CONTAINER_STATUS" == "true" ]]; then
return 0
@@ -522,7 +538,7 @@ is_app_running() {
dokku_log_warn "Deprecated: ps#fn-is-app-running"
verify_app_name "$APP"
local APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP")
local APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null)
if [[ -n "$APP_RUNNING_CONTAINER_IDS" ]]; then
return 0
@@ -641,30 +657,30 @@ docker_cleanup() {
if [[ -n "$APP" ]]; then
# delete all non-running containers
# shellcheck disable=SC2046
"$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=exited" -f "label=$DOKKU_CONTAINER_LABEL" -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true
# delete all dead containers
# shellcheck disable=SC2046
"$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=dead" -f "label=$DOKKU_CONTAINER_LABEL" -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true
# delete danging images
# shellcheck disable=SC2046
"$DOCKER_BIN" rmi $("$DOCKER_BIN" images -f 'dangling=true' -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true
"$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true
# delete unused images
"$DOCKER_BIN" image prune --all --filter "label=com.dokku.app-name=$APP" --force &>/dev/null || true
else
# delete all non-running containers
# shellcheck disable=SC2046
"$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=exited" -f "label=$DOKKU_CONTAINER_LABEL" -q) &>/dev/null || true
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true
# delete all dead containers
# shellcheck disable=SC2046
"$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=dead" -f "label=$DOKKU_CONTAINER_LABEL" -q) &>/dev/null || true
"$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true
# delete danging images
# shellcheck disable=SC2046
"$DOCKER_BIN" rmi $("$DOCKER_BIN" images -f 'dangling=true' -q) &>/dev/null || true
"$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --quiet) &>/dev/null || true
fi
}
@@ -747,7 +763,7 @@ get_exposed_ports_from_image() {
local IMAGE="$1"
verify_image "$IMAGE"
# shellcheck disable=SC2016
local DOCKER_IMAGE_EXPOSED_PORTS="$("$DOCKER_BIN" inspect -f '{{range $key, $value := .Config.ExposedPorts}}{{$key}} {{end}}' "$IMAGE")"
local DOCKER_IMAGE_EXPOSED_PORTS="$("$DOCKER_BIN" image inspect --format '{{range $key, $value := .Config.ExposedPorts}}{{$key}} {{end}}' "$IMAGE")"
echo "$DOCKER_IMAGE_EXPOSED_PORTS"
}
@@ -755,7 +771,7 @@ get_entrypoint_from_image() {
declare desc="return .Config.Entrypoint from passed image name"
local IMAGE="$1"
verify_image "$IMAGE"
local DOCKER_IMAGE_ENTRYPOINT="$("$DOCKER_BIN" inspect --format '{{range .Config.Entrypoint}}{{.}} {{end}}' "$IMAGE")"
local DOCKER_IMAGE_ENTRYPOINT="$("$DOCKER_BIN" image inspect --format '{{range .Config.Entrypoint}}{{.}} {{end}}' "$IMAGE")"
echo "ENTRYPOINT $DOCKER_IMAGE_ENTRYPOINT"
}
@@ -763,7 +779,7 @@ get_cmd_from_image() {
declare desc="return .Config.Cmd from passed image name"
local IMAGE="$1"
verify_image "$IMAGE"
local DOCKER_IMAGE_CMD="$("$DOCKER_BIN" inspect --format '{{range .Config.Cmd}}{{.}} {{end}}' "$IMAGE")"
local DOCKER_IMAGE_CMD="$("$DOCKER_BIN" image inspect --format '{{range .Config.Cmd}}{{.}} {{end}}' "$IMAGE")"
DOCKER_IMAGE_CMD="${DOCKER_IMAGE_CMD/\/bin\/sh -c/}"
echo "CMD $DOCKER_IMAGE_CMD"
}
@@ -801,7 +817,7 @@ get_container_ports() {
local cid
for cid in $APP_CIDS; do
local container_ports="$("$DOCKER_BIN" port "$cid" | awk '{ print $3 "->" $1}' | awk -F ":" '{ print $2 }')"
local container_ports="$("$DOCKER_BIN" container port "$cid" | awk '{ print $3 "->" $1}' | awk -F ":" '{ print $2 }')"
done
echo "$container_ports"
@@ -907,24 +923,10 @@ internal_get_app_urls() {
get_json_value() {
declare desc="return value of provided json key from a json stream on stdin"
# JSON_NODE should be expresses as either a top-level object that has no children
# or in the format of json.node.path
# or in the format of .json.node.path
local JSON_NODE="$1"
local JSON_NODE=${JSON_NODE//\./\"][\"}
local JSON_NODE="[\"${JSON_NODE}\"]"
cat | python2.7 -c 'import json,sys;obj=json.load(sys.stdin);print json.dumps(obj'"${JSON_NODE}"').strip("\"")'
}
get_json_keys() {
declare desc="return space-separated list of json keys from json provided on stdin"
# JSON_NODE should be expressed as json.node.path and is expected to have children
local JSON_NODE="$1"
local JSON_NODE=${JSON_NODE//\./\"][\"}
local JSON_NODE="[\"${JSON_NODE}\"]"
if [[ "$JSON_NODE" == "[\"\"]" ]]; then
cat | python2.7 -c 'import json,sys;obj=json.load(sys.stdin);print " ".join(obj.keys())'
else
cat | python2.7 -c 'import json,sys;obj=json.load(sys.stdin);print " ".join(obj'"${JSON_NODE}"'.keys())'
fi
cat | jq -r "${JSON_NODE} | select (.!=null)" 2>/dev/null
}
strip_inline_comments() {

View File

@@ -1,2 +1,4 @@
/commands
/subcommands/*
/triggers/*
/triggers

View File

@@ -1,28 +1,5 @@
include ../../common.mk
GO_ARGS ?= -a
SUBCOMMANDS = subcommands/export subcommands/get subcommands/set subcommands/unset subcommands/keys subcommands/bundle
BUILD = commands subcommands
PLUGIN_NAME = config
build-in-docker: clean
docker run --rm \
-v $$PWD/../..:$(GO_REPO_ROOT) \
-w $(GO_REPO_ROOT)/plugins/config \
$(BUILD_IMAGE) \
bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$?
build: commands subcommands
commands: **/**/commands.go
go build $(GO_ARGS) -o commands src/commands/commands.go
subcommands: $(SUBCOMMANDS)
subcommands/%: src/subcommands/*/%.go
go build $(GO_ARGS) -o $@ $<
clean:
rm -rf commands subcommands
src-clean:
rm -rf .gitignore src triggers vendor Makefile *.go glide.*
include ../../common.mk

View File

@@ -1,16 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
func main() {
args := flag.NewFlagSet("config:bundle", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
args.Parse(os.Args[2:])
config.CommandBundle(args.Args(), *global, *merged)
}

View File

@@ -1,17 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
//clear all entries from the given environment
func main() {
args := flag.NewFlagSet("config:clear", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
args.Parse(os.Args[2:])
config.CommandClear(args.Args(), *global, *noRestart)
}

View File

@@ -1,20 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
// print the environment to stdout
func main() {
const defaultPrefix = "export "
const defaultSeparator = "\n"
args := flag.NewFlagSet("config:export", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | shell | pretty | json | json-list ] which format to export as)")
args.Parse(os.Args[2:])
config.CommandExport(args.Args(), *global, *merged, *format)
}

View File

@@ -1,17 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
// get the given entries from the specified environment
func main() {
args := flag.NewFlagSet("config:get", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
quoted := args.Bool("quoted", false, "--quoted: get the value quoted")
args.Parse(os.Args[2:])
config.CommandGet(args.Args(), *global, *quoted)
}

View File

@@ -1,16 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
func main() {
args := flag.NewFlagSet("config:keys", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
args.Parse(os.Args[2:])
config.CommandKeys(args.Args(), *global, *merged)
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
// set the given entries to the specified environment
func main() {
args := flag.NewFlagSet("config:set", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
encoded := args.Bool("encoded", false, "--encoded: interpret VALUEs as base64")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
args.Parse(os.Args[2:])
config.CommandSet(args.Args(), *global, *noRestart, *encoded)
}

View File

@@ -0,0 +1,67 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/config"
)
// main entrypoint to all subcommands
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
switch subcommand {
case "bundle":
args := flag.NewFlagSet("config:bundle", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
args.Parse(os.Args[2:])
config.CommandBundle(args.Args(), *global, *merged)
case "clear":
args := flag.NewFlagSet("config:clear", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
args.Parse(os.Args[2:])
config.CommandClear(args.Args(), *global, *noRestart)
case "export":
args := flag.NewFlagSet("config:export", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | shell | pretty | json | json-list ] which format to export as)")
args.Parse(os.Args[2:])
config.CommandExport(args.Args(), *global, *merged, *format)
case "get":
args := flag.NewFlagSet("config:get", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
quoted := args.Bool("quoted", false, "--quoted: get the value quoted")
args.Parse(os.Args[2:])
config.CommandGet(args.Args(), *global, *quoted)
case "keys":
args := flag.NewFlagSet("config:keys", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
args.Parse(os.Args[2:])
config.CommandKeys(args.Args(), *global, *merged)
case "set":
args := flag.NewFlagSet("config:set", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
encoded := args.Bool("encoded", false, "--encoded: interpret VALUEs as base64")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
args.Parse(os.Args[2:])
config.CommandSet(args.Args(), *global, *noRestart, *encoded)
case "unset":
args := flag.NewFlagSet("config:unset", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
args.Parse(os.Args[2:])
config.CommandUnset(args.Args(), *global, *noRestart)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}
}

View File

@@ -1,17 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/config"
)
//unset the given entries from the given environment
func main() {
args := flag.NewFlagSet("config:unset", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
args.Parse(os.Args[2:])
config.CommandUnset(args.Args(), *global, *noRestart)
}

View File

@@ -60,7 +60,7 @@ enter_default_cmd() {
has_tty && local DOKKU_RUN_OPTS+=" -i -t"
is_image_herokuish_based "$IMAGE" && local EXEC_CMD="/exec"
# shellcheck disable=SC2086
"$DOCKER_BIN" exec $DOKKU_RUN_OPTS $ID $EXEC_CMD "${@:-$DOKKU_APP_SHELL}"
"$DOCKER_BIN" container exec $DOKKU_RUN_OPTS $ID $EXEC_CMD "${@:-$DOKKU_APP_SHELL}"
}
enter_default_cmd "$@"

View File

@@ -67,7 +67,10 @@ git_build_app_repo() {
fi
suppress_output env -u GIT_QUARANTINE_PATH git submodule update --init --recursive
find . -name .git -prune -exec rm -rf {} \; >/dev/null
local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")"
if [[ "$DOKKU_KEEP_GIT_DIR" != "true" ]]; then
find . -name .git -prune -exec rm -rf {} \; >/dev/null
fi
if use_git_worktree; then
pushd "$DOKKU_ROOT/$APP" >/dev/null
@@ -238,7 +241,8 @@ fn-git-create-hook() {
cat >"$PRERECEIVE_HOOK" <<EOF
#!/usr/bin/env bash
set -e; set -o pipefail;
set -e
set -o pipefail
cat | DOKKU_ROOT="$DOKKU_ROOT" dokku git-hook $APP
EOF

View File

@@ -35,9 +35,10 @@ cmd-git-report-single() {
fi
verify_app_name "$APP"
local flag_map=(
"--git-rev-env-var: $(fn-plugin-property-get "git" "$APP" "rev-env-var" "GIT_REV")"
"--git-deploy-branch: $(fn-plugin-property-get "git" "$APP" "deploy-branch" "master")"
"--git-global-deploy-branch: $(fn-plugin-property-get "git" "--global" "deploy-branch" "master")"
"--git-keep-git-dir: $(fn-plugin-property-get "git" "$APP" "keep-git-dir" "false")"
"--git-rev-env-var: $(fn-plugin-property-get "git" "$APP" "rev-env-var" "GIT_REV")"
)
if [[ -z "$INFO_FLAG" ]]; then

View File

@@ -19,12 +19,12 @@ git-set-cmd() {
local cmd="git:set" argv=("$@")
[[ ${argv[0]} == "$cmd" ]] && shift 1
declare APP="$1" KEY="$2" VALUE="$3"
local VALID_KEYS=("deploy-branch" "rev-env-var")
local VALID_KEYS=("deploy-branch" "keep-git-dir" "rev-env-var")
[[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
[[ -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: deploy-branch, rev-env-var"
dokku_log_fail "Invalid key specified, valid keys include: deploy-branch, keep-git-dir, rev-env-var"
fi
if [[ -n "$VALUE" ]]; then

View File

@@ -1,6 +1,7 @@
/commands
/subcommands/*
/triggers/*
/triggers
/network-*
/install
/post-app-clone-setup

View File

@@ -1,37 +1,6 @@
include ../../common.mk
GO_ARGS ?= -a
SUBCOMMANDS = subcommands/rebuild subcommands/rebuildall subcommands/report subcommands/set
TRIGGERS = triggers/install triggers/network-build-config triggers/network-compute-ports triggers/network-config-exists triggers/network-get-ipaddr triggers/network-get-listeners triggers/network-get-port triggers/network-get-property triggers/network-write-ipaddr triggers/network-write-port triggers/post-app-clone-setup triggers/post-create triggers/post-delete triggers/report
build-in-docker: clean
docker run --rm \
-v $$PWD/../..:$(GO_REPO_ROOT) \
-w $(GO_REPO_ROOT)/plugins/network \
$(BUILD_IMAGE) \
bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$?
BUILD = commands subcommands triggers
PLUGIN_NAME = network
build: commands subcommands triggers
$(MAKE) triggers-copy
commands: **/**/commands.go
go build $(GO_ARGS) -o commands src/commands/commands.go
subcommands: $(SUBCOMMANDS)
subcommands/%: src/subcommands/*/%.go
go build $(GO_ARGS) -o $@ $<
clean:
rm -rf commands subcommands triggers network-* install post-app-clone-setup post-create post-delete report
src-clean:
rm -rf .gitignore src triggers vendor Makefile *.go glide.*
triggers: $(TRIGGERS)
triggers/%: src/triggers/*/%.go
go build $(GO_ARGS) -o $@ $<
triggers-copy:
cp triggers/* .
include ../../common.mk

View File

@@ -132,7 +132,7 @@ func GetContainerPort(appName, processType string, isHerokuishContainer bool, co
break
}
}
cmd := sh.Command(common.DockerBin(), "port", containerID, port)
cmd := sh.Command(common.DockerBin(), "container", "port", containerID, port)
cmd.Stderr = ioutil.Discard
b, err := cmd.Output()
if err == nil {

View File

@@ -1,15 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/network"
)
// rebuilds network settings for an app
func main() {
flag.Parse()
appName := flag.Arg(1)
network.BuildConfig(appName)
}

View File

@@ -1,17 +0,0 @@
package main
import (
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/network"
)
// rebuilds network settings for all apps
func main() {
apps, err := common.DokkuApps()
if err != nil {
common.LogFail(err.Error())
}
for _, appName := range apps {
network.BuildConfig(appName)
}
}

View File

@@ -1,34 +0,0 @@
package main
import (
"flag"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/network"
)
// displays a network report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
if strings.HasPrefix(appName, "--") {
infoFlag = appName
appName = ""
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
network.ReportSingleApp(appName, infoFlag)
}
return
}
network.ReportSingleApp(appName, infoFlag)
}

View File

@@ -1,22 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/network"
)
// set or clear a network property for an app
func main() {
flag.Parse()
appName := flag.Arg(1)
property := flag.Arg(2)
value := flag.Arg(3)
if property == "bind-all-interfaces" && value == "" {
value = "false"
}
common.CommandPropertySet("network", appName, property, value, network.DefaultProperties)
}

View File

@@ -0,0 +1,37 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/network"
)
// main entrypoint to all subcommands
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
flag.Parse()
switch subcommand {
case "rebuild":
appName := flag.Arg(1)
network.BuildConfig(appName)
case "rebuildall":
network.CommandRebuildall()
case "report":
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
network.CommandReport(appName, infoFlag)
case "set":
appName := flag.Arg(1)
property := flag.Arg(2)
value := flag.Arg(3)
network.CommandSet(appName, property, value)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}
}

View File

@@ -1,36 +0,0 @@
package main
import (
"fmt"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/proxy"
)
// runs the install step for the network plugin
func main() {
if err := common.PropertySetup("network"); err != nil {
common.LogFail(fmt.Sprintf("Unable to install the network plugin: %s", err.Error()))
}
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
if common.PropertyExists("network", appName, "bind-all-interfaces") {
continue
}
if proxy.IsAppProxyEnabled(appName) {
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())
}
} else {
common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to true")
if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "true"); err != nil {
common.LogWarn(err.Error())
}
}
}
}

View File

@@ -1,15 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/network"
)
// rebuilds network settings for an app
func main() {
flag.Parse()
appName := flag.Arg(0)
network.BuildConfig(appName)
}

View File

@@ -1,46 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"unicode/utf8"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/config"
)
// computes the ports for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
isHerokuishContainer := common.ToBool(flag.Arg(2))
if processType != "web" {
return
}
var dockerfilePorts []string
if !isHerokuishContainer {
dokkuDockerfilePorts := strings.Trim(config.GetWithDefault(appName, "DOKKU_DOCKERFILE_PORTS", ""), " ")
if utf8.RuneCountInString(dokkuDockerfilePorts) > 0 {
dockerfilePorts = strings.Split(dokkuDockerfilePorts, " ")
}
}
var ports []string
if len(dockerfilePorts) == 0 {
ports = append(ports, "5000")
} else {
for _, port := range dockerfilePorts {
port = strings.TrimSuffix(strings.TrimSpace(port), "/tcp")
if port == "" || strings.HasSuffix(port, "/udp") {
continue
}
ports = append(ports, port)
}
}
fmt.Fprint(os.Stdout, strings.Join(ports, " "))
}

View File

@@ -1,22 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/dokku/dokku/plugins/network"
)
// writes true or false to stdout whether a given app has network config
func main() {
flag.Parse()
appName := flag.Arg(0)
if network.HasNetworkConfig(appName) {
fmt.Fprintln(os.Stdout, "true")
return
}
fmt.Fprintln(os.Stdout, "false")
}

View File

@@ -1,20 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/dokku/dokku/plugins/network"
)
// write the ipaddress to stdout for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
containerID := flag.Arg(2)
ipAddress := network.GetContainerIpaddress(appName, processType, containerID)
fmt.Fprintln(os.Stdout, ipAddress)
}

View File

@@ -1,19 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/network"
)
// returns the listeners (host:port combinations) for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
listeners := network.GetListeners(appName)
fmt.Fprint(os.Stdout, strings.Join(listeners, " "))
}

View File

@@ -1,22 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/dokku/dokku/plugins/common"
network "github.com/dokku/dokku/plugins/network"
)
// write the port to stdout for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
isHerokuishContainer := common.ToBool(flag.Arg(2))
containerID := flag.Arg(3)
port := network.GetContainerPort(appName, processType, isHerokuishContainer, containerID)
fmt.Fprintln(os.Stdout, port)
}

View File

@@ -1,21 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/dokku/dokku/plugins/common"
network "github.com/dokku/dokku/plugins/network"
)
// writes the network property to stdout for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
property := flag.Arg(1)
defaultValue := network.GetDefaultValue(property)
value := common.PropertyGetDefault("network", appName, property, defaultValue)
fmt.Fprintln(os.Stdout, value)
}

View File

@@ -1,41 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
)
// writes the ip to disk
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
containerIndex := flag.Arg(2)
ip := flag.Arg(3)
if appName == "" {
common.LogFail("Please specify an app to run the command on")
}
err := common.VerifyAppName(appName)
if err != nil {
common.LogFail(err.Error())
}
appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/")
filename := fmt.Sprintf("%v/IP.%v.%v", appRoot, processType, containerIndex)
f, err := os.Create(filename)
if err != nil {
common.LogFail(err.Error())
}
defer f.Close()
ipBytes := []byte(ip)
_, err = f.Write(ipBytes)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,41 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
)
// writes the port to disk
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
containerIndex := flag.Arg(2)
port := flag.Arg(3)
if appName == "" {
common.LogFail("Please specify an app to run the command on")
}
err := common.VerifyAppName(appName)
if err != nil {
common.LogFail(err.Error())
}
appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/")
filename := fmt.Sprintf("%v/PORT.%v.%v", appRoot, processType, containerIndex)
f, err := os.Create(filename)
if err != nil {
common.LogFail(err.Error())
}
defer f.Close()
portBytes := []byte(port)
_, err = f.Write(portBytes)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,19 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/network"
)
// cleanup network files for a new app clone
func main() {
flag.Parse()
appName := flag.Arg(1)
success := network.PostAppCloneSetup(appName)
if !success {
os.Exit(1)
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
)
// set bind-all-interfaces to false by default
func main() {
flag.Parse()
appName := flag.Arg(0)
err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false")
if err != nil {
common.LogWarn(err.Error())
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
)
// destroys the network property for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
err := common.PropertyDestroy("network", appName)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,15 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/network"
)
// displays a network report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(0)
network.ReportSingleApp(appName, "")
}

View File

@@ -0,0 +1,78 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/network"
)
// main entrypoint to all triggers
func main() {
parts := strings.Split(os.Args[0], "/")
trigger := parts[len(parts)-1]
flag.Parse()
switch trigger {
case "install":
network.TriggerInstall()
case "network-build-config":
appName := flag.Arg(0)
network.BuildConfig(appName)
case "network-compute-ports":
appName := flag.Arg(0)
processType := flag.Arg(1)
isHerokuishContainer := common.ToBool(flag.Arg(2))
network.TriggerNetworkComputePorts(appName, processType, isHerokuishContainer)
case "network-config-exists":
appName := flag.Arg(0)
network.TriggerNetworkConfigExists(appName)
case "network-get-ipaddr":
appName := flag.Arg(0)
processType := flag.Arg(1)
containerID := flag.Arg(2)
network.TriggerNetworkGetIppaddr(appName, processType, containerID)
case "network-get-listeners":
appName := flag.Arg(0)
network.TriggerNetworkGetListeners(appName)
case "network-get-port":
appName := flag.Arg(0)
processType := flag.Arg(1)
isHerokuishContainer := common.ToBool(flag.Arg(2))
containerID := flag.Arg(3)
network.TriggerNetworkGetPort(appName, processType, isHerokuishContainer, containerID)
case "network-get-property":
appName := flag.Arg(0)
property := flag.Arg(1)
network.TriggerNetworkGetProperty(appName, property)
case "network-write-ipaddr":
appName := flag.Arg(0)
processType := flag.Arg(1)
containerIndex := flag.Arg(2)
ip := flag.Arg(3)
network.TriggerNetworkWriteIpaddr(appName, processType, containerIndex, ip)
case "network-write-port":
appName := flag.Arg(0)
processType := flag.Arg(1)
containerIndex := flag.Arg(2)
port := flag.Arg(3)
network.TriggerNetworkWritePort(appName, processType, containerIndex, port)
case "post-app-clone-setup":
appName := flag.Arg(1)
network.TriggerPostAppCloneSetup(appName)
case "post-create":
appName := flag.Arg(0)
network.TriggerPostCreate(appName)
case "post-delete":
appName := flag.Arg(0)
network.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
network.ReportSingleApp(appName, "")
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}
}

View File

@@ -0,0 +1,48 @@
package network
import (
"strings"
"github.com/dokku/dokku/plugins/common"
)
// CommandRebuildall rebuilds network settings for all apps
func CommandRebuildall() {
apps, err := common.DokkuApps()
if err != nil {
common.LogFail(err.Error())
}
for _, appName := range apps {
BuildConfig(appName)
}
}
// CommandReport displays a network report for one or more apps
func CommandReport(appName string, infoFlag string) {
if strings.HasPrefix(appName, "--") {
infoFlag = appName
appName = ""
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
ReportSingleApp(appName, infoFlag)
}
return
}
ReportSingleApp(appName, infoFlag)
}
// CommandSet set or clear a network property for an app
func CommandSet(appName string, property string, value string) {
if property == "bind-all-interfaces" && value == "" {
value = "false"
}
common.CommandPropertySet("network", appName, property, value, DefaultProperties)
}

178
plugins/network/triggers.go Normal file
View File

@@ -0,0 +1,178 @@
package network
import (
"fmt"
"os"
"strings"
"unicode/utf8"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/config"
"github.com/dokku/dokku/plugins/proxy"
)
// TriggerInstall runs the install step for the network plugin
func TriggerInstall() {
if err := common.PropertySetup("network"); err != nil {
common.LogFail(fmt.Sprintf("Unable to install the network plugin: %s", err.Error()))
}
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
if common.PropertyExists("network", appName, "bind-all-interfaces") {
continue
}
if proxy.IsAppProxyEnabled(appName) {
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())
}
} else {
common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to true")
if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "true"); err != nil {
common.LogWarn(err.Error())
}
}
}
}
// TriggerNetworkComputePorts computes the ports for a given app container
func TriggerNetworkComputePorts(appName string, processType string, isHerokuishContainer bool) {
if processType != "web" {
return
}
var dockerfilePorts []string
if !isHerokuishContainer {
dokkuDockerfilePorts := strings.Trim(config.GetWithDefault(appName, "DOKKU_DOCKERFILE_PORTS", ""), " ")
if utf8.RuneCountInString(dokkuDockerfilePorts) > 0 {
dockerfilePorts = strings.Split(dokkuDockerfilePorts, " ")
}
}
var ports []string
if len(dockerfilePorts) == 0 {
ports = append(ports, "5000")
} else {
for _, port := range dockerfilePorts {
port = strings.TrimSuffix(strings.TrimSpace(port), "/tcp")
if port == "" || strings.HasSuffix(port, "/udp") {
continue
}
ports = append(ports, port)
}
}
fmt.Fprint(os.Stdout, strings.Join(ports, " "))
}
// TriggerNetworkConfigExists writes true or false to stdout whether a given app has network config
func TriggerNetworkConfigExists(appName string) {
if HasNetworkConfig(appName) {
fmt.Fprintln(os.Stdout, "true")
return
}
fmt.Fprintln(os.Stdout, "false")
}
// TriggerNetworkGetIppaddr writes the ipaddress to stdout for a given app container
func TriggerNetworkGetIppaddr(appName string, processType string, containerID string) {
ipAddress := GetContainerIpaddress(appName, processType, containerID)
fmt.Fprintln(os.Stdout, ipAddress)
}
// TriggerNetworkGetListeners returns the listeners (host:port combinations) for a given app container
func TriggerNetworkGetListeners(appName string) {
listeners := GetListeners(appName)
fmt.Fprint(os.Stdout, strings.Join(listeners, " "))
}
// TriggerNetworkGetPort writes the port to stdout for a given app container
func TriggerNetworkGetPort(appName string, processType string, isHerokuishContainer bool, containerID string) {
port := GetContainerPort(appName, processType, isHerokuishContainer, containerID)
fmt.Fprintln(os.Stdout, port)
}
// TriggerNetworkGetProperty writes the network property to stdout for a given app container
func TriggerNetworkGetProperty(appName string, property string) {
defaultValue := GetDefaultValue(property)
value := common.PropertyGetDefault("network", appName, property, defaultValue)
fmt.Fprintln(os.Stdout, value)
}
// TriggerNetworkWriteIpaddr writes the ip to disk
func TriggerNetworkWriteIpaddr(appName string, processType string, containerIndex string, ip string) {
if appName == "" {
common.LogFail("Please specify an app to run the command on")
}
err := common.VerifyAppName(appName)
if err != nil {
common.LogFail(err.Error())
}
appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/")
filename := fmt.Sprintf("%v/IP.%v.%v", appRoot, processType, containerIndex)
f, err := os.Create(filename)
if err != nil {
common.LogFail(err.Error())
}
defer f.Close()
ipBytes := []byte(ip)
_, err = f.Write(ipBytes)
if err != nil {
common.LogFail(err.Error())
}
}
// TriggerNetworkWritePort writes the port to disk
func TriggerNetworkWritePort(appName string, processType string, containerIndex string, port string) {
if appName == "" {
common.LogFail("Please specify an app to run the command on")
}
err := common.VerifyAppName(appName)
if err != nil {
common.LogFail(err.Error())
}
appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/")
filename := fmt.Sprintf("%v/PORT.%v.%v", appRoot, processType, containerIndex)
f, err := os.Create(filename)
if err != nil {
common.LogFail(err.Error())
}
defer f.Close()
portBytes := []byte(port)
_, err = f.Write(portBytes)
if err != nil {
common.LogFail(err.Error())
}
}
// TriggerPostAppCloneSetup cleans up network files for a new app clone
func TriggerPostAppCloneSetup(appName string) {
success := PostAppCloneSetup(appName)
if !success {
os.Exit(1)
}
}
// TriggerPostCreate sets bind-all-interfaces to false by default
func TriggerPostCreate(appName string) {
err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false")
if err != nil {
common.LogWarn(err.Error())
}
}
// TriggerPostDelete destroys the network property for a given app container
func TriggerPostDelete(appName string) {
err := common.PropertyDestroy("network", appName)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -11,18 +11,7 @@ source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions"
get_nginx_location() {
declare desc="check that nginx is at the expected location and return it"
local NGINX_LOCATION
NGINX_LOCATION=$(which nginx 2>/dev/null)
if [[ -z "$NGINX_LOCATION" ]]; then
NGINX_LOCATION="/usr/sbin/nginx"
fi
if [[ ! -x "$NGINX_LOCATION" ]]; then
dokku_log_fail "Could not find nginx binary in \$PATH or at '${NGINX_LOCATION}'."
fi
echo "$NGINX_LOCATION"
fn-nginx-vhosts-nginx-location
}
validate_nginx() {
@@ -69,32 +58,18 @@ validate_nginx() {
restart_nginx() {
declare desc="restart nginx for given distros"
case "$DOKKU_DISTRO" in
debian)
sudo /usr/sbin/invoke-rc.d nginx reload >/dev/null
;;
ubuntu)
sudo /etc/init.d/nginx reload >/dev/null
;;
opensuse)
sudo /sbin/service nginx reload >/dev/null
;;
arch | centos | rhel)
sudo /usr/bin/systemctl reload nginx
;;
esac
fn-nginx-vhosts-nginx-init-cmd "reload"
}
nginx_logs() {
declare desc="display app nginx logs"
local APP="$2"
declare NGINX_LOGS_TYPE="${1#nginx:}" APP="$2"
local NGINX_LOG_ROOT="/var/log/nginx"
verify_app_name "$APP"
local NGINX_LOGS_TYPE=${1#nginx:}
fn-nginx-vhosts-uses-openresty && NGINX_LOG_ROOT="/var/log/openresty"
local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs}
local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log"
local NGINX_LOGS_PATH="$NGINX_LOG_ROOT/$APP-$NGINX_LOGS_TYPE.log"
if [[ $3 == "-t" ]]; then
local NGINX_LOGS_ARGS="-F"
@@ -259,6 +234,28 @@ is_http2_enabled() {
echo $HAS_SUPPORT
}
is_grpc_enabled() {
declare desc="detects whether the installed nginx version has grpc support"
local NGINX_VERSION="$1"
local MAJOR_VERSION MINOR_VERSION PATCH_VERSION
local HAS_SUPPORT=false
MAJOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[1]}')
MINOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[2]}')
PATCH_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[3]}')
if [[ "$MAJOR_VERSION" -ge "2" ]]; then
HAS_SUPPORT=true
elif [[ "$MAJOR_VERSION" -eq "1" ]]; then
if [[ "$MINOR_VERSION" -eq "13" ]] && [[ "$PATCH_VERSION" -ge "10" ]]; then
HAS_SUPPORT=true
elif [[ "$MINOR_VERSION" -ge "14" ]]; then
HAS_SUPPORT=true
fi
fi
echo $HAS_SUPPORT
}
nginx_build_config() {
declare desc="build nginx config to proxy app containers using sigil"
local APP="$1"
@@ -324,7 +321,7 @@ nginx_build_config() {
done
fi
local NGINX_LOCATION NGINX_VERSION SPDY_SUPPORTED HTTP2_SUPPORTED HTTP2_PUSH_SUPPORTED
local NGINX_LOCATION NGINX_VERSION SPDY_SUPPORTED HTTP2_SUPPORTED HTTP2_PUSH_SUPPORTED GRPC_SUPPORTED
NGINX_LOCATION=$(get_nginx_location)
if [[ -z "$NGINX_LOCATION" ]]; then
exit 1
@@ -333,9 +330,13 @@ nginx_build_config() {
SPDY_SUPPORTED="$(is_spdy_enabled "$NGINX_VERSION")"
HTTP2_SUPPORTED="$(is_http2_enabled "$NGINX_VERSION")"
HTTP2_PUSH_SUPPORTED="$(is_http2_push_enabled "$NGINX_VERSION")"
GRPC_SUPPORTED="$(is_grpc_enabled "$NGINX_VERSION")"
PROXY_PORT_MAP=$(echo "$PROXY_PORT_MAP" | xargs) # trailing spaces mess up default template
local NGINX_LOG_ROOT="/var/log/nginx"
fn-nginx-vhosts-uses-openresty && NGINX_LOG_ROOT="/var/log/openresty"
if [[ -z "$DOKKU_APP_LISTENERS" ]]; then
dokku_log_warn_quiet "No web listeners specified for $APP"
elif (is_deployed "$APP"); then
@@ -366,7 +367,9 @@ nginx_build_config() {
PASSED_LISTEN_IP_PORT="$PASSED_LISTEN_IP_PORT"
SPDY_SUPPORTED="$SPDY_SUPPORTED"
HTTP2_SUPPORTED="$HTTP2_SUPPORTED"
NGINX_LOG_ROOT="$NGINX_LOG_ROOT"
HTTP2_PUSH_SUPPORTED="$HTTP2_PUSH_SUPPORTED"
GRPC_SUPPORTED="$GRPC_SUPPORTED"
DOKKU_APP_LISTEN_PORT="$DOKKU_APP_LISTEN_PORT" DOKKU_APP_LISTEN_IP="$DOKKU_APP_LISTEN_IP"
APP_SSL_PATH="$APP_SSL_PATH" SSL_INUSE="$SSL_INUSE" SSL_SERVER_NAME="$SSL_SERVER_NAME"
# @TODO: Remove this after a few versions
@@ -381,11 +384,10 @@ nginx_build_config() {
dokku_log_info1 "Creating $SCHEME nginx.conf"
mv "$NGINX_CONF" "$DOKKU_ROOT/$APP/nginx.conf"
dokku_log_info1 "Running nginx-pre-reload"
plugn trigger nginx-pre-reload "$APP" "$DOKKU_APP_LISTEN_PORT" "$DOKKU_APP_LISTEN_IP"
dokku_log_verbose "Reloading nginx"
validate_nginx && restart_nginx
validate_nginx && restart_nginx >/dev/null
fi
if ([[ -n "$NONSSL_VHOSTS" ]] || [[ -n "$SSL_VHOSTS" ]]) && [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
@@ -401,7 +403,7 @@ nginx_build_config() {
if (is_deployed "$APP"); then
dokku_log_info1 "reloading nginx after nginx.conf deletion"
validate_nginx && restart_nginx
validate_nginx && restart_nginx >/dev/null
fi
fi
fi

View File

@@ -3,63 +3,81 @@ set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/config/functions"
source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions"
NGINX_BIN="$(fn-nginx-vhosts-nginx-location)"
NGINX_ROOT="/etc/nginx"
NGINX_LOG_ROOT="/var/log/nginx"
NGINX_INIT_NAME="nginx"
NGINX_SUDOERS_FILE="/etc/sudoers.d/dokku-nginx"
if fn-nginx-vhosts-uses-openresty; then
NGINX_ROOT="/usr/local/openresty/nginx/conf"
NGINX_LOG_ROOT="/var/log/openresty"
NGINX_INIT_NAME="openresty"
NGINX_SUDOERS_FILE="/etc/sudoers.d/dokku-openresty"
fi
case "$DOKKU_DISTRO" in
debian)
echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx
echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d $NGINX_INIT_NAME reload, $NGINX_BIN -t, ${NGINX_BIN} -t -c *" >"$NGINX_SUDOERS_FILE"
;;
ubuntu)
echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx
if [[ -x /usr/bin/sv ]]; then
echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/sv reload $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, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE"
fi
;;
opensuse)
echo "%dokku ALL=(ALL) NOPASSWD:/sbin/service nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx
echo "%dokku ALL=(ALL) NOPASSWD:/sbin/service $NGINX_INIT_NAME reload, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE"
;;
arch)
echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx
echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE"
;;
centos | rhel)
echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx
echo "Defaults:dokku !requiretty" >>/etc/sudoers.d/dokku-nginx
echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE"
echo "Defaults:dokku !requiretty" >>"$NGINX_SUDOERS_FILE"
;;
esac
chmod 0440 /etc/sudoers.d/dokku-nginx
chmod 0440 "$NGINX_SUDOERS_FILE"
# if dhparam.pem has not been created, create it the first time
if [[ ! -f /etc/nginx/dhparam.pem ]]; then
openssl dhparam -out /etc/nginx/dhparam.pem 2048
if [[ ! -f "$NGINX_ROOT/dhparam.pem" ]]; then
openssl dhparam -out "$NGINX_ROOT/dhparam.pem" 2048
fi
mkdir -p /etc/nginx/conf.d
chown root:root /etc/nginx/dhparam.pem
chown root:root /etc/nginx/conf.d
cat <<EOF >/etc/nginx/conf.d/dokku.conf
mkdir -p "$NGINX_ROOT/conf.d"
chown root:root "$NGINX_ROOT/dhparam.pem"
chown root:root "$NGINX_ROOT/conf.d"
cat <<EOF >"$NGINX_ROOT/conf.d/dokku.conf"
include $DOKKU_ROOT/*/nginx.conf;
server_tokens off;
# Settings from https://mozilla.github.io/server-side-tls/ssl-config-generator/
ssl_session_cache shared:SSL:20m;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 1d;
ssl_session_tickets on;
ssl_session_tickets off;
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
ssl_dhparam $NGINX_ROOT/dhparam.pem;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
EOF
# allow users to override their server_names_hash_bucket_size
if [[ ! -f /etc/nginx/conf.d/server_names_hash_bucket_size.conf ]]; then
echo 'server_names_hash_bucket_size 512;' >|/etc/nginx/conf.d/server_names_hash_bucket_size.conf
if [[ ! -f "$NGINX_ROOT/conf.d/server_names_hash_bucket_size.conf" ]]; then
echo 'server_names_hash_bucket_size 512;' >|"$NGINX_ROOT/conf.d/server_names_hash_bucket_size.conf"
fi
# revert dokku group changes
mkdir -p "$NGINX_LOG_ROOT"
gpasswd -a dokku adm
chgrp --quiet -R adm /var/log/nginx
chgrp --quiet -R adm "$NGINX_LOG_ROOT"
gpasswd -M "$(egrep ^dokku: /etc/group | awk -F ":" '{ print $4 }')" dokku
[[ -f /etc/logrotate.d/nginx ]] && sed -i -e 's/create 0640 www-data dokku/create 0640 www-data adm/g' /etc/logrotate.d/nginx
@@ -93,24 +111,9 @@ for app in $(dokku_apps); do
fi
done
case "$DOKKU_DISTRO" in
debian)
NGINX_INIT="/usr/sbin/invoke-rc.d"
"$NGINX_INIT" nginx start || "$NGINX_INIT" nginx reload
;;
ubuntu)
NGINX_INIT="/etc/init.d/nginx"
"$NGINX_INIT" start || "$NGINX_INIT" reload
;;
opensuse)
NGINX_INIT="/sbin/service"
"$NGINX_INIT" nginx start || "$NGINX_INIT" nginx reload
;;
arch | centos | rhel)
NGINX_INIT="/usr/bin/systemctl"
"$NGINX_INIT" start nginx || "$NGINX_INIT" reload nginx
;;
esac
# 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 ]]; then
fn-nginx-vhosts-nginx-init-cmd start || fn-nginx-vhosts-nginx-init-cmd reload
fi

View File

@@ -1,6 +1,71 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
fn-nginx-vhosts-uses-openresty() {
declare desc="returns whether openresty is in use or not"
if [[ -x /usr/bin/openresty ]]; then
return
fi
return 1
}
fn-nginx-vhosts-nginx-location() {
declare desc="check that nginx is at the expected location and return it"
local NGINX_LOCATION
NGINX_LOCATION=$(which nginx 2>/dev/null)
if [[ -z "$NGINX_LOCATION" ]]; then
NGINX_LOCATION="/usr/sbin/nginx"
fi
if fn-nginx-vhosts-uses-openresty; then
NGINX_LOCATION="/usr/bin/openresty"
fi
if [[ ! -x "$NGINX_LOCATION" ]]; then
dokku_log_fail "Could not find nginx binary in \$PATH or at '${NGINX_LOCATION}'."
fi
echo "$NGINX_LOCATION"
}
fn-nginx-vhosts-nginx-init-cmd() {
declare desc="start nginx for given distros"
declare CMD="$1"
local NGINX_INIT_NAME
NGINX_INIT_NAME=nginx
if fn-nginx-vhosts-uses-openresty; then
NGINX_INIT_NAME=openresty
fi
case "$DOKKU_DISTRO" in
debian)
sudo /usr/sbin/invoke-rc.d "$NGINX_INIT_NAME" "$CMD"
;;
ubuntu)
# support docker-based installations
if [[ -x /usr/bin/sv ]]; then
sudo /usr/bin/sv "$CMD" "$NGINX_INIT_NAME"
else
sudo "/etc/init.d/$NGINX_INIT_NAME" "$CMD"
fi
;;
opensuse)
sudo /sbin/service "$NGINX_INIT_NAME" "$CMD"
;;
arch | centos | rhel)
sudo /usr/bin/systemctl "$CMD" "$NGINX_INIT_NAME"
;;
esac
}
nginx_vhosts_validate_single_func() {
declare APP="$1" FLAG="$2"

View File

@@ -3,4 +3,4 @@ set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions"
restart_nginx "$@"
restart_nginx "$@" >/dev/null

View File

@@ -9,8 +9,8 @@ server {
listen [::]:{{ $listen_port }};
listen {{ $listen_port }};
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log /var/log/nginx/{{ $.APP }}-access.log;
error_log /var/log/nginx/{{ $.APP }}-error.log;
access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log;
error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log;
{{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }}
return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri;
{{ else }}
@@ -60,13 +60,13 @@ server {
listen {{ $listen_port }} ssl {{ if eq $.HTTP2_SUPPORTED "true" }}http2{{ else if eq $.SPDY_SUPPORTED "true" }}spdy{{ end }};
{{ if $.SSL_SERVER_NAME }}server_name {{ $.SSL_SERVER_NAME }}; {{ end }}
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log /var/log/nginx/{{ $.APP }}-access.log;
error_log /var/log/nginx/{{ $.APP }}-error.log;
access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log;
error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log;
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
keepalive_timeout 70;
{{ if and (eq $.SPDY_SUPPORTED "true") (ne $.HTTP2_SUPPORTED "true") }}add_header Alternate-Protocol {{ $.PROXY_SSL_PORT }}:npn-spdy/2;{{ end }}
@@ -117,7 +117,42 @@ server {
internal;
}
}
{{ else if eq $scheme "grpc"}}
{{ if eq $.GRPC_SUPPORTED "true"}}{{ if eq $.HTTP2_SUPPORTED "true"}}
server {
listen [::]:{{ $listen_port }} http2;
listen {{ $listen_port }} http2;
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log;
error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log;
location / {
grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }};
}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
}
{{ end }}{{ end }}
{{ else if eq $scheme "grpcs"}}
{{ if eq $.GRPC_SUPPORTED "true"}}{{ if eq $.HTTP2_SUPPORTED "true"}}
server {
listen [::]:{{ $listen_port }} ssl http2;
listen {{ $listen_port }} ssl http2;
{{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }}
access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log;
error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log;
ssl_certificate {{ $.APP_SSL_PATH }}/server.crt;
ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
location / {
grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }};
}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
}
{{ end }}{{ end }}
{{ end }}
{{ end }}
{{ if $.DOKKU_APP_LISTENERS }}
{{ range $upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }}

View File

@@ -62,7 +62,7 @@ cmd-ps-report-single() {
local APP_CONTAINER_STATUS
for CONTAINER_FILE in $CONTAINER_FILES; do
CID=$(<"$DOKKU_ROOT/$APP/$CONTAINER_FILE")
APP_CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f '{{.State.Status}}' "$CID" 2>/dev/null || true)
APP_CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Status}}' "$CID" 2>/dev/null || true)
[[ -z "$APP_CONTAINER_STATUS" ]] && APP_CONTAINER_STATUS="missing"
STATUSES+=("${CONTAINER_FILE#*.}:$APP_CONTAINER_STATUS#${CID:0:12}")
done

View File

@@ -14,14 +14,14 @@ ps_main_cmd() {
verify_app_name "$APP"
! (is_deployed "$APP") && dokku_log_warn "App $APP has not been deployed" && exit 0
local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP")
local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null)
local CID
for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do
has_tty && local DOKKU_RUN_OPTS="-i -t"
dokku_log_info1_quiet "running processes in container: $CID"
# shellcheck disable=SC2086
"$DOCKER_BIN" exec $DOKKU_RUN_OPTS $CID /bin/sh -c "ps auxwww"
"$DOCKER_BIN" container exec $DOKKU_RUN_OPTS $CID /bin/sh -c "ps auxwww"
done
}

View File

@@ -1,2 +1,5 @@
/commands
/subcommands/*
/triggers/*
/triggers
/pre-delete

View File

@@ -1,37 +1,6 @@
include ../../common.mk
GO_ARGS ?= -a
SUBCOMMANDS = subcommands/gc subcommands/purge-cache
TRIGGERS = triggers/pre-delete
build-in-docker: clean
docker run --rm \
-v $$PWD/../..:$(GO_REPO_ROOT) \
-w $(GO_REPO_ROOT)/plugins/repo \
$(BUILD_IMAGE) \
bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$?
BUILD = commands subcommands triggers
PLUGIN_NAME = repo
build: commands subcommands triggers
$(MAKE) triggers-copy
commands: **/**/commands.go
go build $(GO_ARGS) -o commands src/commands/commands.go
subcommands: $(SUBCOMMANDS)
subcommands/%: src/subcommands/*/%.go
go build $(GO_ARGS) -o $@ $<
clean:
rm -rf commands subcommands triggers pre-delete
src-clean:
rm -rf .gitignore src triggers vendor Makefile *.go glide.*
triggers: $(TRIGGERS)
triggers/%: src/triggers/*/%.go
go build $(GO_ARGS) -o $@ $<
triggers-copy:
cp triggers/* .
include ../../common.mk

View File

@@ -24,7 +24,8 @@ func PurgeCache(appName string) error {
dockerLabelArgs := fmt.Sprintf("--label=com.dokku.app-name=%s", appName)
purgeCacheCmd := common.NewShellCmd(strings.Join([]string{
common.DockerBin(),
"run --rm", dockerLabelArgs, dokkuGlobalRunArgs,
"container",
"run", "--rm", dockerLabelArgs, dokkuGlobalRunArgs,
"-v", strings.Join([]string{cacheHostDir, ":/cache"}, ""), image,
`find /cache -depth -mindepth 1 -maxdepth 1 -exec rm -Rf {} ;`}, " "))
purgeCacheCmd.Execute()

View File

@@ -1,22 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/repo"
)
// deletes the contents of the build cache stored in the repository
func main() {
flag.Parse()
appName := flag.Arg(1)
if appName == "" {
common.LogFail("Please specify an app to run the command on")
}
err := repo.PurgeCache(appName)
if err != nil {
common.LogWarn(err.Error())
}
}

View File

@@ -0,0 +1,35 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/repo"
)
// main entrypoint to all subcommands
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
flag.Parse()
var err error
switch subcommand {
case "gc":
flag.Parse()
appName := flag.Arg(1)
err = repo.CommandGc(appName)
case "purge-cache":
appName := flag.Arg(1)
err = repo.CommandPurgeCache(appName)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,19 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/repo"
)
// destroys the buildpacks property for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
err := repo.PurgeCache(appName)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -0,0 +1,31 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/repo"
)
// main entrypoint to all triggers
func main() {
parts := strings.Split(os.Args[0], "/")
trigger := parts[len(parts)-1]
flag.Parse()
var err error
switch trigger {
case "pre-delete":
appName := flag.Arg(0)
err = repo.PurgeCache(appName)
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,22 +1,20 @@
package main
package repo
import (
"flag"
"errors"
"strings"
"github.com/dokku/dokku/plugins/common"
)
// runs 'git gc --aggressive' against the application's repo
func main() {
flag.Parse()
appName := flag.Arg(1)
// CommandGc runs 'git gc --aggressive' against the application's repo
func CommandGc(appName string) error {
if appName == "" {
common.LogFail("Please specify an app to run the command on")
return errors.New("Please specify an app to run the command on")
}
err := common.VerifyAppName(appName)
if err != nil {
common.LogFail(err.Error())
return err
}
appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/")
@@ -26,4 +24,14 @@ func main() {
gitGcCmd := common.NewShellCmd("git gc --aggressive")
gitGcCmd.Env = cmdEnv
gitGcCmd.Execute()
return nil
}
// CommandPurgeCache deletes the contents of the build cache stored in the repository
func CommandPurgeCache(appName string) error {
if appName == "" {
common.LogFail("Please specify an app to run the command on")
}
return PurgeCache(appName)
}

View File

@@ -1,6 +1,7 @@
/commands
/subcommands/*
/triggers/*
/triggers
/install
/post-delete
/report

View File

@@ -1,38 +1,6 @@
include ../../common.mk
GO_ARGS ?= -a
SUBCOMMANDS = subcommands/limit subcommands/limit-clear subcommands/report subcommands/reserve subcommands/reserve-clear
TRIGGERS = triggers/docker-args-process-deploy triggers/install triggers/post-delete triggers/report triggers/resource-get-property
build-in-docker: clean
docker run --rm \
-v $$PWD/../..:$(GO_REPO_ROOT) \
-w $(GO_REPO_ROOT)/plugins/resource \
$(BUILD_IMAGE) \
bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$?
BUILD = commands subcommands triggers
PLUGIN_NAME = resource
build: commands subcommands triggers
$(MAKE) triggers-copy
commands: **/**/commands.go
go build $(GO_ARGS) -o commands src/commands/commands.go
subcommands: $(SUBCOMMANDS)
subcommands/%: src/subcommands/*/%.go
go build $(GO_ARGS) -o $@ $<
clean:
rm -rf commands subcommands triggers docker-args-process-deploy docker-args-process-run install post-delete report resource-get-property
src-clean:
rm -rf .gitignore src triggers vendor Makefile *.go glide.*
triggers: $(TRIGGERS)
triggers/%: src/triggers/*/%.go
go build $(GO_ARGS) -o $@ $<
triggers-copy:
cp triggers/* .
ln -sf docker-args-process-deploy docker-args-process-run
include ../../common.mk

View File

@@ -1,20 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
args.Parse(os.Args[2:])
err := resource.CommandLimitClear(args.Args(), *processType)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,35 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
args := flag.NewFlagSet("resource:limit", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
cpu := args.String("cpu", "", "cpu: The amount of cpu to limit processes by")
memory := args.String("memory", "", "memory: The amount of memory to limit processes by")
memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to limit processes by")
network := args.String("network", "", "network: The amount of network bandwidth to limit processes by")
networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to limit processes by")
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by")
args.Parse(os.Args[2:])
resources := resource.Resource{
CPU: *cpu,
Memory: *memory,
MemorySwap: *memorySwap,
Network: *network,
NetworkIngress: *networkIngress,
NetworkEgress: *networkEgress,
}
err := resource.CommandLimit(args.Args(), *processType, resources)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,33 +0,0 @@
package main
import (
"flag"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// displays a resource report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
if strings.HasPrefix(appName, "--") {
common.LogFail("The resource:report command does not support flags without an app name")
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
resource.ReportSingleApp(appName, infoFlag)
}
return
}
resource.ReportSingleApp(appName, infoFlag)
}

View File

@@ -1,20 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
args.Parse(os.Args[2:])
err := resource.CommandReserveClear(args.Args(), *processType)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,35 +0,0 @@
package main
import (
"flag"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
func main() {
args := flag.NewFlagSet("resource:reserve", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
cpu := args.String("cpu", "", "cpu: The amount of cpu to reserve for processes")
memory := args.String("memory", "", "memory: The amount of memory to reserve for processes")
memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to reserve for processes")
network := args.String("network", "", "network: The amount of network bandwidth to reserve for processes")
networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to reserve for processes")
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes")
args.Parse(os.Args[2:])
resources := resource.Resource{
CPU: *cpu,
Memory: *memory,
MemorySwap: *memorySwap,
Network: *network,
NetworkIngress: *networkIngress,
NetworkEgress: *networkEgress,
}
err := resource.CommandReserve(args.Args(), *processType, resources)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -0,0 +1,84 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// main entrypoint to all subcommands
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
var err error
switch subcommand {
case "limit":
args := flag.NewFlagSet("resource:limit", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
cpu := args.String("cpu", "", "cpu: The amount of cpu to limit processes by")
memory := args.String("memory", "", "memory: The amount of memory to limit processes by")
memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to limit processes by")
network := args.String("network", "", "network: The amount of network bandwidth to limit processes by")
networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to limit processes by")
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by")
args.Parse(os.Args[2:])
resources := resource.Resource{
CPU: *cpu,
Memory: *memory,
MemorySwap: *memorySwap,
Network: *network,
NetworkIngress: *networkIngress,
NetworkEgress: *networkEgress,
}
err = resource.CommandLimit(args.Args(), *processType, resources)
case "limit-clear":
args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
args.Parse(os.Args[2:])
err = resource.CommandLimitClear(args.Args(), *processType)
case "report":
flag.Parse()
appName := flag.Arg(1)
infoFlag := flag.Arg(2)
resource.CommandReport(appName, infoFlag)
case "reserve":
args := flag.NewFlagSet("resource:reserve", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to manage")
cpu := args.String("cpu", "", "cpu: The amount of cpu to reserve for processes")
memory := args.String("memory", "", "memory: The amount of memory to reserve for processes")
memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to reserve for processes")
network := args.String("network", "", "network: The amount of network bandwidth to reserve for processes")
networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to reserve for processes")
networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes")
args.Parse(os.Args[2:])
resources := resource.Resource{
CPU: *cpu,
Memory: *memory,
MemorySwap: *memorySwap,
Network: *network,
NetworkIngress: *networkIngress,
NetworkEgress: *networkEgress,
}
err = resource.CommandReserve(args.Args(), *processType, resources)
case "reserve-clear":
args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError)
processType := args.String("process-type", "", "process-type: A process type to clear")
args.Parse(os.Args[2:])
err = resource.CommandReserveClear(args.Args(), *processType)
default:
common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,14 +0,0 @@
package main
import (
"fmt"
"github.com/dokku/dokku/plugins/common"
)
// runs the install step for the resource plugin
func main() {
if err := common.PropertySetup("resource"); err != nil {
common.LogFail(fmt.Sprintf("Unable to install the resource plugin: %s", err.Error()))
}
}

View File

@@ -1,18 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/common"
)
// destroys the resource property for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
err := common.PropertyDestroy("resource", appName)
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -1,15 +0,0 @@
package main
import (
"flag"
"github.com/dokku/dokku/plugins/resource"
)
// displays a resource report for one or more apps
func main() {
flag.Parse()
appName := flag.Arg(0)
resource.ReportSingleApp(appName, "")
}

View File

@@ -1,26 +0,0 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// writes the resource key to stdout for a given app container
func main() {
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(1)
resourceType := flag.Arg(2)
key := flag.Arg(3)
value, err := resource.GetResourceValue(appName, processType, resourceType, key)
if err != nil {
common.LogFail(err.Error())
}
fmt.Fprintln(os.Stdout, value)
}

View File

@@ -0,0 +1,46 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
"github.com/dokku/dokku/plugins/resource"
)
// main entrypoint to all triggers
func main() {
parts := strings.Split(os.Args[0], "/")
trigger := parts[len(parts)-1]
flag.Parse()
var err error
switch trigger {
case "docker-args-process-deploy":
appName := flag.Arg(0)
processType := flag.Arg(3)
err = resource.TriggerDockerArgsProcessDeploy(appName, processType)
case "install":
err = resource.TriggerInstall()
case "post-delete":
appName := flag.Arg(0)
err = resource.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
resource.ReportSingleApp(appName, "")
case "resource-get-property":
appName := flag.Arg(0)
processType := flag.Arg(1)
resourceType := flag.Arg(2)
key := flag.Arg(3)
err = resource.TriggerResourceGetProperty(appName, processType, resourceType, key)
default:
common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger))
}
if err != nil {
common.LogFail(err.Error())
}
}

View File

@@ -2,6 +2,8 @@ package resource
import (
"fmt"
"strings"
"github.com/dokku/dokku/plugins/common"
)
@@ -26,6 +28,27 @@ func CommandLimitClear(args []string, processType string) error {
return nil
}
// CommandReport displays a resource report for one or more apps
func CommandReport(appName string, infoFlag string) {
if strings.HasPrefix(appName, "--") {
infoFlag = appName
appName = ""
}
if len(appName) == 0 {
apps, err := common.DokkuApps()
if err != nil {
return
}
for _, appName := range apps {
ReportSingleApp(appName, infoFlag)
}
return
}
ReportSingleApp(appName, infoFlag)
}
// CommandReserve implements resource:reserve
func CommandReserve(args []string, processType string, r Resource) error {
appName, err := getAppName(args)

View File

@@ -1,7 +1,6 @@
package main
package resource
import (
"flag"
"fmt"
"io/ioutil"
"os"
@@ -10,26 +9,22 @@ import (
"github.com/dokku/dokku/plugins/common"
)
// outputs the process-specific docker options
func main() {
// TriggerDockerArgsProcessDeploy outputs the process-specific docker options
func TriggerDockerArgsProcessDeploy(appName string, processType string) error {
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
common.LogFail(err.Error())
return err
}
flag.Parse()
appName := flag.Arg(0)
processType := flag.Arg(3)
if os.Getenv("DOKKU_OMIT_RESOURCE_ARGS") == "1" {
fmt.Print(string(stdin))
return
return nil
}
resources, err := common.PropertyGetAll("resource", appName)
if err != nil {
fmt.Print(string(stdin))
return
return nil
}
limits := make(map[string]string)
@@ -86,4 +81,29 @@ func main() {
}
fmt.Print(string(stdin))
return nil
}
// TriggerInstall runs the install step for the resource plugin
func TriggerInstall() error {
if err := common.PropertySetup("resource"); err != nil {
return fmt.Errorf("Unable to install the resource plugin: %v", err)
}
return nil
}
// TriggerPostDelete destroys the resource property for a given app container
func TriggerPostDelete(appName string) error {
return common.PropertyDestroy("resource", appName)
}
// TriggerResourceGetProperty writes the resource key to stdout for a given app container
func TriggerResourceGetProperty(appName string, processType string, resourceType string, key string) error {
value, err := GetResourceValue(appName, processType, resourceType, key)
if err != nil {
return err
}
fmt.Fprintln(os.Stdout, value)
return nil
}

View File

@@ -79,6 +79,7 @@ scheduler-docker-local-check-deploy() {
local TIMEOUT="${DOKKU_CHECKS_TIMEOUT:-30}"
# use this number of retries for checks
local ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}"
local CHECKS_URL="${DOKKU_CHECKS_URL:-http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/}"
local CHECK_DEPLOY_TMP_WORK_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
local CHECKS_FILENAME=${CHECK_DEPLOY_TMP_WORK_DIR}/CHECKS
@@ -101,9 +102,8 @@ scheduler-docker-local-check-deploy() {
if [[ ! -s "${CHECKS_FILENAME}" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then
# We allow custom check for web instances only
if [[ "$DOKKU_APP_CONTAINER_TYPE" == "web" ]]; then
dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS."
dokku_log_verbose "See http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/ for examples"
dokku_log_verbose "CHECKS file not found in container: Running simple container check..."
dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS. See ${CHECKS_URL} for examples"
else
dokku_log_verbose "Non web container detected: Running default container check..."
fi
@@ -116,10 +116,10 @@ scheduler-docker-local-check-deploy() {
sleep "$DOKKU_DEFAULT_CHECKS_WAIT"
! (is_container_status "$DOKKU_APP_CONTAINER_ID" "Running") && dokku_log_fail "App container failed to start!!"
local container_restarts="$("$DOCKER_BIN" inspect -f "{{ .RestartCount }}" "$DOKKU_APP_CONTAINER_ID")"
local container_restarts="$("$DOCKER_BIN" container inspect --format "{{ .RestartCount }}" "$DOKKU_APP_CONTAINER_ID")"
if [[ $container_restarts -ne 0 ]]; then
"$DOCKER_BIN" container update --restart=no "$DOKKU_APP_CONTAINER_ID" &>/dev/null || true
"$DOCKER_BIN" stop "$DOKKU_APP_CONTAINER_ID" || true
"$DOCKER_BIN" container stop "$DOKKU_APP_CONTAINER_ID" || true
dokku_log_fail "App container failed to start!!"
fi

View File

@@ -37,26 +37,26 @@ scheduler-docker-local-core-post-deploy() {
local NAME="$APP.$DYNO"
local CURRENT_CONTAINER_ID="$(<"$container")"
# TODO: Ensure these are from the current service
local PREVIOUS_CIDS=$("$DOCKER_BIN" ps -a -q -f name="^.?$NAME\$" | xargs) || true
local PREVIOUS_CIDS=$("$DOCKER_BIN" container list --all --quiet --filter name="^.?$NAME\$" | xargs) || true
if [[ -n $PREVIOUS_CIDS ]]; then
dokku_log_verbose_quiet "Found previous container(s) ($PREVIOUS_CIDS) named $NAME"
# in case $PREVIOUS_CIDS has more than one entry
local cid
for cid in $PREVIOUS_CIDS; do
local PREVIOUS_CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f '{{.State.Status}}' "$cid" || echo "dead")
local PREVIOUS_CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Status}}' "$cid" || echo "dead")
# dead containers cannot be renamed
if [[ "$PREVIOUS_CONTAINER_STATUS" != "dead" ]]; then
local CONTAINER_DATE_NAME="$NAME.$(date +%s)"
dokku_log_verbose_quiet "Renaming container ($cid) ${NAME} to $CONTAINER_DATE_NAME"
"$DOCKER_BIN" rename "$NAME" "$CONTAINER_DATE_NAME" >/dev/null 2>&1 || dokku_log_warn "Unable to rename container"
"$DOCKER_BIN" container rename "$NAME" "$CONTAINER_DATE_NAME" >/dev/null 2>&1 || dokku_log_warn "Unable to rename container"
fi
done
fi
local ID=$(cat "$container")
local CURRENT_NAME=$("$DOCKER_BIN" inspect -f '{{.Name}}' "$ID" | tr -d /)
local CURRENT_NAME=$("$DOCKER_BIN" container inspect --format '{{.Name}}' "$ID" | tr -d /)
if [[ -n "$CURRENT_NAME" ]]; then
dokku_log_verbose_quiet "Renaming container (${ID:0:12}) $CURRENT_NAME to $NAME"
"$DOCKER_BIN" rename "$CURRENT_NAME" "$NAME" >/dev/null
"$DOCKER_BIN" container rename "$CURRENT_NAME" "$NAME" >/dev/null
fi
done
shopt -u nullglob

View File

@@ -95,7 +95,7 @@ fn-scheduler-docker-local-retire-container() {
declare APP="$1" CID="$2" DEAD_TIME="$3"
local STATE
STATE="$("$DOCKER_BIN" inspect -f "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
if [[ -z "$STATE" ]]; then
return
fi
@@ -104,7 +104,7 @@ fn-scheduler-docker-local-retire-container() {
[[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}"
if [[ "$STATE" == "restarting" ]]; then
"$DOCKER_BIN" update --restart=no "$CID" >/dev/null 2>&1
"$DOCKER_BIN" container update --restart=no "$CID" >/dev/null 2>&1
fi
if [[ "$STATE" != "dead" ]] && [[ "$STATE" != "exited" ]]; then
@@ -112,18 +112,18 @@ fn-scheduler-docker-local-retire-container() {
# to not send SIGKILL as the docs would indicate. If that fails, move
# on to the next.
# shellcheck disable=SC2086
"$DOCKER_BIN" stop $DOCKER_STOP_TIME_ARG "$CID" \
|| "$DOCKER_BIN" kill "$CID" \
"$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$CID" \
|| "$DOCKER_BIN" container kill "$CID" \
|| dokku_log_warn "Unable to kill container ${CID}"
fi
STATE="$("$DOCKER_BIN" inspect -f "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)"
if [[ -z "$STATE" ]]; then
return
fi
if [[ "$STATE" != "dead" ]] && [[ "$STATE" != "exited" ]]; then
if ! "$DOCKER_BIN" kill "$CID"; then
if ! "$DOCKER_BIN" container kill "$CID"; then
dokku_log_warn "Unable to kill container ${CID}"
fi
fi

Some files were not shown because too many files have changed in this diff Show More