diff --git a/README.md b/README.md index 78583413..75ee935d 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,16 @@ postgres:backup-unset-encryption , Removes backup encryption for future ba postgres:clone Create container then copy data from into postgres:connect Connect via psql to a postgres service postgres:create Create a postgres service with environment variables +postgres:create-database Create a postgres database in the specified service postgres:destroy Delete the service, delete the data and stop its container if there are no links left +postgres:destroy-database Delete a postgres database in the specified service postgres:enter [command] Enter or run a command in a running postgres service container postgres:exists Check if the postgres service exists postgres:export > Export a dump of the postgres service database postgres:expose [port] Expose a postgres service on custom port if provided (random port otherwise) postgres:import < Import a dump into the postgres service database postgres:info Print the connection information -postgres:link Link the postgres service to the app +postgres:link [--database database] Link the postgres service to the app postgres:linked Check if the postgres service is linked to an app postgres:list List all postgres services postgres:logs [-t] Print the most recent log(s) for this service @@ -43,7 +45,7 @@ postgres:restart Graceful shutdown and restart of the postgres postgres:start Start a previously stopped postgres service postgres:stop Stop a running postgres service postgres:unexpose Unexpose a previously exposed postgres service -postgres:unlink Unlink the postgres service from the app +postgres:unlink [--database database] Unlink the postgres service from the app ``` ## usage diff --git a/common-functions b/common-functions index 74503397..2cc489c0 100755 --- a/common-functions +++ b/common-functions @@ -24,6 +24,17 @@ get_database_name() { echo "$DATABASE" | tr .- _ } +get_database_user_name() { + declare SERVICE="$1" + declare DATABASE="$2" + + if [ "$DATABASE" = "$SERVICE" ]; then + echo "postgres" + else + echo "$DATABASE" + fi +} + get_random_ports() { declare desc="Retrieves N random ports" declare iterations="${1:-1}" @@ -250,11 +261,34 @@ service_exposed_ports() { done } +service_databases() { + declare desc="Lists databases for a service" + declare SERVICE="$1" + local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + local DATABASE_DIR="$SERVICE_ROOT/databases" + [[ ! -d $DATABASE_DIR ]] && echo '-' && return 0 + for DATABASE in $DATABASE_DIR/*; do + echo -n "$(basename "$DATABASE") " + done +} + +service_users() { + declare desc="Lists users for a service" + declare SERVICE="$1" + local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + local USER_DIR="$SERVICE_ROOT/auth" + [[ ! -d $USER_DIR ]] && echo '-' && return 0 + for USER in $USER_DIR/*; do + echo -n "$(basename "$USER") " + done +} + service_info() { declare desc="Retrieves information about a given service" declare SERVICE="$1" INFO_FLAG="$2" local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" - local SERVICE_URL=$(service_url "$SERVICE") + local PASSWORD=$(cat "$SERVICE_ROOT/auth/postgres") + local SERVICE_URL=$(service_url "$SERVICE" postgres "$PASSWORD" "$SERVICE") local PORT_FILE="$SERVICE_ROOT/PORT" local SERVICE_CONTAINER_ID="$(cat "$SERVICE_ROOT/ID")" local flag key valid_flags @@ -307,9 +341,12 @@ service_link() { declare desc="Links a service to an application" declare SERVICE="$1" APP="$2" update_plugin_scheme_for_app "$APP" - local SERVICE_URL=$(service_url "$SERVICE") - local SERVICE_NAME="$(get_service_name "$SERVICE")" local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + local DATABASE=${3:-$(get_database_name "$SERVICE")} + local USER=$(get_database_user_name "$SERVICE" "$DATABASE") + local PASSWORD=$(cat "$SERVICE_ROOT/auth/$USER") + local SERVICE_URL=$(service_url "$SERVICE" "$USER" "$PASSWORD" "$DATABASE") + local SERVICE_NAME="$(get_service_name "$SERVICE")" local EXISTING_CONFIG=$(config_all "$APP") local LINK=$(echo "$EXISTING_CONFIG" | grep "$SERVICE_URL" | cut -d: -f1) || true local DEFAULT_ALIAS=$(echo "$EXISTING_CONFIG" | grep "${PLUGIN_DEFAULT_ALIAS}_URL") || true @@ -355,9 +392,9 @@ service_list() { if [[ -z $SERVICES ]]; then dokku_log_warn "There are no $PLUGIN_SERVICE services" else - LIST="NAME,VERSION,STATUS,EXPOSED PORTS,LINKS\n" + LIST="NAME,VERSION,STATUS,EXPOSED PORTS,DATABASES,USERS,LINKS\n" for SERVICE in $SERVICES; do - LIST+="$SERVICE,$(service_version "$SERVICE"),$(service_status "$SERVICE"),$(service_exposed_ports "$SERVICE"),$(service_linked_apps "$SERVICE")\n" + LIST+="$SERVICE,$(service_version "$SERVICE"),$(service_status "$SERVICE"),$(service_exposed_ports "$SERVICE"),$(service_databases "$SERVICE"),$(service_users "$SERVICE"),$(service_linked_apps "$SERVICE")\n" done printf "%b" "$LIST" | column -t -s, fi @@ -515,26 +552,19 @@ service_promote() { local PLUGIN_DEFAULT_CONFIG_VAR="${PLUGIN_DEFAULT_ALIAS}_URL" local EXISTING_CONFIG=$(config_all "$APP") update_plugin_scheme_for_app "$APP" - local SERVICE_URL=$(service_url "$SERVICE") - local CONFIG_VARS=($(echo "$EXISTING_CONFIG" | grep "$SERVICE_URL" | cut -d: -f1)) || true + local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" local PREVIOUS_DEFAULT_URL=$(get_url_from_config "$EXISTING_CONFIG" "$PLUGIN_DEFAULT_CONFIG_VAR") + local USER="postgres" + local DATABASE="$SERVICE" + local PASSWORD=$(cat "$SERVICE_ROOT/auth/$USER") + local SERVICE_URL=$(service_url "$SERVICE" "$USER" "$PASSWORD" "$DATABASE") + local CONFIG_VAR=$(echo "$EXISTING_CONFIG" | grep "$SERVICE_URL" | cut -d: -f1) || true - [[ -z ${CONFIG_VARS[*]} ]] && dokku_log_fail "Not linked to app $APP" - [[ ${CONFIG_VARS[*]} =~ $PLUGIN_DEFAULT_CONFIG_VAR ]] && dokku_log_fail "Service $1 already promoted as $PLUGIN_DEFAULT_CONFIG_VAR" + [[ -z $CONFIG_VAR ]] && dokku_log_fail "Not linked to app $APP" + [[ $CONFIG_VAR =~ $PLUGIN_DEFAULT_CONFIG_VAR ]] && dokku_log_fail "Service $1 already promoted as $PLUGIN_DEFAULT_CONFIG_VAR" - local NEW_CONFIG_VARS="" - if [[ -n $PREVIOUS_DEFAULT_URL ]]; then - local PREVIOUS_ALIAS=$(echo "$EXISTING_CONFIG" | grep "$PREVIOUS_DEFAULT_URL" | grep -v "$PLUGIN_DEFAULT_CONFIG_VAR") || true - if [[ -z $PREVIOUS_ALIAS ]]; then - local ALIAS=$(service_alternative_alias "$EXISTING_CONFIG") - NEW_CONFIG_VARS+="${ALIAS}_URL=$PREVIOUS_DEFAULT_URL " - fi - fi - local PROMOTE_URL=$(get_url_from_config "$EXISTING_CONFIG" "${CONFIG_VARS[0]}") - NEW_CONFIG_VARS+="$PLUGIN_DEFAULT_CONFIG_VAR=$PROMOTE_URL" - - # shellcheck disable=SC2086 - config_set "$APP" $NEW_CONFIG_VARS + config_set --no-restart "$APP" "${PLUGIN_DEFAULT_CONFIG_VAR}=$SERVICE_URL" + config_set "$APP" "${CONFIG_VAR}=$PREVIOUS_DEFAULT_URL" } service_set_alias() { @@ -583,8 +613,12 @@ service_stop() { service_unlink() { declare desc="Unlinks an application from a service" declare SERVICE="$1" APP="$2" + local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + local DATABASE=${3:-$(get_database_name "$SERVICE")} + local USER=$(get_database_user_name "$SERVICE" "$DATABASE") + local PASSWORD=$(cat "$SERVICE_ROOT/auth/$USER") update_plugin_scheme_for_app "$APP" - local SERVICE_URL=$(service_url "$SERVICE") + local SERVICE_URL=$(service_url "$SERVICE" "$USER" "$PASSWORD" "$DATABASE") local SERVICE_NAME="$(get_service_name "$SERVICE")" local EXISTING_CONFIG=$(config_all "$APP") local SERVICE_ALIAS=$(service_alias "$SERVICE") @@ -611,6 +645,59 @@ service_version() { docker inspect -f '{{.Config.Image}}' "$SERVICE_NAME" } + +service_create_database() { + local SERVICE="$1" + local DATABASE="$2" + local USER="$2" + [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a name for the service" + [[ -z "$DATABASE" ]] && dokku_log_fail "Please specify a name for the database" + + verify_service_name "$SERVICE" + + local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + local SERVICE_NAME="$(get_service_name "$SERVICE")" + + dokku_log_verbose_quiet "Creating user" + password=$(openssl rand -hex 16) + if docker exec "$SERVICE_NAME" su - postgres -c "psql -c \"CREATE USER \\\"$USER\\\" WITH PASSWORD '$password';\"" > /dev/null 2>&1; then + echo "$password" > "$SERVICE_ROOT/auth/$USER" + chmod 640 "$SERVICE_ROOT/auth/$USER" + else + dokku_log_verbose_quiet "Already exists" + fi + + dokku_log_verbose_quiet "Creating database" + if docker exec "$SERVICE_NAME" su - postgres -c "createdb -E utf8 $DATABASE" 2> /dev/null; then + touch "$SERVICE_ROOT/databases/$DATABASE" + else + dokku_log_verbose_quiet "Already exists" + fi + docker exec "$SERVICE_NAME" su - postgres -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE \\\"$DATABASE\\\" TO \\\"$USER\\\";\"" > /dev/null + + dokku_log_info2 "$PLUGIN_SERVICE database created: $DATABASE" +} + +service_destroy_database() { + local SERVICE="$1" + local DATABASE="$2" + + verify_service_name "$SERVICE" + verify_database_name "$SERVICE" "$DATABASE" + SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + SERVICE_NAME="$(get_service_name "$SERVICE")" + + dokku_log_info1 "Deleting $DATABASE from $SERVICE" + if docker exec "$SERVICE_NAME" su - postgres -c "psql -c \"DROP DATABASE $DATABASE;\"" 2> /dev/null && docker exec "$SERVICE_NAME" su - postgres -c "psql -c \"DROP USER $DATABASE;\"" 2> /dev/null; then + rm -f "$SERVICE_ROOT/databases/$DATABASE" + rm -f "$SERVICE_ROOT/auth/$DATABASE" + dokku_log_info2 "$PLUGIN_SERVICE $SERVICE database deleted: $DATABASE" + else + dokku_log_fail "Could not delete the database" + fi +} + + update_plugin_scheme_for_app() { declare desc="Retrieves the updated plugin scheme" declare APP="$1" @@ -627,3 +714,37 @@ verify_service_name() { [[ ! -d "$PLUGIN_DATA_ROOT/$SERVICE" ]] && dokku_log_fail "$PLUGIN_SERVICE service $SERVICE does not exist" return 0 } + +verify_user_name() { + declare desc="Verifies that a user exists" + declare SERVICE="$1" USER="$2" + [[ ! -n "$SERVICE" ]] && dokku_log_fail "(verify_user_name) SERVICE must not be null" + [[ ! -n "$USER" ]] && dokku_log_fail "(verify_user_name) SERVICE must not be null" + [[ ! -f "$PLUGIN_DATA_ROOT/$SERVICE/auth/$USER" ]] && dokku_log_fail "$PLUGIN_SERVICE user $USER for service $SERVICE does not exist" + return 0 +} + +verify_database_name() { + declare desc="Verifies that a database exists" + declare SERVICE="$1" + declare DATABASE="$2" + [[ ! -n "$SERVICE" ]] && dokku_log_fail "(verify_service_name) SERVICE must not be null" + [[ ! -n "$DATABASE" ]] && dokku_log_fail "(verify_service_name) DATABASE must not be null" + [[ ! -f "$PLUGIN_DATA_ROOT/$SERVICE/databases/$DATABASE" ]] && dokku_log_fail "$PLUGIN_SERVICE database $DATABASE for service $SERVICE does not exist" + return 0 +} + +check_auth_migration() { + declare desc="Check whether root credentials need to be migrated into multi-user format and do so if needed" + declare SERVICE="$1" + [[ ! -n "$SERVICE" ]] && dokku_log_fail "(verify_service_name) SERVICE must not be null" + local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" + if [ -f "$SERVICE_ROOT/PASSWORD" ]; then + dokku_log_verbose_quiet "Migrating root user to multi-user format for $SERVICE" + local AUTH_DIR="$SERVICE_ROOT/auth" + mkdir -p "$AUTH_DIR" + mv "$SERVICE_ROOT/PASSWORD" "$AUTH_DIR/postgres" + mkdir -p "$SERVICE_ROOT/databases/" + touch "$SERVICE_ROOT/databases/postgres" + fi +} diff --git a/functions b/functions index 154eef08..7714e789 100755 --- a/functions +++ b/functions @@ -25,7 +25,7 @@ service_create() { local SERVICE="$1" [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a name for the service" [[ ! -d "$PLUGIN_DATA_ROOT/$SERVICE" ]] || dokku_log_fail "$PLUGIN_SERVICE service $SERVICE already exists" - SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; LINKS_FILE="$SERVICE_ROOT/LINKS" + SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"; LINKS_FILE="$SERVICE_ROOT/LINKS"; AUTH_DIR="$SERVICE_ROOT/auth"; DB_DIR="$SERVICE_ROOT/databases" service_parse_args "${@:2}" @@ -35,14 +35,16 @@ service_create() { mkdir -p "$SERVICE_ROOT" || dokku_log_fail "Unable to create service directory" mkdir -p "$SERVICE_ROOT/data" || dokku_log_fail "Unable to create service data directory" + mkdir -p "$AUTH_DIR" || dokku_log_fail "Unable to create service auth directory" + mkdir -p "$DB_DIR" || dokku_log_fail "Unable to create service databases directory" touch "$LINKS_FILE" PASSWORD=$(openssl rand -hex 16) if [[ -n "$SERVICE_PASSWORD" ]]; then PASSWORD="$SERVICE_PASSWORD" dokku_log_warn "Specified password may not be as secure as the auto-generated password" fi - echo "$PASSWORD" > "$SERVICE_ROOT/PASSWORD" - chmod 640 "$SERVICE_ROOT/PASSWORD" + echo "$PASSWORD" > "$AUTH_DIR/postgres" + chmod 640 "$AUTH_DIR/postgres" [[ -n "$SERVICE_CUSTOM_ENV" ]] && POSTGRES_CUSTOM_ENV="$SERVICE_CUSTOM_ENV" if [[ -n $POSTGRES_CUSTOM_ENV ]]; then @@ -57,8 +59,9 @@ service_create_container() { local SERVICE="$1" local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" local SERVICE_NAME="$(get_service_name "$SERVICE")" - local PASSWORD="$(cat "$SERVICE_ROOT/PASSWORD")" + local PASSWORD="$(cat "$SERVICE_ROOT/auth/postgres")" local PREVIOUS_ID + local DB_DIR="$SERVICE_ROOT/databases" ID=$(docker run --name "$SERVICE_NAME" -v "$SERVICE_ROOT/data:/var/lib/postgresql/data" -e "POSTGRES_PASSWORD=$PASSWORD" --env-file="$SERVICE_ROOT/ENV" -d --restart always --label dokku=service --label dokku.service=postgres "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION") echo "$ID" > "$SERVICE_ROOT/ID" @@ -68,6 +71,7 @@ service_create_container() { dokku_log_verbose_quiet "Creating container database" DATABASE_NAME="$(get_database_name "$SERVICE")" + touch "$DB_DIR/$DATABASE_NAME" docker exec "$SERVICE_NAME" su - postgres -c "createdb -E utf8 $DATABASE_NAME" 2> /dev/null || echo 'Already exists' dokku_log_verbose_quiet "Securing connection to database" @@ -87,7 +91,7 @@ service_export() { local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" local SERVICE_NAME="$(get_service_name "$SERVICE")" local DATABASE_NAME="$(get_database_name "$SERVICE")" - local PASSWORD="$(cat "$SERVICE_ROOT/PASSWORD")" + local PASSWORD="$(cat "$SERVICE_ROOT/auth/postgres")" [[ -n $SSH_TTY ]] && stty -opost docker exec "$SERVICE_NAME" env PGPASSWORD="$PASSWORD" pg_dump -Fc --no-acl --no-owner -h localhost -U postgres -w "$DATABASE_NAME" @@ -101,7 +105,7 @@ service_import() { SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" SERVICE_NAME="$(get_service_name "$SERVICE")" DATABASE_NAME="$(get_database_name "$SERVICE")" - PASSWORD="$(cat "$SERVICE_ROOT/PASSWORD")" + PASSWORD="$(cat "$SERVICE_ROOT/auth/postgres")" if [[ -t 0 ]]; then dokku_log_fail "No data provided on stdin." @@ -123,7 +127,7 @@ service_start() { dokku_log_info1_quiet "Starting container" local PREVIOUS_ID=$(docker ps -f status=exited | grep -e "$SERVICE_NAME$" | awk '{print $1}') || true local IMAGE_EXISTS=$(docker images | grep -e "^$PLUGIN_IMAGE " | grep -q " $PLUGIN_IMAGE_VERSION " && true) - local PASSWORD="$(cat "$SERVICE_ROOT/PASSWORD")" + local PASSWORD="$(cat "$SERVICE_ROOT/auth/postgres")" if [[ -n $PREVIOUS_ID ]]; then docker start "$PREVIOUS_ID" > /dev/null @@ -140,8 +144,9 @@ service_url() { local SERVICE="$1" local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" - local PASSWORD="$(cat "$SERVICE_ROOT/PASSWORD")" - local DATABASE_NAME="$(get_database_name "$SERVICE")" + local USER="$2" # postgres + local PASSWORD="$3" + local DATABASE_NAME="$4" local SERVICE_ALIAS="$(service_alias "$SERVICE")" - echo "$PLUGIN_SCHEME://postgres:$PASSWORD@$SERVICE_ALIAS:${PLUGIN_DATASTORE_PORTS[0]}/$DATABASE_NAME" + echo "$PLUGIN_SCHEME://$USER:$PASSWORD@$SERVICE_ALIAS:${PLUGIN_DATASTORE_PORTS[0]}/$DATABASE_NAME" } diff --git a/install b/install index 57f88332..39fcc02c 100755 --- a/install +++ b/install @@ -1,6 +1,7 @@ #!/usr/bin/env bash source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config" set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions" plugin-install() { pull-docker-image() { @@ -36,6 +37,10 @@ plugin-install() { EOL chmod 0440 "$_SUDOERS_FILE" + + for d in "$PLUGIN_DATA_ROOT"/* ; do + check_auth_migration "$d" + done } plugin-install "$@" diff --git a/subcommands/create-database b/subcommands/create-database new file mode 100755 index 00000000..9bbe4d15 --- /dev/null +++ b/subcommands/create-database @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config" +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_BASE_PATH/common/functions" +source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions" + +service-create-database-cmd() { + declare desc="create a $PLUGIN_SERVICE database" + local cmd="$PLUGIN_COMMAND_PREFIX:create-database" argv=("$@"); [[ ${argv[0]} == "$cmd" ]] && shift 1 + declare SERVICE="$1" DATABASE="$2" + + [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a name for the service" + [[ -z "$DATABASE" ]] && dokku_log_fail "Please specify a name for the database" + + service_create_database "$SERVICE" "$DATABASE" +} + +service-create-database-cmd "$@" diff --git a/subcommands/destroy-database b/subcommands/destroy-database new file mode 100755 index 00000000..2285268b --- /dev/null +++ b/subcommands/destroy-database @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config" +set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_BASE_PATH/common/functions" +source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions" + +service-destroy-database-cmd() { + declare desc="delete a $PLUGIN_SERVICE database from the specified service" + local cmd="$PLUGIN_COMMAND_PREFIX:destroy-database" argv=("$@"); [[ ${argv[0]} == "$cmd" ]] && shift 1 + declare SERVICE="$1" DATABASE="$2" + + [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a name for the service" + [[ -z "$DATABASE" ]] && dokku_log_fail "Please specify a name for the database" + + service_destroy_database "$SERVICE" "$DATABASE" +} + +service-destroy-database-cmd "$@" diff --git a/subcommands/link b/subcommands/link index 7dc893f4..532383f2 100755 --- a/subcommands/link +++ b/subcommands/link @@ -41,14 +41,28 @@ service-link-cmd() { #A app, app to run command against declare desc="link the $PLUGIN_SERVICE service to the app" local cmd="$PLUGIN_COMMAND_PREFIX:link" argv=("$@"); [[ ${argv[0]} == "$cmd" ]] && shift 1 - declare SERVICE="$1" APP="$2" - APP=${APP:="$DOKKU_APP_NAME"} + declare SERVICE="$1" APP="$2" DATABASE_FLAG="" + + local next_index=1; local skip=false; local args=("$@"); local positional=() + for arg in "$@"; do + $skip && skip=false && local next_index=$(( next_index + 1 )) && continue + case "$arg" in + --database) + DATABASE=${args[$next_index]}; skip=true + ;; + *) + positional+=("$arg") + esac + local next_index=$(( next_index + 1 )) + done + APP=${APP:="$DOKKU_APP_NAME"} [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a name for the service" + verify_service_name "$SERVICE" [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$APP" - verify_service_name "$SERVICE" - service_link "$SERVICE" "$APP" + [[ -z "$DATABASE" ]] || verify_database_name "$SERVICE" "$DATABASE" + service_link "$SERVICE" "$APP" "$DATABASE" } service-link-cmd "$@" diff --git a/subcommands/unlink b/subcommands/unlink index a58e9c7b..83c75e38 100755 --- a/subcommands/unlink +++ b/subcommands/unlink @@ -12,14 +12,29 @@ service-unlink-cmd() { #A app, app to run command against declare desc="unlink the $PLUGIN_SERVICE service from the app" local cmd="$PLUGIN_COMMAND_PREFIX:unlink" argv=("$@"); [[ ${argv[0]} == "$cmd" ]] && shift 1 - declare SERVICE="$1" APP="$2" + declare SERVICE="$1" APP="$2" DATABASE_FLAG="" + + local next_index=1; local skip=false; local args=("$@"); local positional=() + for arg in "$@"; do + $skip && skip=false && local next_index=$(( next_index + 1 )) && continue + case "$arg" in + --database) + DATABASE=${args[$next_index]}; skip=true + ;; + *) + positional+=("$arg") + esac + local next_index=$(( next_index + 1 )) + done + APP=${APP:="$DOKKU_APP_NAME"} [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a name for the service" - [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on" verify_service_name "$SERVICE" + [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on" verify_app_name "$APP" - service_unlink "$SERVICE" "$APP" + [[ -z "$DATABASE_FLAG" ]] || verify_database_name "$SERVICE" "$DATABASE_FLAG" + service_unlink "$SERVICE" "$APP" "$DATABASE" } service-unlink-cmd "$@" diff --git a/tests/service_create_database.bats b/tests/service_create_database.bats new file mode 100644 index 00000000..c4592b94 --- /dev/null +++ b/tests/service_create_database.bats @@ -0,0 +1,29 @@ +#!/usr/bin/env bats +load test_helper + +setup() { + export ECHO_DOCKER_COMMAND="false" + dokku "$PLUGIN_COMMAND_PREFIX:create" l >&2 + dokku apps:create my_app >&2 +} + +teardown() { + export ECHO_DOCKER_COMMAND="false" + dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l >&2 + rm -rf "$DOKKU_ROOT/my_app" +} + +@test "($PLUGIN_COMMAND_PREFIX:create-database) success" { + run dokku "$PLUGIN_COMMAND_PREFIX:create-database" l d + assert_contains "${lines[*]}" "database created: d" +} + +@test "($PLUGIN_COMMAND_PREFIX:create-database) error when there is only one argument" { + run dokku "$PLUGIN_COMMAND_PREFIX:create-database" l + assert_contains "${lines[*]}" "Please specify a name for the database" +} + +@test "($PLUGIN_COMMAND_PREFIX:create-database) error when there are no arguments" { + run dokku "$PLUGIN_COMMAND_PREFIX:create-database" + assert_contains "${lines[*]}" "Please specify a name for the service" +} \ No newline at end of file diff --git a/tests/service_destroy_database.bats b/tests/service_destroy_database.bats new file mode 100644 index 00000000..1d663427 --- /dev/null +++ b/tests/service_destroy_database.bats @@ -0,0 +1,28 @@ +#!/usr/bin/env bats +load test_helper + +setup() { + dokku "$PLUGIN_COMMAND_PREFIX:create" l >&2 + dokku "$PLUGIN_COMMAND_PREFIX:create-database" l d >&2 + dokku apps:create my_app >&2 +} + +teardown() { + dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l >&2 + rm -rf "$DOKKU_ROOT/my_app" +} + +@test "($PLUGIN_COMMAND_PREFIX:destroy-database) success" { + run dokku "$PLUGIN_COMMAND_PREFIX:destroy-database" l d + assert_contains "${lines[*]}" "database deleted: d" +} + +@test "($PLUGIN_COMMAND_PREFIX:destroy-database) error when there are no arguments" { + run dokku "$PLUGIN_COMMAND_PREFIX:destroy-database" + assert_contains "${lines[*]}" "Please specify a name for the service" +} + +@test "($PLUGIN_COMMAND_PREFIX:destroy-database) error when there is only one argument" { + run dokku "$PLUGIN_COMMAND_PREFIX:destroy-database" l + assert_contains "${lines[*]}" "Please specify a name for the database" +} diff --git a/tests/service_export.bats b/tests/service_export.bats index 8d0c4e06..9dc4419c 100755 --- a/tests/service_export.bats +++ b/tests/service_export.bats @@ -25,7 +25,7 @@ teardown() { export ECHO_DOCKER_COMMAND="true" export SSH_TTY=`tty` run dokku "$PLUGIN_COMMAND_PREFIX:export" l - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_exit_status 0 assert_output "docker exec dokku.postgres.l env PGPASSWORD=$password pg_dump -Fc --no-acl --no-owner -h localhost -U postgres -w l" } @@ -34,7 +34,7 @@ teardown() { export ECHO_DOCKER_COMMAND="true" unset SSH_TTY run dokku "$PLUGIN_COMMAND_PREFIX:export" l - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_exit_status 0 assert_output "docker exec dokku.postgres.l env PGPASSWORD=$password pg_dump -Fc --no-acl --no-owner -h localhost -U postgres -w l" } diff --git a/tests/service_import.bats b/tests/service_import.bats index a9dfb1c4..76f24c05 100755 --- a/tests/service_import.bats +++ b/tests/service_import.bats @@ -31,7 +31,7 @@ teardown() { @test "($PLUGIN_COMMAND_PREFIX:import) success" { export ECHO_DOCKER_COMMAND="true" run dokku "$PLUGIN_COMMAND_PREFIX:import" l < "$PLUGIN_DATA_ROOT/fake.dump" - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_output "docker exec -i dokku.postgres.l env PGPASSWORD=$password pg_restore -h localhost -cO -d l -U postgres -w" } diff --git a/tests/service_info.bats b/tests/service_info.bats index 980d6a88..84d1e77f 100755 --- a/tests/service_info.bats +++ b/tests/service_info.bats @@ -21,21 +21,21 @@ teardown() { @test "($PLUGIN_COMMAND_PREFIX:info) success" { run dokku "$PLUGIN_COMMAND_PREFIX:info" l - local password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + local password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_contains "${lines[*]}" "postgres://postgres:$password@dokku-postgres-l:5432/l" } @test "($PLUGIN_COMMAND_PREFIX:info) replaces underscores by dash in hostname" { dokku "$PLUGIN_COMMAND_PREFIX:create" test_with_underscores run dokku "$PLUGIN_COMMAND_PREFIX:info" test_with_underscores - local password="$(cat "$PLUGIN_DATA_ROOT/test_with_underscores/PASSWORD")" + local password="$(cat "$PLUGIN_DATA_ROOT/test_with_underscores/auth/postgres")" assert_contains "${lines[*]}" "postgres://postgres:$password@dokku-postgres-test-with-underscores:5432/test_with_underscores" dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" test_with_underscores } @test "($PLUGIN_COMMAND_PREFIX:info) success with flag" { run dokku "$PLUGIN_COMMAND_PREFIX:info" l --dsn - local password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + local password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_output "postgres://postgres:$password@dokku-postgres-l:5432/l" run dokku "$PLUGIN_COMMAND_PREFIX:info" l --config-dir diff --git a/tests/service_link.bats b/tests/service_link.bats index 131e6c48..5986f910 100755 --- a/tests/service_link.bats +++ b/tests/service_link.bats @@ -40,7 +40,7 @@ teardown() { @test "($PLUGIN_COMMAND_PREFIX:link) exports DATABASE_URL to app" { dokku "$PLUGIN_COMMAND_PREFIX:link" l my_app url=$(dokku config:get my_app DATABASE_URL) - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_contains "$url" "postgres://postgres:$password@dokku-postgres-l:5432/l" dokku "$PLUGIN_COMMAND_PREFIX:unlink" l my_app } @@ -64,7 +64,7 @@ teardown() { dokku config:set my_app POSTGRES_DATABASE_SCHEME=postgres2 dokku "$PLUGIN_COMMAND_PREFIX:link" l my_app url=$(dokku config:get my_app DATABASE_URL) - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" assert_contains "$url" "postgres2://postgres:$password@dokku-postgres-l:5432/l" dokku "$PLUGIN_COMMAND_PREFIX:unlink" l my_app } diff --git a/tests/service_list.bats b/tests/service_list.bats index de5a859b..cb92576e 100755 --- a/tests/service_list.bats +++ b/tests/service_list.bats @@ -11,20 +11,20 @@ teardown() { @test "($PLUGIN_COMMAND_PREFIX:list) with no exposed ports, no linked apps" { run dokku "$PLUGIN_COMMAND_PREFIX:list" - assert_contains "${lines[*]}" "l postgres:10.2 running - -" + assert_contains "${lines[*]}" "l postgres:10.2 running - l postgres -" } @test "($PLUGIN_COMMAND_PREFIX:list) with exposed ports" { dokku "$PLUGIN_COMMAND_PREFIX:expose" l 4242 run dokku "$PLUGIN_COMMAND_PREFIX:list" - assert_contains "${lines[*]}" "l postgres:10.2 running 5432->4242 -" + assert_contains "${lines[*]}" "l postgres:10.2 running 5432->4242 l postgres -" } @test "($PLUGIN_COMMAND_PREFIX:list) with linked app" { dokku apps:create my_app dokku "$PLUGIN_COMMAND_PREFIX:link" l my_app run dokku "$PLUGIN_COMMAND_PREFIX:list" - assert_contains "${lines[*]}" "l postgres:10.2 running - my_app" + assert_contains "${lines[*]}" "l postgres:10.2 running - l postgres my_app" dokku --force apps:destroy my_app } diff --git a/tests/service_promote.bats b/tests/service_promote.bats index a5ba44ae..9170e28c 100755 --- a/tests/service_promote.bats +++ b/tests/service_promote.bats @@ -39,7 +39,7 @@ teardown() { } @test "($PLUGIN_COMMAND_PREFIX:promote) changes DATABASE_URL" { - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" dokku config:set my_app "DATABASE_URL=postgres://u:p@host:5432/db" "DOKKU_POSTGRES_BLUE_URL=postgres://postgres:$password@dokku-postgres-l:5432/l" dokku "$PLUGIN_COMMAND_PREFIX:promote" l my_app url=$(dokku config:get my_app DATABASE_URL) @@ -47,14 +47,15 @@ teardown() { } @test "($PLUGIN_COMMAND_PREFIX:promote) creates new config url when needed" { - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" dokku config:set my_app "DATABASE_URL=postgres://u:p@host:5432/db" "DOKKU_POSTGRES_BLUE_URL=postgres://postgres:$password@dokku-postgres-l:5432/l" dokku "$PLUGIN_COMMAND_PREFIX:promote" l my_app run dokku config my_app assert_contains "${lines[*]}" "DOKKU_POSTGRES_" } + @test "($PLUGIN_COMMAND_PREFIX:promote) uses POSTGRES_DATABASE_SCHEME variable" { - password="$(cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" + password="$(cat "$PLUGIN_DATA_ROOT/l/auth/postgres")" dokku config:set my_app "POSTGRES_DATABASE_SCHEME=postgres2" "DATABASE_URL=postgres://u:p@host:5432/db" "DOKKU_POSTGRES_BLUE_URL=postgres2://postgres:$password@dokku-postgres-l:5432/l" dokku "$PLUGIN_COMMAND_PREFIX:promote" l my_app url=$(dokku config:get my_app DATABASE_URL) diff --git a/tests/service_unlink.bats b/tests/service_unlink.bats index 704c6e25..302ab73c 100755 --- a/tests/service_unlink.bats +++ b/tests/service_unlink.bats @@ -39,11 +39,12 @@ teardown() { @test "($PLUGIN_COMMAND_PREFIX:unlink) removes link from docker-options" { dokku "$PLUGIN_COMMAND_PREFIX:link" l my_app >&2 dokku "$PLUGIN_COMMAND_PREFIX:unlink" l my_app - options=$(dokku docker-options my_app | xargs) + options=$(dokku docker-options:report my_app | xargs) + echo "$options" check_value="" - [[ "$(dokku version)" == "master" ]] && check_value="Deploy options: --restart=on-failure:10" + [[ "$(dokku version)" == "master" ]] && check_value="Docker options deploy: --restart=on-failure:10" [[ "$(at-least-version 0.7.0 "$(dokku version)")" == "true" ]] && check_value="Deploy options: --restart=on-failure:10" - assert_equal "$options" "$check_value" + assert_contains "$options" "$check_value" } @test "($PLUGIN_COMMAND_PREFIX:unlink) unsets config url from app" {