From 135497afda29f35534f1d02c80f3d6be8a8ebc7d Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 25 Feb 2024 14:08:13 -0500 Subject: [PATCH 1/6] chore: remove unused code for copying cache directories This code no longer is necessary as cache directories are mounted from volumes instead of disk. --- .../builder-herokuish/post-app-clone-setup | 26 ------------------- .../builder-herokuish/post-app-rename-setup | 26 ------------------- 2 files changed, 52 deletions(-) delete mode 100755 plugins/builder-herokuish/post-app-clone-setup delete mode 100755 plugins/builder-herokuish/post-app-rename-setup diff --git a/plugins/builder-herokuish/post-app-clone-setup b/plugins/builder-herokuish/post-app-clone-setup deleted file mode 100755 index 3abb15417..000000000 --- a/plugins/builder-herokuish/post-app-clone-setup +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" - -trigger-builder-herokuish-post-app-clone-setup() { - declare desc="builder-herokuish post-app-clone-setup plugin trigger" - declare trigger="post-app-clone-setup" - declare OLD_APP="$1" NEW_APP="$2" - - local NEW_CACHE_DIR="$DOKKU_ROOT/$NEW_APP/cache" - local NEW_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$NEW_APP/cache" - - pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null - find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" - popd &>/dev/null || pushd "/tmp" >/dev/null - - if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" - "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$NEW_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache - fi - rm -rf "$NEW_CACHE_DIR" -} - -trigger-builder-herokuish-post-app-clone-setup "$@" diff --git a/plugins/builder-herokuish/post-app-rename-setup b/plugins/builder-herokuish/post-app-rename-setup deleted file mode 100755 index 26c5a6dbb..000000000 --- a/plugins/builder-herokuish/post-app-rename-setup +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" -source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" - -trigger-builder-herokuish-post-app-clone-setup() { - declare desc="builder-herokuish post-app-clone-setup plugin trigger" - declare trigger="post-app-clone-setup" - declare OLD_APP="$1" NEW_APP="$2" - - local OLD_CACHE_DIR="$DOKKU_ROOT/$OLD_APP/cache" - local OLD_CACHE_HOST_DIR="$DOKKU_HOST_ROOT/$OLD_APP/cache" - - if [[ -d "$OLD_CACHE_DIR" ]] && ! rmdir "$OLD_CACHE_DIR" &>/dev/null; then - local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$NEW_APP" - "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$OLD_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache - fi - rm -rf "$OLD_CACHE_DIR" - - pushd "$DOKKU_ROOT/$OLD_APP/." >/dev/null - find ./* \( -name ".cache" -o -name "cache" \) -prune -o -print | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP" - popd &>/dev/null || pushd "/tmp" >/dev/null -} - -trigger-builder-herokuish-post-app-clone-setup "$@" From c26a49bb4e5c9dd960f68c35a59db3c65301398a Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 25 Feb 2024 16:53:41 -0500 Subject: [PATCH 2/6] tests: add tests for config and docker options These two are also still stored in the app repo directory and not copied over as properties, so would be susceptible to not having the code copied over. --- tests/unit/apps_1.bats | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/unit/apps_1.bats b/tests/unit/apps_1.bats index 06ef1be1e..8e7fd3f2c 100644 --- a/tests/unit/apps_1.bats +++ b/tests/unit/apps_1.bats @@ -178,6 +178,14 @@ teardown() { echo "output: $output" echo "status: $status" assert_success + run /bin/bash -c "dokku config:set --no-restart $TEST_APP KEY=VALUE-$TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --no-healthcheck" + echo "output: $output" + echo "status: $status" + assert_success run /bin/bash -c "dokku git:set $TEST_APP deploy-branch SOME_BRANCH_NAME" echo "output: $output" echo "status: $status" @@ -204,6 +212,16 @@ teardown() { echo "status: $status" assert_success assert_output "https://github.com/heroku/heroku-buildpack-ruby.git" + run /bin/bash -c "dokku config:get great-test-name KEY" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "VALUE-$TEST_APP" + run /bin/bash -c "dokku docker-options:report great-test-name deploy --docker-options-deploy" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains "--no-healthcheck" run /bin/bash -c "dokku git:report great-test-name --git-deploy-branch" echo "output: $output" echo "status: $status" From 883809f35e7bb543ee0a1cf40896a7ba507852ce Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 25 Feb 2024 19:00:16 -0500 Subject: [PATCH 3/6] fix: properly rewrite domains when renaming an app --- plugins/domains/post-app-rename-setup | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/domains/post-app-rename-setup b/plugins/domains/post-app-rename-setup index 7cbce6a11..3ec256a9c 100755 --- a/plugins/domains/post-app-rename-setup +++ b/plugins/domains/post-app-rename-setup @@ -7,9 +7,9 @@ trigger-domains-post-app-rename-setup() { declare trigger="post-app-rename-setup" declare OLD_APP="$1" NEW_APP="$2" - if [[ -f "$DOKKU_ROOT/$NEW_APP/VHOST" ]]; then + if [[ -f "$DOKKU_ROOT/$OLD_APP/VHOST" ]]; then while read -r VHOST || [[ -n "$VHOST" ]]; do - sed -i -e "s/$OLD_APP.$VHOST/$NEW_APP.$VHOST/g" "$DOKKU_ROOT/$NEW_APP/VHOST" + sed -e "s/$OLD_APP.$VHOST/$NEW_APP.$VHOST/g" "$DOKKU_ROOT/$OLD_APP/VHOST" >"$DOKKU_ROOT/$NEW_APP/VHOST" done <"$DOKKU_ROOT/VHOST" fi } From e0409caf757fa762e1db81be0425ad9a2c5bae9f Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 14 Mar 2024 00:25:25 -0400 Subject: [PATCH 4/6] fix: ensure env vars are copied over when cloning or renaming an app --- plugins/config/.gitignore | 1 + plugins/config/Makefile | 2 +- plugins/config/environment.go | 60 ++++++++++++------------- plugins/config/src/triggers/triggers.go | 8 ++++ plugins/config/triggers.go | 40 +++++++++++++++++ 5 files changed, 80 insertions(+), 31 deletions(-) diff --git a/plugins/config/.gitignore b/plugins/config/.gitignore index b79352e77..3b7e2f512 100644 --- a/plugins/config/.gitignore +++ b/plugins/config/.gitignore @@ -4,3 +4,4 @@ /triggers /config-* /config_sub +/post-* diff --git a/plugins/config/Makefile b/plugins/config/Makefile index e38a8f62d..86ffcb36b 100644 --- a/plugins/config/Makefile +++ b/plugins/config/Makefile @@ -1,6 +1,6 @@ GOARCH ?= amd64 SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset -TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global +TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global triggers/post-app-clone-setup triggers/post-app-rename-setup BUILD = commands config_sub subcommands triggers PLUGIN_NAME = config diff --git a/plugins/config/environment.go b/plugins/config/environment.go index 2f6ddf071..877939e5f 100644 --- a/plugins/config/environment.go +++ b/plugins/config/environment.go @@ -16,7 +16,7 @@ import ( "github.com/ryanuber/columnize" ) -//ExportFormat types of possible exports +// ExportFormat types of possible exports type ExportFormat int const ( @@ -40,14 +40,14 @@ const ( ExportFormatPackArgKeys ) -//Env is a representation for global or app environment +// Env is a representation for global or app environment type Env struct { name string filename string env map[string]string } -//newEnvFromString creates an env from the given ENVFILE contents representation +// newEnvFromString creates an env from the given ENVFILE contents representation func newEnvFromString(rep string) (env *Env, err error) { envMap, err := godotenv.Unmarshal(rep) env = &Env{ @@ -58,7 +58,7 @@ func newEnvFromString(rep string) (env *Env, err error) { return } -//LoadAppEnv loads an environment for the given app +// LoadAppEnv loads an environment for the given app func LoadAppEnv(appName string) (env *Env, err error) { appfile, err := getAppFile(appName) if err != nil { @@ -67,7 +67,7 @@ func LoadAppEnv(appName string) (env *Env, err error) { return loadFromFile(appName, appfile) } -//LoadMergedAppEnv loads an app environment merged with the global environment +// LoadMergedAppEnv loads an app environment merged with the global environment func LoadMergedAppEnv(appName string) (env *Env, err error) { env, err = LoadAppEnv(appName) if err != nil { @@ -83,7 +83,7 @@ func LoadMergedAppEnv(appName string) (env *Env, err error) { return global, err } -//LoadGlobalEnv loads the global environment +// LoadGlobalEnv loads the global environment func LoadGlobalEnv() (*Env, error) { return loadFromFile("", getGlobalFile()) } @@ -93,13 +93,13 @@ func (e *Env) Filename() string { return e.filename } -//Get an environment variable +// Get an environment variable func (e *Env) Get(key string) (value string, ok bool) { value, ok = e.env[key] return } -//GetDefault an environment variable or a default if it doesn't exist +// GetDefault an environment variable or a default if it doesn't exist func (e *Env) GetDefault(key string, defaultValue string) string { v, ok := e.env[key] if !ok { @@ -108,8 +108,8 @@ func (e *Env) GetDefault(key string, defaultValue string) string { return v } -//GetBoolDefault gets the bool value of the given key with the given default -//right now that is evaluated as `value != "0"` +// GetBoolDefault gets the bool value of the given key with the given default +// right now that is evaluated as `value != "0"` func (e *Env) GetBoolDefault(key string, defaultValue bool) bool { v, ok := e.Get(key) if !ok { @@ -118,17 +118,17 @@ func (e *Env) GetBoolDefault(key string, defaultValue bool) bool { return v != "0" } -//Set an environment variable +// Set an environment variable func (e *Env) Set(key string, value string) { e.env[key] = value } -//Unset an environment variable +// Unset an environment variable func (e *Env) Unset(key string) { delete(e.env, key) } -//Keys gets the keys in this environment +// Keys gets the keys in this environment func (e *Env) Keys() (keys []string) { keys = make([]string, 0, len(e.env)) for k := range e.env { @@ -138,12 +138,12 @@ func (e *Env) Keys() (keys []string) { return } -//Len returns the number of items in this environment +// Len returns the number of items in this environment func (e *Env) Len() int { return len(e.env) } -//Map returns the Env as a map +// Map returns the Env as a map func (e *Env) Map() map[string]string { return e.env } @@ -152,14 +152,14 @@ func (e *Env) String() string { return e.EnvfileString() } -//Merge merges the given environment on top of the receiver +// Merge merges the given environment on top of the receiver func (e *Env) Merge(other *Env) { for _, k := range other.Keys() { e.Set(k, other.GetDefault(k, "")) } } -//Write an Env back to the file it was read from as an exportfile +// Write an Env back to the file it was read from as an exportfile func (e *Env) Write() error { if e.filename == "" { return errors.New("this Env was created unbound to a file") @@ -167,7 +167,7 @@ func (e *Env) Write() error { return godotenv.Write(e.Map(), e.filename) } -//Export the Env in the given format +// Export the Env in the given format func (e *Env) Export(format ExportFormat) string { switch format { case ExportFormatExports: @@ -194,23 +194,23 @@ func (e *Env) Export(format ExportFormat) string { } } -//EnvfileString returns the contents of this Env in dotenv format +// EnvfileString returns the contents of this Env in dotenv format func (e *Env) EnvfileString() string { rep, _ := godotenv.Marshal(e.Map()) return rep } -//ExportfileString returns the contents of this Env as bash exports +// ExportfileString returns the contents of this Env as bash exports func (e *Env) ExportfileString() string { return e.stringWithPrefixAndSeparator("export ", "\n") } -//DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env... +// DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env... func (e *Env) DockerArgsString() string { return e.stringWithPrefixAndSeparator("--env=", " ") } -//DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env... +// DockerArgsKeysString gets the contents of this Env in the form -env=KEY --env... func (e *Env) DockerArgsKeysString() string { keys := e.Keys() entries := make([]string, len(keys)) @@ -220,7 +220,7 @@ func (e *Env) DockerArgsKeysString() string { return strings.Join(entries, " ") } -//JSONString returns the contents of this Env as a key/value json object +// JSONString returns the contents of this Env as a key/value json object func (e *Env) JSONString() string { data, err := json.Marshal(e.Map()) if err != nil { @@ -230,7 +230,7 @@ func (e *Env) JSONString() string { return string(data) } -//JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var +// JSONListString returns the contents of this Env as a json list of objects containing the name and the value of the env var func (e *Env) JSONListString() string { var list []map[string]string for _, key := range e.Keys() { @@ -249,7 +249,7 @@ func (e *Env) JSONListString() string { return string(data) } -//PackArgKeysAsString gets the contents of this Env in the form -env KEY --env... +// PackArgKeysAsString gets the contents of this Env in the form -env KEY --env... func (e *Env) PackArgKeysAsString() string { keys := e.Keys() entries := make([]string, len(keys)) @@ -259,13 +259,13 @@ func (e *Env) PackArgKeysAsString() string { return strings.Join(entries, " ") } -//ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'" +// ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'" // for passing the environment in the shell func (e *Env) ShellString() string { return e.stringWithPrefixAndSeparator("", " ") } -//ExportBundle writes a tarfile of the environment to the given io.Writer. +// ExportBundle writes a tarfile of the environment to the given io.Writer. // for every environment variable there is a file with the variable's key // with its content set to the variable's value func (e *Env) ExportBundle(dest io.Writer) error { @@ -287,7 +287,7 @@ func (e *Env) ExportBundle(dest io.Writer) error { return nil } -//stringWithPrefixAndSeparator makes a string of the environment +// stringWithPrefixAndSeparator makes a string of the environment // with the given prefix and separator for each entry func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) string { keys := e.Keys() @@ -299,12 +299,12 @@ func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) stri return strings.Join(entries, separator) } -//singleQuoteEscape escapes the value as if it were shell-quoted in single quotes +// singleQuoteEscape escapes the value as if it were shell-quoted in single quotes func singleQuoteEscape(value string) string { // so that 'esc'aped' -> 'esc'\''aped' return strings.Replace(value, "'", "'\\''", -1) } -//prettyPrintEnvEntries in columns +// prettyPrintEnvEntries in columns func prettyPrintEnvEntries(prefix string, entries map[string]string) string { colConfig := columnize.DefaultConfig() colConfig.Prefix = prefix diff --git a/plugins/config/src/triggers/triggers.go b/plugins/config/src/triggers/triggers.go index eec123a48..1f8f58732 100644 --- a/plugins/config/src/triggers/triggers.go +++ b/plugins/config/src/triggers/triggers.go @@ -36,6 +36,14 @@ func main() { case "config-get-global": key := flag.Arg(0) err = config.TriggerConfigGetGlobal(key) + case "post-app-clone-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = config.TriggerPostAppCloneSetup(oldAppName, newAppName) + case "post-app-rename-setup": + oldAppName := flag.Arg(0) + newAppName := flag.Arg(1) + err = config.TriggerPostAppRenameSetup(oldAppName, newAppName) default: err = fmt.Errorf("Invalid plugin trigger call: %s", trigger) } diff --git a/plugins/config/triggers.go b/plugins/config/triggers.go index 3014f6d26..af96d114c 100644 --- a/plugins/config/triggers.go +++ b/plugins/config/triggers.go @@ -44,3 +44,43 @@ func TriggerConfigGetGlobal(key string) error { return nil } + +// TriggerPostAppCloneSetup creates new buildpacks files +func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { + oldEnv, err := LoadAppEnv(oldAppName) + if err != nil { + return fmt.Errorf("Unable to load old environment: %s", err.Error()) + } + + newEnv, err := LoadAppEnv(newAppName) + if err != nil { + return fmt.Errorf("Unable to load new environment: %s", err.Error()) + } + + newEnv.Merge(oldEnv) + if err := newEnv.Write(); err != nil { + return fmt.Errorf("Unable to write new environment: %s", err.Error()) + } + + return nil +} + +// TriggerPostAppRenameSetup renames buildpacks files +func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { + oldEnv, err := LoadAppEnv(oldAppName) + if err != nil { + return fmt.Errorf("Unable to load old environment: %s", err.Error()) + } + + newEnv, err := LoadAppEnv(newAppName) + if err != nil { + return fmt.Errorf("Unable to load new environment: %s", err.Error()) + } + + newEnv.Merge(oldEnv) + if err := newEnv.Write(); err != nil { + return fmt.Errorf("Unable to write new environment: %s", err.Error()) + } + + return nil +} From 1cc8b3723da3c3d806ecc738da6129f7309d6e81 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 14 Mar 2024 00:25:35 -0400 Subject: [PATCH 5/6] fix: drop extra phase argument --- tests/unit/apps_1.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/apps_1.bats b/tests/unit/apps_1.bats index 8e7fd3f2c..5b85ffacd 100644 --- a/tests/unit/apps_1.bats +++ b/tests/unit/apps_1.bats @@ -217,7 +217,7 @@ teardown() { echo "status: $status" assert_success assert_output "VALUE-$TEST_APP" - run /bin/bash -c "dokku docker-options:report great-test-name deploy --docker-options-deploy" + run /bin/bash -c "dokku docker-options:report great-test-name --docker-options-deploy" echo "output: $output" echo "status: $status" assert_success From 0ea9e7aa42982e8e2845291d12d3fcf81ff621c2 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 14 Mar 2024 00:26:04 -0400 Subject: [PATCH 6/6] fix: copy over all phase files during an app rename or clone --- plugins/docker-options/post-app-clone-setup | 20 ++++++++++++++++++++ plugins/docker-options/post-app-rename-setup | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100755 plugins/docker-options/post-app-clone-setup create mode 100755 plugins/docker-options/post-app-rename-setup diff --git a/plugins/docker-options/post-app-clone-setup b/plugins/docker-options/post-app-clone-setup new file mode 100755 index 000000000..9b36b329d --- /dev/null +++ b/plugins/docker-options/post-app-clone-setup @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/docker-options/functions" + +trigger-docker-options-post-app-clone-setup() { + declare desc="copies docker options over" + declare trigger="post-app-clone-setup" + declare OLD_APP="$1" NEW_APP="$2" + + declare -a phases + phases=("build" "deploy" "run") + for phase in "${phases[@]}"; do + if [[ -f "$(fn-get-phase-file-path "$OLD_APP" "$phase")" ]]; then + cp "$(fn-get-phase-file-path "$OLD_APP" "$phase")" "$(fn-get-phase-file-path "$NEW_APP" "$phase")" + fi + done +} + +trigger-docker-options-post-app-clone-setup "$@" diff --git a/plugins/docker-options/post-app-rename-setup b/plugins/docker-options/post-app-rename-setup new file mode 100755 index 000000000..0688252a6 --- /dev/null +++ b/plugins/docker-options/post-app-rename-setup @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/docker-options/functions" + +trigger-docker-options-post-app-rename-setup() { + declare desc="copies docker options over" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + + declare -a phases + phases=("build" "deploy" "run") + for phase in "${phases[@]}"; do + if [[ -f "$(fn-get-phase-file-path "$OLD_APP" "$phase")" ]]; then + cp "$(fn-get-phase-file-path "$OLD_APP" "$phase")" "$(fn-get-phase-file-path "$NEW_APP" "$phase")" + fi + done +} + +trigger-docker-options-post-app-rename-setup "$@"