diff --git a/docs/deployment/application-management.md b/docs/deployment/application-management.md index 9d58be15d..b738caede 100644 --- a/docs/deployment/application-management.md +++ b/docs/deployment/application-management.md @@ -134,6 +134,12 @@ Renaming node-js-app to io-js-app... done This will copy all of your app's contents into a new app directory with the name of your choice, delete your old app, then rebuild the new version of the app and deploy it. All of your config variables, including database urls, will be preserved. +By default, Dokku will deploy the renamed app, though you can skip the deploy by using the `--skip-deploy` flag: + +```shell +dokku apps:rename --skip-deploy node-js-app io-js-app +``` + ### Cloning an existing app > New as of 0.11.5 @@ -157,7 +163,7 @@ This will copy all of your app's contents into a new app directory with the name > Warning: If you have exposed specific ports via `docker-options` plugin, or performed anything that cannot be done against multiple applications, `apps:clone` may result in errors. -By default, Dokku will deploy this new application, though you can skip the deploy by using the `--skip-deploy` flag: +By default, Dokku will deploy this new app, though you can skip the deploy by using the `--skip-deploy` flag: ```shell dokku apps:clone --skip-deploy node-js-app io-js-app diff --git a/docs/development/plugin-triggers.md b/docs/development/plugin-triggers.md index 202c74a9d..6f884fc72 100644 --- a/docs/development/plugin-triggers.md +++ b/docs/development/plugin-triggers.md @@ -527,7 +527,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x ### `network-clear-config` - Description: Clears network configuration -- Invoked by: `internally triggered by proxy-clear-config within proxy implementations` +- Invoked by: `internally triggered within proxy implementations` - Arguments: `$APP` - Example: diff --git a/plugins/20_events/post-app-rename-setup b/plugins/20_events/post-app-rename-setup new file mode 120000 index 000000000..5178a749f --- /dev/null +++ b/plugins/20_events/post-app-rename-setup @@ -0,0 +1 @@ +hook \ No newline at end of file diff --git a/plugins/apps/subcommands/clone b/plugins/apps/subcommands/clone index 7ba17a6a9..960b20569 100755 --- a/plugins/apps/subcommands/clone +++ b/plugins/apps/subcommands/clone @@ -21,8 +21,6 @@ cmd-apps-clone() { OLD_APP="$1" NEW_APP="$2" [[ -z "$OLD_APP" ]] && dokku_log_fail "Please specify an app to run the command on" - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" - is_valid_app_name "$OLD_APP" is_valid_app_name "$NEW_APP" apps_exists "$OLD_APP" >/dev/null 2>&1 || dokku_log_fail "App does not exist" @@ -35,24 +33,10 @@ cmd-apps-clone() { dokku_log_fail "Name is already taken" fi - local NEW_CACHE_DIR="$DOKKU_ROOT/$NEW_APP/cache" - local NEW_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$NEW_APP/cache" - + dokku_log_info1_quiet "Cloning $OLD_APP to $NEW_APP" apps_create "$NEW_APP" - pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null - find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" - popd >/dev/null 2>&1 || pushd "/tmp" >/dev/null plugn trigger post-app-clone-setup "$OLD_APP" "$NEW_APP" - - if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then - "$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" - - [[ -f "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" ]] && sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" - [[ "$SKIP_REBUILD" == "true" ]] || ps_rebuild "$NEW_APP" - plugn trigger post-app-clone "$OLD_APP" "$NEW_APP" - dokku_log_info1_quiet "Cloning $OLD_APP to $NEW_APP... done" + SKIP_REBUILD=$SKIP_REBUILD plugn trigger post-app-clone "$OLD_APP" "$NEW_APP" } cmd-apps-clone "$@" diff --git a/plugins/apps/subcommands/rename b/plugins/apps/subcommands/rename index 0ce98e154..803e4e8e2 100755 --- a/plugins/apps/subcommands/rename +++ b/plugins/apps/subcommands/rename @@ -10,29 +10,29 @@ cmd-apps-rename() { declare cmd="apps:rename" [[ "$1" == "$cmd" ]] && shift 1 declare OLD_APP="$1" NEW_APP="$2" + local SKIP_REBUILD=false + for arg in "$@"; do + [[ "$arg" == "--skip-deploy" ]] && shift 1 && SKIP_REBUILD=true + [[ "$arg" =~ ^--.* ]] || break + done + + OLD_APP="$1" NEW_APP="$2" [[ -z "$OLD_APP" ]] && dokku_log_fail "Please specify an app to run the command on" - [[ -d "$DOKKU_ROOT/$NEW_APP" ]] && dokku_log_fail "Name is already taken" - local OLD_CACHE_DIR="$DOKKU_ROOT/$OLD_APP/cache" - local OLD_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$OLD_APP/cache" - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$OLD_APP" + is_valid_app_name "$OLD_APP" + is_valid_app_name "$NEW_APP" + apps_exists "$OLD_APP" >/dev/null 2>&1 || dokku_log_fail "App does not exist" - if [[ -d "$OLD_CACHE_DIR" ]] && ! rmdir "$OLD_CACHE_DIR" >/dev/null 2>&1; then - "$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 + if apps_exists "$NEW_APP" >/dev/null 2>&1; then + dokku_log_fail "Name is already taken" fi - rm -rf "$OLD_CACHE_DIR" + + dokku_log_info1_quiet "Renaming $OLD_APP to $NEW_APP" apps_create "$NEW_APP" - cp -a "$DOKKU_ROOT/$OLD_APP/." "$DOKKU_ROOT/$NEW_APP" - plugn trigger proxy-clear-config "$NEW_APP" + plugn trigger post-app-rename-setup "$OLD_APP" "$NEW_APP" DOKKU_APPS_FORCE_DELETE=1 apps_destroy "$OLD_APP" - [[ -f "$DOKKU_ROOT/$NEW_APP/URLS" ]] && sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/URLS" - [[ -f "$DOKKU_ROOT/$NEW_APP/VHOST" ]] && sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/VHOST" - [[ -f "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" ]] && sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" - ps_rebuild "$NEW_APP" - plugn trigger post-app-rename "$OLD_APP" "$NEW_APP" - docker_cleanup "$OLD_APP" "true" - echo "Renaming $OLD_APP to $NEW_APP... done" + SKIP_REBUILD=$SKIP_REBUILD plugn trigger post-app-rename "$OLD_APP" "$NEW_APP" } cmd-apps-rename "$@" diff --git a/plugins/builder-herokuish/post-app-clone-setup b/plugins/builder-herokuish/post-app-clone-setup new file mode 100755 index 000000000..5d79dda88 --- /dev/null +++ b/plugins/builder-herokuish/post-app-clone-setup @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" + +trigger-builder-herokuish-post-app-clone-setup() { + declare desc="builder-herokuish post-app-clone-setup plugin trigger" + declare trigger="post-app-clone-setup" + declare OLD_APP="$1" NEW_APP="$2" + + local NEW_CACHE_DIR="$DOKKU_ROOT/$NEW_APP/cache" + local NEW_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$NEW_APP/cache" + + pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null + find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" + popd >/dev/null 2>&1 || pushd "/tmp" >/dev/null + + if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then + local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" + "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$NEW_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache + fi + rm -rf "$NEW_CACHE_DIR" +} + +trigger-builder-herokuish-post-app-clone-setup "$@" diff --git a/plugins/builder-herokuish/post-app-rename-setup b/plugins/builder-herokuish/post-app-rename-setup new file mode 100755 index 000000000..8c8d8ddfe --- /dev/null +++ b/plugins/builder-herokuish/post-app-rename-setup @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" + +trigger-builder-herokuish-post-app-clone-setup() { + declare desc="builder-herokuish post-app-clone-setup plugin trigger" + declare trigger="post-app-clone-setup" + declare OLD_APP="$1" NEW_APP="$2" + + local OLD_CACHE_DIR="$DOKKU_ROOT/$OLD_APP/cache" + local OLD_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$OLD_APP/cache" + + if [[ -d "$OLD_CACHE_DIR" ]] && ! rmdir "$OLD_CACHE_DIR" >/dev/null 2>&1; then + local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" + "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$OLD_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache + fi + rm -rf "$OLD_CACHE_DIR" + + pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null + find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" + popd >/dev/null 2>&1 || pushd "/tmp" >/dev/null +} + +trigger-builder-herokuish-post-app-clone-setup "$@" diff --git a/plugins/buildpacks/.gitignore b/plugins/buildpacks/.gitignore index 053d0cfd9..291036bd4 100644 --- a/plugins/buildpacks/.gitignore +++ b/plugins/buildpacks/.gitignore @@ -3,6 +3,5 @@ /triggers/* /triggers /install -/post-delete -/post-extract +/post-* /report diff --git a/plugins/buildpacks/Makefile b/plugins/buildpacks/Makefile index 74a13c23e..700601cc5 100644 --- a/plugins/buildpacks/Makefile +++ b/plugins/buildpacks/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/add subcommands/clear subcommands/list subcommands/remove subcommands/report subcommands/set -TRIGGERS = triggers/install triggers/post-delete triggers/post-extract triggers/report +TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/post-extract triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = buildpacks diff --git a/plugins/buildpacks/src/triggers/triggers.go b/plugins/buildpacks/src/triggers/triggers.go index 83e01740b..d8d3420cf 100644 --- a/plugins/buildpacks/src/triggers/triggers.go +++ b/plugins/buildpacks/src/triggers/triggers.go @@ -16,9 +16,18 @@ func main() { trigger := parts[len(parts)-1] flag.Parse() + var err error switch trigger { case "install": buildpacks.TriggerInstall() + case "post-app-clone-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = buildpacks.TriggerPostAppCloneSetup(oldAppName, newAppName) + case "post-app-rename-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = buildpacks.TriggerPostAppRenameSetup(oldAppName, newAppName) case "post-delete": appName := flag.Arg(0) buildpacks.TriggerPostDelete(appName) @@ -32,4 +41,8 @@ func main() { default: common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger)) } + + if err != nil { + common.LogFail(err.Error()) + } } diff --git a/plugins/buildpacks/triggers.go b/plugins/buildpacks/triggers.go index d06e387e4..26481c634 100644 --- a/plugins/buildpacks/triggers.go +++ b/plugins/buildpacks/triggers.go @@ -16,6 +16,29 @@ func TriggerInstall() { } } +// TriggerPostAppCloneSetup creates new buildpacks files +func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { + err := common.PropertyClone("buildpacks", oldAppName, newAppName) + if err != nil { + return err + } + + return nil +} + +// TriggerPostAppRenameSetup renames buildpacks files +func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { + if err := common.PropertyClone("buildpacks", oldAppName, newAppName); err != nil { + return err + } + + if err := common.PropertyDestroy("buildpacks", oldAppName); err != nil { + return err + } + + return nil +} + // TriggerPostDelete destroys the buildpacks property for a given app container func TriggerPostDelete(appName string) { err := common.PropertyDestroy("buildpacks", appName) diff --git a/plugins/common/properties.go b/plugins/common/properties.go index cbbf75349..5c5971fab 100644 --- a/plugins/common/properties.go +++ b/plugins/common/properties.go @@ -44,6 +44,22 @@ func CommandPropertySet(pluginName, appName, property, value string, properties } } +// PropertyClone clones a set of properties from one app to another +func PropertyClone(pluginName string, oldAppName string, newAppName string) error { + properties, err := PropertyGetAll(pluginName, oldAppName) + if err != nil { + return nil + } + + for property, value := range properties { + if err := PropertyWrite(pluginName, newAppName, property, value); err != nil { + return err + } + } + + return nil +} + // PropertyDelete deletes a property from the plugin properties for an app func PropertyDelete(pluginName string, appName string, property string) error { propertyPath := getPropertyPath(pluginName, appName, property) diff --git a/plugins/common/property-functions b/plugins/common/property-functions index 6c8d0fffe..8f20ad8b4 100755 --- a/plugins/common/property-functions +++ b/plugins/common/property-functions @@ -9,10 +9,16 @@ fn-plugin-property-get() { fn-plugin-property-get-default "$PLUGIN" "$APP" "$KEY" "$DEFAULT" } +fn-plugin-property-clone() { + declare desc="destroy the properties for an app" + declare PLUGIN="$1" OLD_APP="$2" NEW_APP="$3" + "$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "clone" "$PLUGIN" "$OLD_APP" "$NEW_APP" +} + fn-plugin-property-destroy() { declare desc="destroy the properties for an app" declare PLUGIN="$1" APP="$2" - "$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "destroy" "$PLUGIN" "$APP" "$KEY" + "$PLUGIN_CORE_AVAILABLE_PATH/common/prop" "destroy" "$PLUGIN" "$APP" } fn-plugin-property-delete() { diff --git a/plugins/common/src/prop/prop.go b/plugins/common/src/prop/prop.go index f72d970b2..8614d9a0f 100644 --- a/plugins/common/src/prop/prop.go +++ b/plugins/common/src/prop/prop.go @@ -33,12 +33,78 @@ func main() { pluginName := flag.Arg(1) switch cmd { - case "rpush": + case "clone": + oldAppName := flag.Arg(2) + newAppName := flag.Arg(3) + err := common.PropertyClone(pluginName, oldAppName, newAppName) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + case "del": + appName := flag.Arg(2) + property := flag.Arg(3) + err := common.PropertyDelete(pluginName, appName, property) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + case "destroy": + appName := flag.Arg(2) + err := common.PropertyDestroy(pluginName, appName) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + case "exists": + appName := flag.Arg(2) + property := flag.Arg(3) + exists := common.PropertyExists(pluginName, appName, property) + if !exists { + os.Exit(1) + } + case "get": + appName := flag.Arg(2) + property := flag.Arg(3) + value := common.PropertyGet(pluginName, appName, property) + if value != "" { + fmt.Printf("%v\n", value) + } + case "get-all": + appName := flag.Arg(2) + values, err := common.PropertyGetAll(pluginName, appName) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + for key, value := range values { + fmt.Fprintln(os.Stdout, key, strings.TrimSuffix(value, "\n")) + } + case "get-with-default": + appName := flag.Arg(2) + property := flag.Arg(3) + defaultValue := flag.Arg(4) + value := common.PropertyGetDefault(pluginName, appName, property, defaultValue) + if value != "" { + fmt.Printf("%v\n", value) + } + case "lindex": + appName := flag.Arg(2) + property := flag.Arg(3) + index := strToInt(flag.Arg(4), 0, false) + propertyValue, err := common.PropertyListGetByIndex(pluginName, appName, property, index) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + fmt.Printf("%v\n", propertyValue) + case "lismember": appName := flag.Arg(2) property := flag.Arg(3) value := flag.Arg(4) - index := strToInt(flag.Arg(5), 0, true) - err := common.PropertyListAdd(pluginName, appName, property, value, index) + _, err := common.PropertyListGetByValue(pluginName, appName, property, value) if err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) @@ -65,26 +131,6 @@ func main() { for _, line := range lines { fmt.Printf("%v\n", line) } - case "lindex": - appName := flag.Arg(2) - property := flag.Arg(3) - index := strToInt(flag.Arg(4), 0, false) - propertyValue, err := common.PropertyListGetByIndex(pluginName, appName, property, index) - if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) - } - - fmt.Printf("%v\n", propertyValue) - case "lismember": - appName := flag.Arg(2) - property := flag.Arg(3) - value := flag.Arg(4) - _, err := common.PropertyListGetByValue(pluginName, appName, property, value) - if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) - } case "lrem": appName := flag.Arg(2) property := flag.Arg(3) @@ -113,6 +159,16 @@ func main() { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } + case "rpush": + appName := flag.Arg(2) + property := flag.Arg(3) + value := flag.Arg(4) + index := strToInt(flag.Arg(5), 0, true) + err := common.PropertyListAdd(pluginName, appName, property, value, index) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } case "set": appName := flag.Arg(2) property := flag.Arg(3) @@ -122,60 +178,11 @@ func main() { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } - case "get": - appName := flag.Arg(2) - property := flag.Arg(3) - value := common.PropertyGet(pluginName, appName, property) - if value != "" { - fmt.Printf("%v\n", value) - } - case "get-with-default": - appName := flag.Arg(2) - property := flag.Arg(3) - defaultValue := flag.Arg(4) - value := common.PropertyGetDefault(pluginName, appName, property, defaultValue) - if value != "" { - fmt.Printf("%v\n", value) - } - case "get-all": - appName := flag.Arg(2) - values, err := common.PropertyGetAll(pluginName, appName) - if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) - } - - for key, value := range values { - fmt.Fprintln(os.Stdout, key, strings.TrimSuffix(value, "\n")) - } - case "exists": - appName := flag.Arg(2) - property := flag.Arg(3) - exists := common.PropertyExists(pluginName, appName, property) - if !exists { - os.Exit(1) - } - case "del": - appName := flag.Arg(2) - property := flag.Arg(3) - err := common.PropertyDelete(pluginName, appName, property) - if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) - } case "setup": err := common.PropertySetup(pluginName) if err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } - case "destroy": - appName := flag.Arg(2) - err := common.PropertyDestroy(pluginName, appName) - if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) - } - } } diff --git a/plugins/domains/post-app-rename-setup b/plugins/domains/post-app-rename-setup new file mode 100755 index 000000000..7a2d2a5ff --- /dev/null +++ b/plugins/domains/post-app-rename-setup @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-domains-post-app-rename-setup() { + declare desc="updates VHOST and URLS files during rename" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + + if [[ -f "$DOKKU_ROOT/$NEW_APP/URLS" ]]; then + sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/URLS" + fi + if [[ -f "$DOKKU_ROOT/$NEW_APP/VHOST" ]]; then + sed -i -e "s/$OLD_APP/$NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/VHOST" + fi +} + +trigger-domains-post-app-rename-setup "$@" diff --git a/plugins/git/post-app-clone-setup b/plugins/git/post-app-clone-setup new file mode 100755 index 000000000..b0d6a21c0 --- /dev/null +++ b/plugins/git/post-app-clone-setup @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" + +trigger-git-post-app-clone-setup() { + declare desc="modifies git-hook" + declare trigger="post-app-clone-setup" + declare OLD_APP="$1" NEW_APP="$2" + + if [[ -f "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" ]]; then + sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" + fi + + fn-plugin-property-clone "git" "$OLD_APP" "$NEW_APP" +} + +trigger-git-post-app-clone-setup "$@" diff --git a/plugins/git/post-app-rename-setup b/plugins/git/post-app-rename-setup new file mode 100755 index 000000000..960d10461 --- /dev/null +++ b/plugins/git/post-app-rename-setup @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" + +trigger-git-post-app-rename-setup() { + declare desc="modifies git-hook" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + + if [[ -f "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" ]]; then + sed -i -e "s/git-hook $OLD_APP/git-hook $NEW_APP/g" "$DOKKU_ROOT/$NEW_APP/hooks/pre-receive" + fi + + fn-plugin-property-clone "git" "$OLD_APP" "$NEW_APP" + fn-plugin-property-destroy "git" "$OLD_APP" +} + +trigger-git-post-app-rename-setup "$@" diff --git a/plugins/network/Makefile b/plugins/network/Makefile index fe23e2813..32a94414d 100644 --- a/plugins/network/Makefile +++ b/plugins/network/Makefile @@ -1,5 +1,5 @@ SUBCOMMANDS = subcommands/create subcommands/destroy subcommands/exists subcommands/info subcommands/list subcommands/rebuild subcommands/rebuildall subcommands/report subcommands/set -TRIGGERS = triggers/core-post-deploy 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-container-create triggers/post-create triggers/post-delete triggers/report +TRIGGERS = triggers/core-post-deploy 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-app-rename-setup triggers/post-container-create triggers/post-create triggers/post-delete triggers/report BUILD = commands subcommands triggers PLUGIN_NAME = network diff --git a/plugins/network/network.go b/plugins/network/network.go index 149fc3ff8..4516b36ed 100644 --- a/plugins/network/network.go +++ b/plugins/network/network.go @@ -188,8 +188,8 @@ func HasNetworkConfig(appName string) bool { return common.FileExists(ipfile) && common.FileExists(portfile) } -// PostAppCloneSetup removes old IP and PORT files for a newly cloned app -func PostAppCloneSetup(appName string) bool { +// ClearNetworkConfig removes old IP and PORT files for a newly cloned app +func ClearNetworkConfig(appName string) bool { dokkuRoot := common.MustGetEnv("DOKKU_ROOT") appRoot := strings.Join([]string{dokkuRoot, appName}, "/") success := true diff --git a/plugins/network/src/triggers/triggers.go b/plugins/network/src/triggers/triggers.go index 24bdd96d0..ce4b26872 100644 --- a/plugins/network/src/triggers/triggers.go +++ b/plugins/network/src/triggers/triggers.go @@ -16,6 +16,7 @@ func main() { trigger := parts[len(parts)-1] flag.Parse() + var err error switch trigger { case "install": network.TriggerInstall() @@ -61,8 +62,13 @@ func main() { port := flag.Arg(3) network.TriggerNetworkWritePort(appName, processType, containerIndex, port) case "post-app-clone-setup": - appName := flag.Arg(1) - network.TriggerPostAppCloneSetup(appName) + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = network.TriggerPostAppCloneSetup(oldAppName, newAppName) + case "post-app-rename-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = network.TriggerPostAppRenameSetup(oldAppName, newAppName) case "post-container-create": containerType := flag.Arg(0) containerID := flag.Arg(1) @@ -85,4 +91,8 @@ func main() { default: common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger)) } + + if err != nil { + common.LogFail(err.Error()) + } } diff --git a/plugins/network/triggers.go b/plugins/network/triggers.go index 8fa11724a..30b49d8b1 100644 --- a/plugins/network/triggers.go +++ b/plugins/network/triggers.go @@ -153,12 +153,37 @@ func TriggerNetworkWritePort(appName string, processType string, containerIndex } } -// TriggerPostAppCloneSetup cleans up network files for a new app clone -func TriggerPostAppCloneSetup(appName string) { - success := PostAppCloneSetup(appName) +// TriggerPostAppCloneSetup creates new network files +func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { + success := ClearNetworkConfig(newAppName) if !success { os.Exit(1) } + + err := common.PropertyClone("network", oldAppName, newAppName) + if err != nil { + return err + } + + return nil +} + +// TriggerPostAppRenameSetup renames network files +func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { + success := ClearNetworkConfig(newAppName) + if !success { + os.Exit(1) + } + + if err := common.PropertyClone("network", oldAppName, newAppName); err != nil { + return err + } + + if err := common.PropertyDestroy("network", oldAppName); err != nil { + return err + } + + return nil } // TriggerPostContainerCreate associates the container with a specified network diff --git a/plugins/nginx-vhosts/post-app-clone-setup b/plugins/nginx-vhosts/post-app-clone-setup index c35608d1f..181bb2a0a 100755 --- a/plugins/nginx-vhosts/post-app-clone-setup +++ b/plugins/nginx-vhosts/post-app-clone-setup @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -eo pipefail [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" trigger-nginx-vhosts-post-app-clone-setup() { declare desc="removes nginx files when setting up a clone" @@ -8,6 +9,7 @@ trigger-nginx-vhosts-post-app-clone-setup() { declare OLD_APP="$1" NEW_APP="$2" local APP_DIR="$DOKKU_ROOT/$NEW_APP" + fn-plugin-property-clone "nginx" "$OLD_APP" "$NEW_APP" rm -rf "$APP_DIR/nginx.conf" } diff --git a/plugins/nginx-vhosts/post-app-rename-setup b/plugins/nginx-vhosts/post-app-rename-setup new file mode 100755 index 000000000..598b4fbd7 --- /dev/null +++ b/plugins/nginx-vhosts/post-app-rename-setup @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions" +source "$PLUGIN_AVAILABLE_PATH/proxy/functions" + +trigger-nginx-vhosts-post-app-rename-setup() { + declare desc="calls proxy-clear-config" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + + fn-plugin-property-clone "nginx" "$OLD_APP" "$NEW_APP" + fn-plugin-property-destroy "nginx" "$OLD_APP" + plugn trigger proxy-clear-config "$NEW_APP" +} + +trigger-nginx-vhosts-post-app-rename-setup "$@" diff --git a/plugins/ps/post-app-clone b/plugins/ps/post-app-clone new file mode 100755 index 000000000..92fdefd7b --- /dev/null +++ b/plugins/ps/post-app-clone @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +trigger-ps-post-app-clone() { + declare desc="ps post-app-clone plugin trigger" + declare trigger="post-app-clone" + declare OLD_APP="$1" NEW_APP="$2" + + if [[ "$SKIP_REBUILD" != "true" ]]; then + ps_rebuild "$NEW_APP" + fi +} + +trigger-ps-post-app-clone "$@" diff --git a/plugins/ps/post-app-rename b/plugins/ps/post-app-rename new file mode 100755 index 000000000..7175b517b --- /dev/null +++ b/plugins/ps/post-app-rename @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/ps/functions" + +trigger-ps-post-app-rename() { + declare desc="ps post-app-rename plugin trigger" + declare trigger="post-app-rename" + declare OLD_APP="$1" NEW_APP="$2" + + if [[ "$SKIP_REBUILD" != "true" ]]; then + ps_rebuild "$NEW_APP" + fi +} + +trigger-ps-post-app-rename "$@" diff --git a/plugins/resource/.gitignore b/plugins/resource/.gitignore index a34683d35..1e1f0ddd2 100644 --- a/plugins/resource/.gitignore +++ b/plugins/resource/.gitignore @@ -3,7 +3,7 @@ /triggers/* /triggers /install -/post-delete +/post-* /report /docker-args-process-deploy /docker-args-process-run diff --git a/plugins/resource/Makefile b/plugins/resource/Makefile index ea16485f9..9357f9cc2 100644 --- a/plugins/resource/Makefile +++ b/plugins/resource/Makefile @@ -1,5 +1,5 @@ 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 +TRIGGERS = triggers/docker-args-process-deploy triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report triggers/resource-get-property BUILD = commands subcommands triggers PLUGIN_NAME = resource diff --git a/plugins/resource/src/triggers/triggers.go b/plugins/resource/src/triggers/triggers.go index 2bdf6d362..79d6e1e19 100644 --- a/plugins/resource/src/triggers/triggers.go +++ b/plugins/resource/src/triggers/triggers.go @@ -24,6 +24,14 @@ func main() { err = resource.TriggerDockerArgsProcessDeploy(appName, processType) case "install": err = resource.TriggerInstall() + case "post-app-clone-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = resource.TriggerPostAppCloneSetup(oldAppName, newAppName) + case "post-app-rename-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = resource.TriggerPostAppRenameSetup(oldAppName, newAppName) case "post-delete": appName := flag.Arg(0) err = resource.TriggerPostDelete(appName) diff --git a/plugins/resource/triggers.go b/plugins/resource/triggers.go index 4b9469a79..cf2dddb06 100644 --- a/plugins/resource/triggers.go +++ b/plugins/resource/triggers.go @@ -92,6 +92,29 @@ func TriggerInstall() error { return nil } +// TriggerPostAppCloneSetup creates new resource files +func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { + err := common.PropertyClone("resource", oldAppName, newAppName) + if err != nil { + return err + } + + return nil +} + +// TriggerPostAppRenameSetup renames resource files +func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { + if err := common.PropertyClone("resource", oldAppName, newAppName); err != nil { + return err + } + + if err := common.PropertyDestroy("resource", oldAppName); err != nil { + return err + } + + return nil +} + // TriggerPostDelete destroys the resource property for a given app container func TriggerPostDelete(appName string) error { return common.PropertyDestroy("resource", appName) diff --git a/plugins/scheduler-docker-local/post-app-clone-setup b/plugins/scheduler-docker-local/post-app-clone-setup index f829496a5..1b3aa0e15 100755 --- a/plugins/scheduler-docker-local/post-app-clone-setup +++ b/plugins/scheduler-docker-local/post-app-clone-setup @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -eo pipefail [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" trigger-scheduler-docker-local-post-app-clone-setup() { declare desc="removes docker-local files when setting up a clone" @@ -8,6 +9,7 @@ trigger-scheduler-docker-local-post-app-clone-setup() { declare OLD_APP="$1" NEW_APP="$2" local APP_DIR="$DOKKU_ROOT/$NEW_APP" + fn-plugin-property-clone "scheduler-docker-local" "$OLD_APP" "$NEW_APP" find "$APP_DIR" -type f -name 'CONTAINER.*' -exec rm {} \; } diff --git a/plugins/scheduler-docker-local/post-app-rename-setup b/plugins/scheduler-docker-local/post-app-rename-setup new file mode 100755 index 000000000..c810bc8db --- /dev/null +++ b/plugins/scheduler-docker-local/post-app-rename-setup @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" + +trigger-scheduler-docker-local-post-app-rename-setup() { + declare desc="updates settings when renaming an app" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + local APP_DIR="$DOKKU_ROOT/$NEW_APP" + + fn-plugin-property-clone "scheduler-docker-local" "$OLD_APP" "$NEW_APP" + fn-plugin-property-destroy "scheduler-docker-local" "$OLD_APP" +} + +trigger-scheduler-docker-local-post-app-rename-setup "$@" diff --git a/tests/unit/10_apps.bats b/tests/unit/10_apps.bats index 0c3464224..e943d809e 100644 --- a/tests/unit/10_apps.bats +++ b/tests/unit/10_apps.bats @@ -117,10 +117,67 @@ teardown() { echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku apps:rename $TEST_APP great-test-name" + + run /bin/bash -c "dokku buildpacks:add $TEST_APP https://github.com/heroku/heroku-buildpack-ruby.git" echo "output: $output" echo "status: $status" assert_success + run /bin/bash -c "dokku git:set $TEST_APP deploy-branch SOME_BRANCH_NAME" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku network:set $TEST_APP attach-post-create test-network" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku nginx:set $TEST_APP bind-address-ipv4 127.0.0.1" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku resource:limit --memory 100 $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku scheduler-docker-local:set $TEST_APP disable-chown true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku --trace apps:rename $TEST_APP great-test-name" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku buildpacks:report great-test-name --buildpacks-list" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "https://github.com/heroku/heroku-buildpack-ruby.git" + run /bin/bash -c "dokku git:report great-test-name --git-deploy-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "SOME_BRANCH_NAME" + run /bin/bash -c "dokku network:report great-test-name --network-attach-post-create" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "test-network" + run /bin/bash -c "dokku nginx:report great-test-name --nginx-bind-address-ipv4" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "127.0.0.1" + run /bin/bash -c "dokku resource:report great-test-name --resource-_default_.limit.memory" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "100" + run /bin/bash -c "dokku scheduler-docker-local:report great-test-name --scheduler-docker-local-disable-chown" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "true" + run /bin/bash -c "dokku --force apps:destroy great-test-name" echo "output: $output" echo "status: $status" @@ -160,6 +217,83 @@ teardown() { assert_success } +@test "(apps) apps:clone (no app)" { + run /bin/bash -c "dokku apps:create $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku buildpacks:add $TEST_APP https://github.com/heroku/heroku-buildpack-ruby.git" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku git:set $TEST_APP deploy-branch SOME_BRANCH_NAME" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku network:set $TEST_APP attach-post-create test-network" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku nginx:set $TEST_APP bind-address-ipv4 127.0.0.1" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku resource:limit --memory 100 $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku scheduler-docker-local:set $TEST_APP disable-chown true" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku apps:clone $TEST_APP great-test-name" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku apps:list | grep $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku buildpacks:report great-test-name --buildpacks-list" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "https://github.com/heroku/heroku-buildpack-ruby.git" + run /bin/bash -c "dokku git:report great-test-name --git-deploy-branch" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "SOME_BRANCH_NAME" + run /bin/bash -c "dokku network:report great-test-name --network-attach-post-create" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "test-network" + run /bin/bash -c "dokku nginx:report great-test-name --nginx-bind-address-ipv4" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "127.0.0.1" + run /bin/bash -c "dokku resource:report great-test-name --resource-_default_.limit.memory" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "100" + run /bin/bash -c "dokku scheduler-docker-local:report great-test-name --scheduler-docker-local-disable-chown" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "true" + + run /bin/bash -c "dokku --force apps:destroy great-test-name" + echo "output: $output" + echo "status: $status" + assert_success +} + @test "(apps) apps:clone ssl-app" { run /bin/bash -c "dokku config:set --no-restart $TEST_APP DOKKU_PROXY_PORT_MAP=https:443:5000 DOKKU_PROXY_SSL_PORT=443" deploy_app diff --git a/tests/unit/20_network.bats b/tests/unit/20_network.bats index 594651f3d..4eddaf925 100644 --- a/tests/unit/20_network.bats +++ b/tests/unit/20_network.bats @@ -85,32 +85,32 @@ teardown() { } @test "(network) network management" { - run /bin/bash -c "dokku network:list | grep test-network" + run /bin/bash -c "dokku network:list | grep $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_failure - run /bin/bash -c "dokku network:exists test-network" + run /bin/bash -c "dokku network:exists $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_failure - run /bin/bash -c "dokku network:create test-network" + run /bin/bash -c "dokku network:create $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku network:list | grep test-network" + run /bin/bash -c "dokku network:list | grep $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku network:create test-network" + run /bin/bash -c "dokku network:create $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_failure - run /bin/bash -c "dokku network:exists test-network" + run /bin/bash -c "dokku network:exists $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_success @@ -125,22 +125,22 @@ teardown() { echo "status: $status" assert_failure - run /bin/bash -c "dokku --force network:destroy test-network" + run /bin/bash -c "dokku --force network:destroy $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_success - run /bin/bash -c "dokku --force network:destroy test-network" + run /bin/bash -c "dokku --force network:destroy $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_failure - run /bin/bash -c "dokku network:exists test-network" + run /bin/bash -c "dokku network:exists $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_failure - run /bin/bash -c "dokku network:list | grep test-network" + run /bin/bash -c "dokku network:list | grep $TEST_NETWORK" echo "output: $output" echo "status: $status" assert_failure