├── update
├── .gitignore
├── Dockerfile
├── plugin.toml
├── docs
└── README.md
├── .devcontainer
├── bin
│ └── copy-file
├── devcontainer.json
├── 20_init_plugin
└── Dockerfile
├── logger_log_to_console.xml
├── .editorconfig
├── .github
├── dependabot.yml
├── workflows
│ ├── tagged-release.yml
│ └── ci.yml
└── labels.yml
├── commands
├── pre-delete
├── subcommands
├── list
├── start
├── pause
├── stop
├── exists
├── unexpose
├── app-links
├── import
├── restart
├── backup-deauth
├── backup-schedule-cat
├── links
├── backup-unschedule
├── backup-unset-encryption
├── export
├── connect
├── backup-unset-public-key-encryption
├── linked
├── enter
├── unlink
├── expose
├── backup-set-encryption
├── logs
├── backup
├── backup-set-public-key-encryption
├── backup-schedule
├── set
├── promote
├── backup-auth
├── create
├── info
├── destroy
├── clone
├── upgrade
└── link
├── post-app-clone-setup
├── post-app-rename-setup
├── service-list
├── tests
├── hook_pre_delete.bats
├── service_list.bats
├── service_stop.bats
├── service_pause.bats
├── service_start.bats
├── service_restart.bats
├── service_connect.bats
├── service_unexpose.bats
├── shellcheck-exclude
├── service_create.bats
├── service_destroy.bats
├── service_logs.bats
├── setup.sh
├── test_helper.bash
├── service_expose.bats
├── service_info.bats
├── service_unlink.bats
├── service_promote.bats
├── service_link.bats
├── shellcheck-to-junit
└── link_networks.bats
├── system_log_ttl_config.xml
├── Vagrantfile
├── pre-start
├── LICENSE.txt
├── pre-restore
├── config
├── install
├── Makefile
├── help-functions
├── functions
├── README.md
└── bin
└── generate
/update:
--------------------------------------------------------------------------------
1 | install
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /tmp
2 | .vagrant
3 | bootstrap.sh
4 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM clickhouse/clickhouse-server:25.12.1.649
2 |
--------------------------------------------------------------------------------
/plugin.toml:
--------------------------------------------------------------------------------
1 | [plugin]
2 | description = "dokku clickhouse service plugin"
3 | version = "1.46.3"
4 | sponsors = ["coding-socks"]
5 | [plugin.config]
6 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Extra Documentation
2 |
3 | The documentation in this folder is supplemental to using this plugin. It is injected automatically into the plugin's readme during documentation generation.
4 |
5 |
--------------------------------------------------------------------------------
/.devcontainer/bin/copy-file:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | main() {
4 | PLUGIN_NAME="$(source /tmp/.env && echo "$PLUGIN_NAME")"
5 | cp "$1" "/var/lib/dokku/plugins/enabled/$PLUGIN_NAME/$1"
6 | }
7 |
8 | main "$@"
9 |
--------------------------------------------------------------------------------
/logger_log_to_console.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | information
4 | true
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | insert_final_newline = true
5 | indent_style = space
6 | indent_size = 2
7 |
8 | [Makefile]
9 | insert_final_newline = true
10 | indent_style = tab
11 | indent_size = 4
12 |
13 | [*.mk]
14 | insert_final_newline = true
15 | indent_style = tab
16 | indent_size = 4
17 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | updates:
4 | - package-ecosystem: "docker"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: daily
12 | open-pull-requests-limit: 10
13 |
--------------------------------------------------------------------------------
/.github/workflows/tagged-release.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: "tagged-release"
3 |
4 | # yamllint disable-line rule:truthy
5 | on:
6 | push:
7 | tags:
8 | - "*"
9 |
10 | jobs:
11 | tagged-release:
12 | name: tagged-release
13 | runs-on: ubuntu-24.04
14 |
15 | steps:
16 | - name: Release
17 | uses: softprops/action-gh-release@v2.5.0
18 | with:
19 | generate_release_notes: true
20 | make_latest: "true"
21 |
--------------------------------------------------------------------------------
/commands:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | [[ " help $PLUGIN_COMMAND_PREFIX:help $PLUGIN_COMMAND_PREFIX $PLUGIN_COMMAND_PREFIX:default " == *" $1 "* ]] || [[ "$1" == "$PLUGIN_COMMAND_PREFIX:"* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
4 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
5 |
6 | set -eo pipefail
7 | [[ $DOKKU_TRACE ]] && set -x
8 |
9 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/help-functions"
10 |
11 | fn-help "$@"
12 |
--------------------------------------------------------------------------------
/pre-delete:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
4 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/functions"
5 | set -eo pipefail
6 | [[ $DOKKU_TRACE ]] && set -x
7 |
8 | APP="$1"
9 | for SERVICE in $(fn-services-list false); do
10 | [[ -n "$SERVICE" ]] || continue
11 | dokku_log_verbose_quiet "Unlinking from $SERVICE"
12 | remove_from_links_file "$(basename "$SERVICE")" "$APP"
13 | done
14 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "build": {
3 | "dockerfile": "Dockerfile",
4 | "context": ".."
5 | },
6 | "containerEnv": {
7 | "SERVICE_HOST_ROOT": "${localWorkspaceFolder}/tmp/data"
8 | },
9 | "initializeCommand": ["mkdir", "-p", "tmp/data"],
10 | "mounts": [
11 | "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind",
12 | "source=${localWorkspaceFolder}/tmp/data/,target=/var/lib/dokku/services/,type=bind"
13 | ],
14 | "overrideCommand": false,
15 | "runArgs": ["--init"]
16 | }
17 |
--------------------------------------------------------------------------------
/.devcontainer/20_init_plugin:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -eo pipefail
3 |
4 | log-info() {
5 | declare desc="Log info formatter"
6 | echo " $*" 1>&2
7 | }
8 |
9 | log-fail() {
10 | declare desc="Log fail formatter"
11 | echo "! $*" 1>&2
12 | exit 1
13 | }
14 |
15 | main() {
16 | dokku plugin:install
17 |
18 | # built in the Dockerfile
19 | PLUGIN_NAME="$(source /tmp/.env && echo "$PLUGIN_NAME")"
20 | PLUGIN_VARIABLE="$(source /tmp/.env && echo "$PLUGIN_VARIABLE")"
21 | echo "export ${PLUGIN_VARIABLE}_HOST_ROOT=${SERVICE_HOST_ROOT}/$PLUGIN_NAME" >/etc/default/dokku
22 | }
23 |
24 | main "$@"
25 |
--------------------------------------------------------------------------------
/subcommands/list:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-list-cmd() {
9 | #E list all services
10 | #E dokku $PLUGIN_COMMAND_PREFIX:list
11 | declare desc="list all $PLUGIN_SERVICE services"
12 | local cmd="$PLUGIN_COMMAND_PREFIX:list" argv=("$@")
13 | [[ ${argv[0]} == "$cmd" ]] && shift 1
14 |
15 | service_list
16 | }
17 |
18 | service-list-cmd "$@"
19 |
--------------------------------------------------------------------------------
/post-app-clone-setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
4 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/functions"
5 | set -eo pipefail
6 | [[ $DOKKU_TRACE ]] && set -x
7 |
8 | plugin-post-app-clone-setup() {
9 | declare OLD_APP_NAME="$1" NEW_APP_NAME="$2"
10 |
11 | for SERVICE in $(fn-services-list false); do
12 | if in_links_file "$SERVICE" "$OLD_APP_NAME"; then
13 | add_to_links_file "$SERVICE" "$NEW_APP_NAME"
14 | fi
15 | done
16 | }
17 |
18 | plugin-post-app-clone-setup "$@"
19 |
--------------------------------------------------------------------------------
/post-app-rename-setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
4 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/functions"
5 | set -eo pipefail
6 | [[ $DOKKU_TRACE ]] && set -x
7 |
8 | plugin-post-app-rename-setup() {
9 | declare OLD_APP_NAME="$1" NEW_APP_NAME="$2"
10 |
11 | for SERVICE in $(fn-services-list false); do
12 | if in_links_file "$SERVICE" "$OLD_APP_NAME"; then
13 | add_to_links_file "$SERVICE" "$NEW_APP_NAME"
14 | fi
15 | done
16 | }
17 |
18 | plugin-post-app-rename-setup "$@"
19 |
--------------------------------------------------------------------------------
/service-list:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
4 | set -eo pipefail
5 | [[ $DOKKU_TRACE ]] && set -x
6 |
7 | plugin-service-list() {
8 | declare desc="allows listing all services for use by other dokku plugins"
9 | declare SERVICE_TYPE="$1"
10 |
11 | if [[ -n "$SERVICE_TYPE" ]] && [[ "$SERVICE_TYPE" != "$PLUGIN_COMMAND_PREFIX" ]]; then
12 | return
13 | fi
14 |
15 | for service in $(fn-services-list false); do
16 | echo "$PLUGIN_COMMAND_PREFIX:$service"
17 | done
18 | }
19 |
20 | plugin-service-list "$@"
21 |
--------------------------------------------------------------------------------
/tests/hook_pre_delete.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku apps:create my-app
6 | dokku "$PLUGIN_COMMAND_PREFIX:create" ls
7 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app >&2
8 | }
9 |
10 | teardown() {
11 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app >&2
12 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" ls
13 | dokku --force apps:destroy my-app || true
14 | }
15 |
16 | @test "($PLUGIN_COMMAND_PREFIX:hook:pre-delete) removes app from links file when destroying app" {
17 | [[ -n $(<"$PLUGIN_DATA_ROOT/ls/LINKS") ]]
18 | dokku --force apps:destroy my-app
19 | [[ -z $(<"$PLUGIN_DATA_ROOT/ls/LINKS") ]]
20 | }
21 |
--------------------------------------------------------------------------------
/tests/service_list.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:list) with no exposed ports, no linked apps" {
13 | run dokku --quiet "$PLUGIN_COMMAND_PREFIX:list"
14 | assert_output "l"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:list) when there are no services" {
18 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
19 | run dokku "$PLUGIN_COMMAND_PREFIX:list"
20 | assert_output "${lines[*]}" "There are no $PLUGIN_SERVICE services"
21 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
22 | }
23 |
--------------------------------------------------------------------------------
/tests/service_stop.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:stop) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:stop"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:stop) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:stop) success" {
23 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" l
24 | assert_success
25 | }
26 |
--------------------------------------------------------------------------------
/tests/service_pause.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:pause) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:pause"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:pause) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:pause" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:pause) success" {
23 | run dokku "$PLUGIN_COMMAND_PREFIX:pause" l
24 | assert_success
25 | }
26 |
--------------------------------------------------------------------------------
/tests/service_start.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:start) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:start"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:start) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:start" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:start) success" {
23 | run dokku "$PLUGIN_COMMAND_PREFIX:start" l
24 | assert_success
25 | }
26 |
--------------------------------------------------------------------------------
/tests/service_restart.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:restart) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:restart"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:restart) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:restart" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:restart) success" {
23 | run dokku "$PLUGIN_COMMAND_PREFIX:restart" l
24 | assert_success
25 | }
26 |
--------------------------------------------------------------------------------
/system_log_ttl_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | event_date + INTERVAL 30 DAY DELETE
4 |
5 |
6 | event_date + INTERVAL 30 DAY DELETE
7 |
8 |
9 | event_date + INTERVAL 30 DAY DELETE
10 |
11 |
12 | event_date + INTERVAL 30 DAY DELETE
13 |
14 |
15 | event_date + INTERVAL 30 DAY DELETE
16 |
17 |
18 | event_date + INTERVAL 30 DAY DELETE
19 |
20 |
21 | event_date + INTERVAL 30 DAY DELETE
22 |
23 |
24 | event_date + INTERVAL 30 DAY DELETE
25 |
26 |
--------------------------------------------------------------------------------
/subcommands/start:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-start-cmd() {
9 | #E start the service
10 | #E dokku $PLUGIN_COMMAND_PREFIX:start lollipop
11 | #A service, service to run command against
12 | declare desc="start a previously stopped $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:start" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | service_start "$SERVICE"
20 | }
21 |
22 | service-start-cmd "$@"
23 |
--------------------------------------------------------------------------------
/tests/service_connect.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:connect) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:connect"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:connect) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:connect" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:connect) success" {
23 | skip "Connect hangs indefinitely without input"
24 | run dokku "$PLUGIN_COMMAND_PREFIX:connect" l
25 | assert_success
26 | }
27 |
--------------------------------------------------------------------------------
/subcommands/pause:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-pause-cmd() {
9 | #E pause the running container for the service
10 | #E dokku $PLUGIN_COMMAND_PREFIX:pause lollipop
11 | #A service, service to run command against
12 | declare desc="pause a running $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:pause" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | service_pause "$SERVICE"
20 | }
21 |
22 | service-pause-cmd "$@"
23 |
--------------------------------------------------------------------------------
/subcommands/stop:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-stop-cmd() {
9 | #E stop the service and removes the running container
10 | #E dokku $PLUGIN_COMMAND_PREFIX:stop lollipop
11 | #A service, service to run command against
12 | declare desc="stop a running $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:stop" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | service_container_rm "$SERVICE"
20 | }
21 |
22 | service-stop-cmd "$@"
23 |
--------------------------------------------------------------------------------
/subcommands/exists:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-exists-cmd() {
9 | #E here we check if the lollipop $PLUGIN_COMMAND_PREFIX service exists.
10 | #E dokku $PLUGIN_COMMAND_PREFIX:exists lollipop
11 | #A service, service to run command against
12 | declare desc="check if the $PLUGIN_SERVICE service exists"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:exists" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | dokku_log_info1 "Service $SERVICE exists"
20 | }
21 |
22 | service-exists-cmd "$@"
23 |
--------------------------------------------------------------------------------
/subcommands/unexpose:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-unexpose-cmd() {
9 | #E unexpose the service, removing access to it from the public interface (0.0.0.0)
10 | #E dokku $PLUGIN_COMMAND_PREFIX:unexpose lollipop
11 | #A service, service to run command against
12 | declare desc="unexpose a previously exposed $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:unexpose" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | service_port_unexpose "$SERVICE"
20 | }
21 |
22 | service-unexpose-cmd "$@"
23 |
--------------------------------------------------------------------------------
/tests/service_unexpose.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:unexpose) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:unexpose"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:unexpose) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:unexpose" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:unexpose) success" {
23 | dokku "$PLUGIN_COMMAND_PREFIX:expose" l
24 | run dokku "$PLUGIN_COMMAND_PREFIX:unexpose" l
25 | [[ ! -f $PLUGIN_DATA_ROOT/PORT ]]
26 | assert_contains "${lines[*]}" "Service l unexposed"
27 | }
28 |
--------------------------------------------------------------------------------
/subcommands/app-links:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-app-links-cmd() {
9 | #E list all $PLUGIN_COMMAND_PREFIX services that are linked to the 'playground' app.
10 | #E dokku $PLUGIN_COMMAND_PREFIX:app-links playground
11 | #A app, app to run command against
12 | declare desc="list all $PLUGIN_SERVICE service links for a given app"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:app-links" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare APP="$1"
16 | APP=${APP:="$DOKKU_APP_NAME"}
17 |
18 | [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
19 | verify_app_name "$APP"
20 | service_app_links "$APP"
21 | }
22 |
23 | service-app-links-cmd "$@"
24 |
--------------------------------------------------------------------------------
/subcommands/import:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-import-cmd() {
9 | #E import a datastore dump
10 | #E dokku $PLUGIN_COMMAND_PREFIX:import lollipop < data.dump
11 | #A service, service to run command against
12 | declare desc="import a dump into the $PLUGIN_SERVICE service database"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:import" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
17 |
18 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
19 | verify_service_name "$SERVICE"
20 | service_import "$SERVICE"
21 | }
22 |
23 | service-import-cmd "$@"
24 |
--------------------------------------------------------------------------------
/tests/shellcheck-exclude:
--------------------------------------------------------------------------------
1 | # SC1090 - Can't follow non-constant source. Use a directive to specify location - https://github.com/koalaman/shellcheck/wiki/SC1090
2 | # SC1091 - Not following -
3 | # SC2034 - Variable appears unused. Verify it or export it - https://github.com/koalaman/shellcheck/wiki/SC2034
4 | # SC2155 - Declare and assign separately to avoid masking return values - https://github.com/koalaman/shellcheck/wiki/SC2155
5 | # SC2206 - Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a - https://github.com/koalaman/shellcheck/wiki/SC2206
6 | # SC2207 - Prefer mapfile or read -a to split command output (or quote to avoid splitting) - https://github.com/koalaman/shellcheck/wiki/SC2207
7 | # SC2220 - Invalid flags are not handled. Add a *) case - https://github.com/koalaman/shellcheck/wiki/SC2220
8 | # SC2230 - which is non-standard. Use builtin 'command -v' instead - https://github.com/koalaman/shellcheck/wiki/SC2230
9 |
--------------------------------------------------------------------------------
/subcommands/restart:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-restart-cmd() {
9 | #E restart the service
10 | #E dokku $PLUGIN_COMMAND_PREFIX:restart lollipop
11 | #A service, service to run command against
12 | declare desc="graceful shutdown and restart of the $PLUGIN_SERVICE service container"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:restart" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | service_pause "$SERVICE"
20 | service_start "$SERVICE"
21 | dokku_log_info1 "Please call dokku ps:restart on all linked apps"
22 | }
23 |
24 | service-restart-cmd "$@"
25 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | BOX_NAME = ENV["BOX_NAME"] || "bento/ubuntu-24.04"
5 | BOX_MEMORY = ENV["BOX_MEMORY"] || "2048"
6 | DOKKU_VERSION = "master"
7 |
8 | Vagrant.configure(2) do |config|
9 | config.vm.box = BOX_NAME
10 | config.ssh.forward_agent = true
11 |
12 | config.vm.provider :virtualbox do |vb|
13 | vb.customize ["modifyvm", :id, "--memory", BOX_MEMORY]
14 | end
15 |
16 | config.vm.provider :vmware_fusion do |v, override|
17 | v.vmx["memsize"] = BOX_MEMORY
18 | end
19 |
20 | config.vm.define "default", primary: true do |vm|
21 | vm.vm.synced_folder File.dirname(__FILE__), "/vagrant"
22 |
23 | vm.vm.provision :shell, :inline => "apt -q update && apt -y -qq install git software-properties-common"
24 | vm.vm.provision :shell, :inline => "cd /vagrant && DOKKU_VERSION=#{DOKKU_VERSION} make setup"
25 | vm.vm.provision :shell, :inline => "cd /vagrant && DOKKU_TRACE=1 DOKKU_VERSION=#{DOKKU_VERSION} make test"
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/subcommands/backup-deauth:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-deauth-cmd() {
9 | #E remove s3 authentication
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-deauth lollipop
11 | #A service, service to run command against
12 | declare desc="remove backup authentication for the $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-deauth" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
17 |
18 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
19 | verify_service_name "$SERVICE"
20 | service_backup_deauth "$SERVICE"
21 | }
22 |
23 | service-backup-deauth-cmd "$@"
24 |
--------------------------------------------------------------------------------
/pre-start:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
4 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/functions"
5 | set -eo pipefail
6 | [[ $DOKKU_TRACE ]] && set -x
7 |
8 | plugin-pre-start() {
9 | declare APP="$1"
10 | local status
11 |
12 | for SERVICE in $(fn-services-list false); do
13 | if ! in_links_file "$SERVICE" "$APP"; then
14 | continue
15 | fi
16 |
17 | status="$(service_status "$SERVICE")"
18 | if [[ "$status" == "running" ]]; then
19 | continue
20 | fi
21 |
22 | if [[ "$status" == "restarting" ]]; then
23 | dokku_log_warn "$PLUGIN_SERVICE service $SERVICE is restarting and may cause issues with linked app $APP"
24 | continue
25 | fi
26 |
27 | dokku_log_warn "$PLUGIN_SERVICE service $SERVICE is not running, issuing service start"
28 | service_start "$SERVICE"
29 | done
30 | }
31 |
32 | plugin-pre-start "$@"
33 |
--------------------------------------------------------------------------------
/subcommands/backup-schedule-cat:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-schedule-cat-cmd() {
9 | #E cat the contents of the configured backup cronfile for the service
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-schedule-cat lollipop
11 | #A service, service to run command against
12 | declare desc="cat the contents of the configured backup cronfile for the service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-schedule-cat" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 |
17 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
18 | verify_service_name "$SERVICE"
19 | service_backup_schedule_cat "$SERVICE"
20 | }
21 |
22 | service-backup-schedule-cat-cmd "$@"
23 |
--------------------------------------------------------------------------------
/subcommands/links:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-links-cmd() {
9 | #E list all apps linked to the 'lollipop' $PLUGIN_COMMAND_PREFIX service.
10 | #E dokku $PLUGIN_COMMAND_PREFIX:links lollipop
11 | #A service, service to run command against
12 | declare desc="list all apps linked to the $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:links" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
17 | local LINKS_FILE="$SERVICE_ROOT/LINKS"
18 |
19 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
20 | verify_service_name "$SERVICE"
21 | service_links "$SERVICE"
22 | }
23 |
24 | service-links-cmd "$@"
25 |
--------------------------------------------------------------------------------
/subcommands/backup-unschedule:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-unschedule-cmd() {
9 | #E remove the scheduled backup from cron
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-unschedule lollipop
11 | #A service, service to run command against
12 | declare desc="unschedule the backup of the $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-unschedule" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
17 |
18 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
19 | verify_service_name "$SERVICE"
20 | service_backup_unschedule "$SERVICE"
21 | }
22 |
23 | service-backup-unschedule-cmd "$@"
24 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2020 Jose Diaz-Gonzalez
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/subcommands/backup-unset-encryption:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-unset-encryption-cmd() {
9 | #E unset the GPG encryption passphrase for backups
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-unset-encryption lollipop
11 | #A service, service to run command against
12 | declare desc="unset encryption for future backups of the $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-unset-encryption" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
17 |
18 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
19 | verify_service_name "$SERVICE"
20 | service_backup_unset_encryption "$SERVICE"
21 | }
22 |
23 | service-backup-unset-encryption-cmd "$@"
24 |
--------------------------------------------------------------------------------
/subcommands/export:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-export-cmd() {
9 | #E by default, datastore output is exported to stdout
10 | #E dokku $PLUGIN_COMMAND_PREFIX:export lollipop
11 | #E you can redirect this output to a file
12 | #E dokku $PLUGIN_COMMAND_PREFIX:export lollipop > data.dump
13 | #A service, service to run command against
14 | declare desc="export a dump of the $PLUGIN_SERVICE service database"
15 | local cmd="$PLUGIN_COMMAND_PREFIX:export" argv=("$@")
16 | [[ ${argv[0]} == "$cmd" ]] && shift 1
17 | declare SERVICE="$1"
18 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
19 |
20 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
21 | verify_service_name "$SERVICE"
22 | service_export "$SERVICE"
23 | }
24 |
25 | service-export-cmd "$@"
26 |
--------------------------------------------------------------------------------
/pre-restore:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
4 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/functions"
5 | set -eo pipefail
6 | [[ $DOKKU_TRACE ]] && set -x
7 |
8 | plugin-pre-restore() {
9 | declare SCHEDULER="$1" APP="$2"
10 | local status
11 |
12 | if [[ "$SCHEDULER" != "docker-local" ]]; then
13 | return
14 | fi
15 |
16 | for SERVICE in $(fn-services-list false); do
17 | if ! in_links_file "$SERVICE" "$APP"; then
18 | continue
19 | fi
20 |
21 | status="$(service_status "$SERVICE")"
22 | if [[ "$status" == "running" ]]; then
23 | continue
24 | fi
25 |
26 | if [[ "$status" == "restarting" ]]; then
27 | dokku_log_warn "$PLUGIN_SERVICE service $SERVICE is restarting and may cause issues with linked app $APP"
28 | continue
29 | fi
30 |
31 | dokku_log_warn "$PLUGIN_SERVICE service $SERVICE is not running, issuing service start"
32 | service_start "$SERVICE"
33 | done
34 | }
35 |
36 | plugin-pre-restore "$@"
37 |
--------------------------------------------------------------------------------
/tests/service_create.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | @test "($PLUGIN_COMMAND_PREFIX:create) success" {
5 | run dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | assert_contains "${lines[*]}" "container created: l"
7 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
8 | }
9 |
10 | @test "($PLUGIN_COMMAND_PREFIX:create) service with dashes" {
11 | run dokku "$PLUGIN_COMMAND_PREFIX:create" service-with-dashes
12 | assert_contains "${lines[*]}" "container created: service-with-dashes"
13 | assert_contains "${lines[*]}" "dokku-$PLUGIN_COMMAND_PREFIX-service-with-dashes"
14 | assert_contains "${lines[*]}" "service_with_dashes"
15 |
16 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" service-with-dashes
17 | }
18 |
19 | @test "($PLUGIN_COMMAND_PREFIX:create) error when there are no arguments" {
20 | run dokku "$PLUGIN_COMMAND_PREFIX:create"
21 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
22 | }
23 |
24 | @test "($PLUGIN_COMMAND_PREFIX:create) error when there is an invalid name specified" {
25 | run dokku "$PLUGIN_COMMAND_PREFIX:create" d.erp
26 | assert_failure
27 | }
28 |
--------------------------------------------------------------------------------
/subcommands/connect:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-connect-cmd() {
9 | #E connect to the service via the $PLUGIN_COMMAND_PREFIX connection tool
10 | #E > NOTE: disconnecting from ssh while running this command may leave zombie processes due to moby/moby#9098
11 | #E dokku $PLUGIN_COMMAND_PREFIX:connect lollipop
12 | #A service, service to run command against
13 | declare desc="connect to the service via the $PLUGIN_COMMAND_PREFIX connection tool"
14 | local cmd="$PLUGIN_COMMAND_PREFIX:connect" argv=("$@")
15 | [[ ${argv[0]} == "$cmd" ]] && shift 1
16 | declare SERVICE="$1"
17 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
18 |
19 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
20 | verify_service_name "$SERVICE"
21 | service_connect "$SERVICE"
22 | }
23 |
24 | service-connect-cmd "$@"
25 |
--------------------------------------------------------------------------------
/subcommands/backup-unset-public-key-encryption:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-unset-public-key-encryption-cmd() {
9 | #E unset the GPG Public Key encryption for backups
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-unset-public-key-encryption lollipop
11 | #A service, service to run command against
12 | declare desc="unset GPG Public Key encryption for future backups of the $PLUGIN_SERVICE service"
13 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-unset-public-key-encryption" argv=("$@")
14 | [[ ${argv[0]} == "$cmd" ]] && shift 1
15 | declare SERVICE="$1"
16 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
17 |
18 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
19 | verify_service_name "$SERVICE"
20 | service_backup_unset_public_key_encryption "$SERVICE"
21 | }
22 |
23 | service-backup-unset-public-key-encryption-cmd "$@"
24 |
--------------------------------------------------------------------------------
/subcommands/linked:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-linked-cmd() {
9 | #E here we check if the lollipop $PLUGIN_COMMAND_PREFIX service is linked to the 'playground' app.
10 | #E dokku $PLUGIN_COMMAND_PREFIX:linked lollipop playground
11 | #A service, service to run command against
12 | #A app, app to run command against
13 | declare desc="check if the $PLUGIN_SERVICE service is linked to an app"
14 | local cmd="$PLUGIN_COMMAND_PREFIX:linked" argv=("$@")
15 | [[ ${argv[0]} == "$cmd" ]] && shift 1
16 | declare SERVICE="$1" APP="$2"
17 | APP=${APP:="$DOKKU_APP_NAME"}
18 |
19 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
20 | [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
21 | verify_app_name "$APP"
22 | verify_service_name "$SERVICE"
23 | service_is_linked "$SERVICE" "$APP"
24 | }
25 |
26 | service-linked-cmd "$@"
27 |
--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM dokku/dokku:latest
2 |
3 | RUN apt-get update
4 | RUN apt-get install --no-install-recommends -y build-essential file nano && \
5 | apt-get clean autoclean && \
6 | apt-get autoremove --yes && \
7 | rm -rf /var/lib/apt/lists/* && \
8 | mkdir -p /mnt/dokku/home/dokku /mnt/dokku/var/lib/dokku/config /mnt/dokku/var/lib/dokku/data /mnt/dokku/var/lib/dokku/services && \
9 | chown -R dokku:dokku /mnt/dokku/home/dokku /mnt/dokku/var/lib/dokku/config /mnt/dokku/var/lib/dokku/data /mnt/dokku/var/lib/dokku/services && \
10 | echo "dokku.me" > /home/dokku/VHOST
11 |
12 | ADD https://raw.githubusercontent.com/dokku/dokku/master/tests/dhparam.pem /mnt/dokku/etc/nginx/dhparam.pem
13 |
14 | COPY .devcontainer/20_init_plugin /etc/my_init.d/20_init_plugin
15 | COPY .devcontainer/bin/ /usr/local/bin/
16 |
17 | COPY . .
18 |
19 | RUN source /tmp/config && \
20 | echo "export ${PLUGIN_DISABLE_PULL_VARIABLE}=true" > /tmp/.env && \
21 | echo "export PLUGIN_NAME=${PLUGIN_COMMAND_PREFIX}" >> /tmp/.env && \
22 | echo "export PLUGIN_VARIABLE=${PLUGIN_VARIABLE}" >> /tmp/.env
23 |
24 | RUN source /tmp/.env && \
25 | dokku plugin:install file:///tmp --name $PLUGIN_NAME && \
26 | make ci-dependencies
27 |
--------------------------------------------------------------------------------
/subcommands/enter:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-enter-cmd() {
9 | #E a bash prompt can be opened against a running service.
10 | #E filesystem changes will not be saved to disk.
11 | #E > NOTE: disconnecting from ssh while running this command may leave zombie processes due to moby/moby#9098
12 | #E dokku $PLUGIN_COMMAND_PREFIX:enter lollipop
13 | #E you may also run a command directly against the service.
14 | #E filesystem changes will not be saved to disk.
15 | #E dokku $PLUGIN_COMMAND_PREFIX:enter lollipop touch /tmp/test
16 | #A service, service to run command against
17 | declare desc="enter or run a command in a running $PLUGIN_SERVICE service container"
18 | local cmd="$PLUGIN_COMMAND_PREFIX:enter" argv=("$@")
19 | [[ ${argv[0]} == "$cmd" ]] && shift 1
20 | declare SERVICE="$1"
21 |
22 | verify_service_name "$SERVICE"
23 | dokku_log_info1_quiet "Filesystem changes may not persist after container restarts"
24 | service_enter "$SERVICE" "${@:2}"
25 | }
26 |
27 | service-enter-cmd "$@"
28 |
--------------------------------------------------------------------------------
/subcommands/unlink:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-unlink-cmd() {
9 | #E you can unlink a $PLUGIN_COMMAND_PREFIX service
10 | #E > NOTE: this will restart your app and unset related environment variables
11 | #E dokku $PLUGIN_COMMAND_PREFIX:unlink lollipop playground
12 | #A service, service to run command against
13 | #A app, app to run command against
14 | #F -n|--no-restart "false", whether or not to restart the app on unlink (default: true)
15 | declare desc="unlink the $PLUGIN_SERVICE service from the app"
16 | local cmd="$PLUGIN_COMMAND_PREFIX:unlink" argv=("$@")
17 | [[ ${argv[0]} == "$cmd" ]] && shift 1
18 | declare SERVICE="$1" APP="$2"
19 | APP=${APP:="$DOKKU_APP_NAME"}
20 |
21 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
22 | [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
23 | verify_service_name "$SERVICE"
24 | verify_app_name "$APP"
25 | service_unlink "$SERVICE" "$APP"
26 | }
27 |
28 | service-unlink-cmd "$@"
29 |
--------------------------------------------------------------------------------
/tests/service_destroy.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | @test "($PLUGIN_COMMAND_PREFIX:destroy) success with --force" {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | run dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
7 | assert_contains "${lines[*]}" "container deleted: l"
8 | }
9 |
10 | @test "($PLUGIN_COMMAND_PREFIX:destroy) error when there are no arguments" {
11 | run dokku "$PLUGIN_COMMAND_PREFIX:destroy"
12 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
13 | }
14 |
15 | @test "($PLUGIN_COMMAND_PREFIX:destroy) error when container does not exist" {
16 | run dokku "$PLUGIN_COMMAND_PREFIX:destroy" non_existing_container
17 | assert_contains "${lines[*]}" "service non_existing_container does not exist"
18 | }
19 |
20 | @test "($PLUGIN_COMMAND_PREFIX:destroy) error when container is linked to an app" {
21 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
22 | dokku apps:create app
23 | dokku "$PLUGIN_COMMAND_PREFIX:link" l app
24 | run dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
25 | assert_contains "${lines[*]}" "Cannot delete linked service"
26 |
27 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" l app
28 | run dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
29 | assert_contains "${lines[*]}" "container deleted: l"
30 | }
31 |
--------------------------------------------------------------------------------
/subcommands/expose:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-expose-cmd() {
9 | #E expose the service on the service's normal ports, allowing access to it from the public interface (0.0.0.0)
10 | #E dokku $PLUGIN_COMMAND_PREFIX:expose lollipop ${PLUGIN_DATASTORE_PORTS[@]}
11 | #E expose the service on the service's normal ports, with the first on a specified ip address (127.0.0.1)
12 | #E dokku $PLUGIN_COMMAND_PREFIX:expose lollipop 127.0.0.1:${PLUGIN_DATASTORE_PORTS[@]}
13 | #A service, service to run command against
14 | #A ports, a list of ports to run against
15 | declare desc="expose a $PLUGIN_SERVICE service on custom host:port if provided (random port on the 0.0.0.0 interface if otherwise unspecified)"
16 | local cmd="$PLUGIN_COMMAND_PREFIX:expose" argv=("$@")
17 | [[ ${argv[0]} == "$cmd" ]] && shift 1
18 | declare SERVICE="$1" PORTS_LIST=("${@:2}")
19 |
20 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
21 | verify_service_name "$SERVICE"
22 | service_port_expose "$SERVICE" "${@:2}"
23 | }
24 |
25 | service-expose-cmd "$@"
26 |
--------------------------------------------------------------------------------
/tests/service_logs.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:logs) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:logs"
14 | echo "output: $output"
15 | echo "status: $status"
16 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
17 | assert_failure
18 | }
19 |
20 | @test "($PLUGIN_COMMAND_PREFIX:logs) error when service does not exist" {
21 | run dokku "$PLUGIN_COMMAND_PREFIX:logs" not_existing_service
22 | echo "output: $output"
23 | echo "status: $status"
24 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
25 | assert_failure
26 | }
27 |
28 | @test "($PLUGIN_COMMAND_PREFIX:logs) success when not tailing" {
29 | skip "This may fail if there is no log output"
30 | run dokku "$PLUGIN_COMMAND_PREFIX:logs" l
31 | echo "output: $output"
32 | echo "status: $status"
33 | assert_success
34 | }
35 |
36 | @test "($PLUGIN_COMMAND_PREFIX:logs) success when tailing" {
37 | skip "This will hang as it waits for log output"
38 | run dokku "$PLUGIN_COMMAND_PREFIX:logs" l -t
39 | echo "output: $output"
40 | echo "status: $status"
41 | assert_success
42 | }
43 |
--------------------------------------------------------------------------------
/subcommands/backup-set-encryption:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-set-encryption-cmd() {
9 | #E set the GPG-compatible passphrase for encrypting backups for backups
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-set-encryption lollipop
11 | #E public key encryption will take precendence over the passphrase encryption if both types are set.
12 | #A service, service to run command against
13 | #A passphrase, a GPG-compatible passphrase
14 | declare desc="set encryption for all future backups of $PLUGIN_SERVICE service"
15 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-set-encryption" argv=("$@")
16 | [[ ${argv[0]} == "$cmd" ]] && shift 1
17 | declare SERVICE="$1" PASSPHRASE="$2"
18 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
19 |
20 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
21 | [[ -z "$PASSPHRASE" ]] && dokku_log_fail "Please specify a GPG backup passphrase"
22 | verify_service_name "$SERVICE"
23 | service_backup_set_encryption "$SERVICE" "$PASSPHRASE"
24 | }
25 |
26 | service-backup-set-encryption-cmd "$@"
27 |
--------------------------------------------------------------------------------
/subcommands/logs:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-logs-cmd() {
9 | #E you can tail logs for a particular service:
10 | #E dokku $PLUGIN_COMMAND_PREFIX:logs lollipop
11 | #E by default, logs will not be tailed, but you can do this with the --tail flag:
12 | #E dokku $PLUGIN_COMMAND_PREFIX:logs lollipop --tail
13 | #E the default tail setting is to show all logs, but an initial count can also be specified
14 | #E dokku $PLUGIN_COMMAND_PREFIX:logs lollipop --tail 5
15 | #A service, service to run command against
16 | #F -t|--tail [], do not stop when end of the logs are reached and wait for additional output
17 | declare desc="print the most recent log(s) for this service"
18 | local cmd="$PLUGIN_COMMAND_PREFIX:logs" argv=("$@")
19 | [[ ${argv[0]} == "$cmd" ]] && shift 1
20 | declare SERVICE="$1" TAIL_FLAG="$2" TAIL_NUM_OPTIONAL="${3:-all}"
21 |
22 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
23 | verify_service_name "$SERVICE"
24 | service_logs "$SERVICE" "$TAIL_FLAG" "$TAIL_NUM_OPTIONAL"
25 | }
26 |
27 | service-logs-cmd "$@"
28 |
--------------------------------------------------------------------------------
/.github/labels.yml:
--------------------------------------------------------------------------------
1 | labels:
2 | - name: bc-break
3 | color: eb6420
4 | - name: blocks release
5 | color: "000000"
6 | - name: 'difficulty: easy'
7 | color: c5def5
8 | - name: 'difficulty: hard'
9 | color: e99695
10 | - name: 'difficulty: medium'
11 | color: fef2c0
12 | - name: hacktoberfest
13 | color: b0581d
14 | - name: 'needs: documentation'
15 | color: c2e0c6
16 | - name: 'needs: more info'
17 | color: c2e0c6
18 | - name: 'needs: rebase'
19 | color: c2e0c6
20 | - name: 'needs: tests'
21 | color: c2e0c6
22 | - name: 'status: duplicate'
23 | color: cccccc
24 | - name: 'status: fix-provided'
25 | color: c5def5
26 | - name: 'status: future'
27 | color: c5def5
28 | - name: 'status: has plan'
29 | color: c5def5
30 | - name: 'status: invalid'
31 | color: cccccc
32 | - name: 'status: merge for next minor'
33 | color: c5def5
34 | - name: 'status: merge for next patch'
35 | color: c5def5
36 | - name: 'status: wontfix'
37 | color: cccccc
38 | - name: 'type: bug'
39 | color: e01b1b
40 | - name: 'type: documentation'
41 | color: 0052cc
42 | - name: 'type: enhancement'
43 | color: 09ab3c
44 | - name: 'type: question'
45 | color: cc317c
46 | - name: 'type: refactor'
47 | color: 0052cc
48 | - name: 'type: rfc'
49 | color: 0052cc
50 | - name: 'type: roadmap'
51 | color: 0052cc
52 | - name: 'type: service'
53 | color: "5319e7"
54 | - name: 'type: support'
55 | color: cc317c
56 | - name: 'type: tests'
57 | color: 0052cc
58 |
--------------------------------------------------------------------------------
/subcommands/backup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-cmd() {
9 | #E backup the 'lollipop' service to the 'my-s3-bucket' bucket on AWS
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup lollipop my-s3-bucket --use-iam
11 | #E restore a backup file (assuming it was extracted via 'tar -xf backup.tgz')
12 | #E dokku $PLUGIN_COMMAND_PREFIX:import lollipop < backup-folder/export
13 | #F -u|--use-iam, use the IAM profile associated with the current server
14 | #A service, service to run command against
15 | #A bucket-name, name of the s3 bucket to upload backups to
16 | declare desc="create a backup of the $PLUGIN_SERVICE service to an existing s3 bucket"
17 | local cmd="$PLUGIN_COMMAND_PREFIX:backup" argv=("$@")
18 | [[ ${argv[0]} == "$cmd" ]] && shift 1
19 | declare SERVICE="$1" BUCKET_NAME="$2" USE_IAM_OPTIONAL_FLAG="$3"
20 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
21 |
22 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
23 | [[ -z "$BUCKET_NAME" ]] && dokku_log_fail "Please specify an aws bucket for the backup"
24 | verify_service_name "$SERVICE"
25 | service_backup "$SERVICE" "$BUCKET_NAME" "$USE_IAM_OPTIONAL_FLAG"
26 | }
27 |
28 | service-backup-cmd "$@"
29 |
--------------------------------------------------------------------------------
/subcommands/backup-set-public-key-encryption:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-set-public-key-encryption-cmd() {
9 | #E set the GPG Public Key for encrypting backups
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-set-public-key-encryption lollipop
11 | #E this method currently requires the to be present on the keyserver 'keyserver.ubuntu.com'
12 | #A service, service to run command against
13 | #A public-key-id, a GPG Public Key ID (or fingerprint) to use for encryption. Must be uploaded to the GPG keyserver beforehand.
14 | declare desc="set GPG Public Key encryption for all future backups of $PLUGIN_SERVICE service"
15 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-set-public-key-encryption" argv=("$@")
16 | [[ ${argv[0]} == "$cmd" ]] && shift 1
17 | declare SERVICE="$1" PUBLIC_KEY_ID="$2"
18 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
19 |
20 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
21 | [[ -z "$PUBLIC_KEY_ID" ]] && dokku_log_fail "Please specify a valid GPG Public Key ID (or fingerprint)"
22 | verify_service_name "$SERVICE"
23 | service_backup_set_public_key_encryption "$SERVICE" "$PUBLIC_KEY_ID"
24 | }
25 |
26 | service-backup-set-public-key-encryption-cmd "$@"
27 |
--------------------------------------------------------------------------------
/subcommands/backup-schedule:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-schedule-cmd() {
9 | #E schedule a backup
10 | #E > 'schedule' is a crontab expression, eg. "0 3 * * *" for each day at 3am
11 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-schedule lollipop "0 3 * * *" my-s3-bucket
12 | #E schedule a backup and authenticate via iam
13 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-schedule lollipop "0 3 * * *" my-s3-bucket --use-iam
14 | #F -u|--use-iam, use the IAM profile associated with the current server
15 | #A service, service to run command against
16 | #A schedule, a cron schedule to run backups on
17 | #A bucket-name, name of the s3 bucket to upload backups to
18 | declare desc="schedule a backup of the $PLUGIN_SERVICE service"
19 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-schedule" argv=("$@")
20 | [[ ${argv[0]} == "$cmd" ]] && shift 1
21 | declare SERVICE="$1" SCHEDULE="$2" BUCKET_NAME="$3" USE_IAM_OPTIONAL_FLAG="$4"
22 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
23 |
24 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
25 | [[ -z "$SCHEDULE" ]] && dokku_log_fail "Please specify a schedule for the backup"
26 | [[ -z "$BUCKET_NAME" ]] && dokku_log_fail "Please specify an aws bucket for the backup"
27 | verify_service_name "$SERVICE"
28 | service_backup_schedule "$SERVICE" "$SCHEDULE" "$BUCKET_NAME" "$USE_IAM_OPTIONAL_FLAG"
29 | }
30 |
31 | service-backup-schedule-cmd "$@"
32 |
--------------------------------------------------------------------------------
/tests/setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eo pipefail
3 | [[ $TRACE ]] && set -x
4 | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 762E3157
5 | echo "deb http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
6 | curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
7 |
8 | sudo mkdir -p /etc/nginx
9 | sudo curl https://raw.githubusercontent.com/dokku/dokku/master/tests/dhparam.pem -o /etc/nginx/dhparam.pem
10 |
11 | echo "dokku dokku/skip_key_file boolean true" | sudo debconf-set-selections
12 | wget https://raw.githubusercontent.com/dokku/dokku/master/bootstrap.sh
13 | if [[ "$DOKKU_VERSION" == "master" ]]; then
14 | sudo bash bootstrap.sh
15 | else
16 | sudo DOKKU_TAG="$DOKKU_VERSION" bash bootstrap.sh
17 | fi
18 | echo "Dokku version $DOKKU_VERSION"
19 |
20 | export DOKKU_LIB_ROOT="/var/lib/dokku"
21 | export DOKKU_PLUGINS_ROOT="$DOKKU_LIB_ROOT/plugins/available"
22 | pushd "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")" >/dev/null
23 | source "config"
24 | popd >/dev/null
25 | sudo rm -rf "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX"
26 | sudo mkdir -p "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX" "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX/subcommands" "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX/scripts" "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX/templates"
27 | sudo find ./ -maxdepth 1 -type f -exec cp '{}' "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX" \;
28 | [[ -d "./scripts" ]] && sudo find ./scripts -maxdepth 1 -type f -exec cp '{}' "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX/scripts" \;
29 | [[ -d "./subcommands" ]] && sudo find ./subcommands -maxdepth 1 -type f -exec cp '{}' "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX/subcommands" \;
30 | [[ -d "./templates" ]] && sudo find ./templates -maxdepth 1 -type f -exec cp '{}' "$DOKKU_PLUGINS_ROOT/$PLUGIN_COMMAND_PREFIX/templates" \;
31 | sudo mkdir -p "$PLUGIN_CONFIG_ROOT" "$PLUGIN_DATA_ROOT"
32 | sudo dokku plugin:enable "$PLUGIN_COMMAND_PREFIX"
33 | sudo dokku plugin:install
34 |
--------------------------------------------------------------------------------
/tests/test_helper.bash:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | export DOKKU_LIB_ROOT="/var/lib/dokku"
3 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
4 |
5 | flunk() {
6 | {
7 | if [ "$#" -eq 0 ]; then
8 | cat -
9 | else
10 | echo "$*"
11 | fi
12 | }
13 | return 1
14 | }
15 |
16 | assert_equal() {
17 | if [ "$1" != "$2" ]; then
18 | {
19 | echo "expected: $1"
20 | echo "actual: $2"
21 | } | flunk
22 | fi
23 | }
24 |
25 | # ShellCheck doesn't know about $status from Bats
26 | # shellcheck disable=SC2154
27 | assert_exit_status() {
28 | assert_equal "$1" "$status"
29 | }
30 |
31 | # ShellCheck doesn't know about $status from Bats
32 | # shellcheck disable=SC2154
33 | # shellcheck disable=SC2120
34 | assert_success() {
35 | if [ "$status" -ne 0 ]; then
36 | flunk "command failed with exit status $status"
37 | elif [ "$#" -gt 0 ]; then
38 | assert_output "$1"
39 | fi
40 | }
41 |
42 | assert_failure() {
43 | if [[ "$status" -eq 0 ]]; then
44 | flunk "expected failed exit status"
45 | elif [[ "$#" -gt 0 ]]; then
46 | assert_output "$1"
47 | fi
48 | }
49 |
50 | assert_exists() {
51 | if [ ! -f "$1" ]; then
52 | flunk "expected file to exist: $1"
53 | fi
54 | }
55 |
56 | assert_contains() {
57 | if [[ "$1" != *"$2"* ]]; then
58 | flunk "expected $2 to be in: $1"
59 | fi
60 | }
61 |
62 | # ShellCheck doesn't know about $output from Bats
63 | # shellcheck disable=SC2154
64 | assert_output() {
65 | local expected
66 | if [ $# -eq 0 ]; then
67 | expected="$(cat -)"
68 | else
69 | expected="$1"
70 | fi
71 | assert_equal "$expected" "$output"
72 | }
73 |
74 | # ShellCheck doesn't know about $output from Bats
75 | # shellcheck disable=SC2154
76 | assert_output_contains() {
77 | local input="$output"
78 | local expected="$1"
79 | local count="${2:-1}"
80 | local found=0
81 | until [ "${input/$expected/}" = "$input" ]; do
82 | input="${input/$expected/}"
83 | found=$((found + 1))
84 | done
85 | assert_equal "$count" "$found"
86 | }
87 |
--------------------------------------------------------------------------------
/subcommands/set:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
7 | source "$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)/common-functions"
8 |
9 | service-set-cmd() {
10 | #E set the network to attach after the service container is started
11 | #E dokku $PLUGIN_COMMAND_PREFIX:set lollipop post-create-network custom-network
12 | #E set multiple networks
13 | #E dokku $PLUGIN_COMMAND_PREFIX:set lollipop post-create-network custom-network,other-network
14 | #E unset the post-create-network value
15 | #E dokku $PLUGIN_COMMAND_PREFIX:set lollipop post-create-network
16 | #A service, service to run command against
17 | #A key, property name to set
18 | #A value, optional property value to set or empty to unset key
19 | declare desc="set or clear a property for a service"
20 | local cmd="$PLUGIN_COMMAND_PREFIX:set" argv=("$@")
21 | [[ ${argv[0]} == "$cmd" ]] && shift 1
22 | declare SERVICE="$1" KEY="$2" VALUE="$3"
23 | local VALID_KEYS=("initial-network" "post-create-network" "post-start-network")
24 | verify_service_name "$SERVICE"
25 |
26 | [[ -z "$KEY" ]] && dokku_log_fail "No key specified"
27 |
28 | if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then
29 | dokku_log_fail "Invalid key specified, valid keys include: initial-network, post-create-network, post-start-network"
30 | fi
31 |
32 | if [[ -n "$VALUE" ]]; then
33 | dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}"
34 | fn-plugin-property-write "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "$KEY" "$VALUE"
35 | else
36 | dokku_log_info2_quiet "Unsetting ${KEY}"
37 | if [[ "$KEY" == "rev-env-var" ]]; then
38 | fn-plugin-property-write "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "$KEY" "$VALUE"
39 | else
40 | fn-plugin-property-delete "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "$KEY"
41 | fi
42 | fi
43 | }
44 |
45 | service-set-cmd "$@"
46 |
--------------------------------------------------------------------------------
/config:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | _DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3 | export CLICKHOUSE_IMAGE=${CLICKHOUSE_IMAGE:="$(awk -F '[ :]' '{print $2}' "${_DIR}/Dockerfile")"}
4 | export CLICKHOUSE_IMAGE_VERSION=${CLICKHOUSE_IMAGE_VERSION:="$(awk -F '[ :]' '{print $3}' "${_DIR}/Dockerfile")"}
5 | export CLICKHOUSE_ROOT=${CLICKHOUSE_ROOT:="$DOKKU_LIB_ROOT/services/clickhouse"}
6 | export DOKKU_LIB_HOST_ROOT=${DOKKU_LIB_HOST_ROOT:=$DOKKU_LIB_ROOT}
7 | export CLICKHOUSE_HOST_ROOT=${CLICKHOUSE_HOST_ROOT:="$DOKKU_LIB_HOST_ROOT/services/clickhouse"}
8 |
9 | export PLUGIN_UNIMPLEMENTED_SUBCOMMANDS=("backup" "backup-auth" "backup-deauth" "backup-schedule" "backup-schedule-cat" "backup-set-encryption" "backup-unschedule" "backup-unset-encryption" "clone" "export" "import")
10 | export PLUGIN_COMMAND_PREFIX="clickhouse"
11 | export PLUGIN_CONFIG_ROOT=${PLUGIN_CONFIG_ROOT:="$DOKKU_LIB_ROOT/config/$PLUGIN_COMMAND_PREFIX"}
12 | export PLUGIN_DATA_ROOT=$CLICKHOUSE_ROOT
13 | export PLUGIN_DATA_HOST_ROOT=$CLICKHOUSE_HOST_ROOT
14 | export PLUGIN_DATASTORE_PORTS=(9000 8123)
15 | export PLUGIN_DATASTORE_WAIT_PORT=9000
16 | export PLUGIN_DEFAULT_ALIAS="CLICKHOUSE"
17 | export PLUGIN_DISABLE_PULL=${CLICKHOUSE_DISABLE_PULL:=}
18 | export PLUGIN_DISABLE_PULL_VARIABLE="CLICKHOUSE_DISABLE_PULL"
19 | export PLUGIN_ALT_ALIAS="DOKKU_CLICKHOUSE"
20 | export PLUGIN_IMAGE=$CLICKHOUSE_IMAGE
21 | export PLUGIN_IMAGE_VERSION=$CLICKHOUSE_IMAGE_VERSION
22 | export PLUGIN_SCHEME="clickhouse"
23 | export PLUGIN_SERVICE="Clickhouse"
24 | export PLUGIN_VARIABLE="CLICKHOUSE"
25 | export PLUGIN_BASE_PATH="$PLUGIN_PATH"
26 | export PLUGIN_CONFIG_SUFFIX="config"
27 | if [[ -n $DOKKU_API_VERSION ]]; then
28 | export PLUGIN_BASE_PATH="$PLUGIN_ENABLED_PATH"
29 | fi
30 |
31 | export PLUGIN_BUSYBOX_IMAGE=${PLUGIN_BUSYBOX_IMAGE:=busybox:1.37.0-uclibc}
32 | export PLUGIN_AMBASSADOR_IMAGE=${PLUGIN_AMBASSADOR_IMAGE:=dokku/ambassador:0.8.2}
33 | export PLUGIN_S3BACKUP_IMAGE=${PLUGIN_S3BACKUP_IMAGE:=dokku/s3backup:0.18.0}
34 | export PLUGIN_WAIT_IMAGE=${PLUGIN_WAIT_IMAGE:=dokku/wait:0.9.3}
35 |
36 | export CLICKHOUSE_CONFIG_OPTIONS=${CLICKHOUSE_CONFIG_OPTIONS:=""}
37 |
--------------------------------------------------------------------------------
/tests/service_expose.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" ls
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" ls
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:expose) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:expose"
14 | echo "output: $output"
15 | echo "status: $status"
16 | assert_failure
17 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
18 | }
19 |
20 | @test "($PLUGIN_COMMAND_PREFIX:expose) error when service does not exist" {
21 | run dokku "$PLUGIN_COMMAND_PREFIX:expose" not_existing_service
22 | echo "output: $output"
23 | echo "status: $status"
24 | assert_failure
25 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
26 | }
27 |
28 | @test "($PLUGIN_COMMAND_PREFIX:expose) error when already exposed" {
29 | run dokku "$PLUGIN_COMMAND_PREFIX:expose" ls
30 | echo "output: $output"
31 | echo "status: $status"
32 | assert_success
33 |
34 | run dokku "$PLUGIN_COMMAND_PREFIX:expose" ls
35 | echo "output: $output"
36 | echo "status: $status"
37 | assert_failure
38 | assert_contains "${lines[*]}" "Service ls already exposed on port(s)"
39 |
40 | run sudo rm "$PLUGIN_DATA_ROOT/ls/PORT"
41 | echo "output: $output"
42 | echo "status: $status"
43 | assert_success
44 |
45 | run dokku "$PLUGIN_COMMAND_PREFIX:expose" ls
46 | echo "output: $output"
47 | echo "status: $status"
48 | assert_success
49 | assert_contains "${lines[*]}" "Service ls has an untracked expose container, removing"
50 | }
51 |
52 | @test "($PLUGIN_COMMAND_PREFIX:expose) success when not providing custom ports" {
53 | run dokku "$PLUGIN_COMMAND_PREFIX:expose" ls
54 | echo "output: $output"
55 | echo "status: $status"
56 | assert_success
57 | [[ "${lines[*]}" =~ exposed\ on\ port\(s\)\ \[container\-\>host\]\:\ [[:digit:]]+ ]]
58 | }
59 |
60 | @test "($PLUGIN_COMMAND_PREFIX:expose) success when providing custom ports" {
61 | run dokku "$PLUGIN_COMMAND_PREFIX:expose" ls 4242 4243
62 | echo "output: $output"
63 | echo "status: $status"
64 | assert_success
65 | assert_contains "${lines[*]}" "exposed on port(s) [container->host]: 9000->4242 8123->4243"
66 | }
67 |
--------------------------------------------------------------------------------
/subcommands/promote:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-promote-cmd() {
9 | #E if you have a $PLUGIN_COMMAND_PREFIX service linked to an app and try to link another $PLUGIN_COMMAND_PREFIX service
10 | #E another link environment variable will be generated automatically:
11 | #E
12 | #E DOKKU_${PLUGIN_DEFAULT_ALIAS}_BLUE_URL=${PLUGIN_SCHEME}://other_service:ANOTHER_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-other-service:${PLUGIN_DATASTORE_PORTS[0]}/other_service
13 | #E
14 | #E you can promote the new service to be the primary one
15 | #E > NOTE: this will restart your app
16 | #E dokku $PLUGIN_COMMAND_PREFIX:promote other_service playground
17 | #E this will replace ${PLUGIN_DEFAULT_ALIAS}_URL with the url from other_service and generate
18 | #E another environment variable to hold the previous value if necessary.
19 | #E you could end up with the following for example:
20 | #E
21 | #E ${PLUGIN_DEFAULT_ALIAS}_URL=${PLUGIN_SCHEME}://other_service:ANOTHER_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-other-service:${PLUGIN_DATASTORE_PORTS[0]}/other_service
22 | #E DOKKU_${PLUGIN_DEFAULT_ALIAS}_BLUE_URL=${PLUGIN_SCHEME}://other_service:ANOTHER_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-other-service:${PLUGIN_DATASTORE_PORTS[0]}/other_service
23 | #E DOKKU_${PLUGIN_DEFAULT_ALIAS}_SILVER_URL=${PLUGIN_SCHEME}://lollipop:SOME_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-lollipop:${PLUGIN_DATASTORE_PORTS[0]}/lollipop
24 | #A service, service to run command against
25 | #A app, app to run command against
26 | declare desc="promote service as ${PLUGIN_DEFAULT_ALIAS}_URL in "
27 | local cmd="$PLUGIN_COMMAND_PREFIX:promote" argv=("$@")
28 | [[ ${argv[0]} == "$cmd" ]] && shift 1
29 | declare SERVICE="$1" APP="$2"
30 | APP=${APP:="$DOKKU_APP_NAME"}
31 |
32 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
33 | [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
34 | verify_service_name "$SERVICE"
35 | verify_app_name "$APP"
36 | service_promote "$SERVICE" "$APP"
37 | }
38 |
39 | service-promote-cmd "$@"
40 |
--------------------------------------------------------------------------------
/subcommands/backup-auth:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-backup-auth-cmd() {
9 | #E setup s3 backup authentication
10 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-auth lollipop AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
11 | #E setup s3 backup authentication with different region
12 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-auth lollipop AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION
13 | #E setup s3 backup authentication with different signature version and endpoint
14 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-auth lollipop AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION AWS_SIGNATURE_VERSION ENDPOINT_URL
15 | #E more specific example for minio auth
16 | #E dokku $PLUGIN_COMMAND_PREFIX:backup-auth lollipop MINIO_ACCESS_KEY_ID MINIO_SECRET_ACCESS_KEY us-east-1 s3v4 https://YOURMINIOSERVICE
17 | #A service, service to run command against
18 | #A access-key-id, an amazon AWS_ACCESS_KEY_ID
19 | #A aws-secret-access-key, an amazon AWS_SECRET_ACCESS_KEY
20 | #A aws-default-region, (optional) a valid amazon S3 region
21 | #A aws-signature-version, (optional) the AWS signature version to use when signing S3 requests
22 | #A endpoint-url, (optional) an aws endpoint to upload to
23 | declare desc="set up authentication for backups on the $PLUGIN_SERVICE service"
24 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-auth" argv=("$@")
25 | [[ ${argv[0]} == "$cmd" ]] && shift 1
26 | declare SERVICE="$1" AWS_ACCESS_KEY_ID="$2" AWS_SECRET_ACCESS_KEY="$3" AWS_DEFAULT_REGION="$4" AWS_SIGNATURE_VERSION="$5" ENDPOINT_URL="$6"
27 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
28 |
29 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
30 | [[ -z "$AWS_ACCESS_KEY_ID" ]] && dokku_log_fail "Please specify an aws access key id"
31 | [[ -z "$AWS_SECRET_ACCESS_KEY" ]] && dokku_log_fail "Please specify an aws secret access key"
32 | verify_service_name "$SERVICE"
33 | service_backup_auth "$SERVICE" "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" "$AWS_DEFAULT_REGION" "$AWS_SIGNATURE_VERSION" "$ENDPOINT_URL"
34 | }
35 |
36 | service-backup-auth-cmd "$@"
37 |
--------------------------------------------------------------------------------
/subcommands/create:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-create-cmd() {
9 | #E create a $PLUGIN_COMMAND_PREFIX service named lollipop
10 | #E dokku $PLUGIN_COMMAND_PREFIX:create lollipop
11 | #E you can also specify the image and image version to use for the service.
12 | #E it *must* be compatible with the ${PLUGIN_IMAGE} image.
13 | #E export ${PLUGIN_VARIABLE}_IMAGE="${PLUGIN_IMAGE}"
14 | #E export ${PLUGIN_VARIABLE}_IMAGE_VERSION="${PLUGIN_IMAGE_VERSION}"
15 | #E dokku $PLUGIN_COMMAND_PREFIX:create lollipop
16 | #E you can also specify custom environment variables to start
17 | #E the ${PLUGIN_COMMAND_PREFIX} service in semicolon-separated form.
18 | #E export ${PLUGIN_VARIABLE}_CUSTOM_ENV="USER=alpha;HOST=beta"
19 | #E dokku $PLUGIN_COMMAND_PREFIX:create lollipop
20 | #A service, service to run command against
21 | #F -c|--config-options "--args --go=here", extra arguments to pass to the container create command
22 | #F -C|--custom-env "USER=alpha;HOST=beta", semi-colon delimited environment variables to start the service with
23 | #F -i|--image IMAGE, the image name to start the service with
24 | #F -I|--image-version IMAGE_VERSION, the image version to start the service with
25 | #F -m|--memory MEMORY, container memory limit in megabytes (default: unlimited)
26 | #F -N|--initial-network INITIAL_NETWORK, the initial network to attach the service to
27 | #F -p|--password PASSWORD, override the user-level service password
28 | #F -P|--post-create-network NETWORKS, a comma-separated list of networks to attach the service container to after service creation
29 | #F -r|--root-password PASSWORD, override the root-level service password
30 | #F -S|--post-start-network NETWORKS, a comma-separated list of networks to attach the service container to after service start
31 | #F -s|--shm-size SHM_SIZE, override shared memory size for $PLUGIN_COMMAND_PREFIX docker container
32 | declare desc="create a $PLUGIN_SERVICE service"
33 | local cmd="$PLUGIN_COMMAND_PREFIX:create" argv=("$@")
34 | [[ ${argv[0]} == "$cmd" ]] && shift 1
35 | declare SERVICE="$1" CREATE_FLAGS_LIST=("${@:2}")
36 |
37 | service_create "$SERVICE" "${@:2}"
38 | }
39 |
40 | service-create-cmd "$@"
41 |
--------------------------------------------------------------------------------
/subcommands/info:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-info-cmd() {
9 | #E get connection information as follows:
10 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop
11 | #E you can also retrieve a specific piece of service info via flags:
12 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --config-dir
13 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --data-dir
14 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --dsn
15 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --exposed-ports
16 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --id
17 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --internal-ip
18 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --initial-network
19 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --links
20 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --post-create-network
21 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --post-start-network
22 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --service-root
23 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --status
24 | #E dokku $PLUGIN_COMMAND_PREFIX:info lollipop --version
25 | #A service, service to run command against
26 | #F --config-dir, show the service configuration directory
27 | #F --data-dir, show the service data directory
28 | #F --dsn, show the service DSN
29 | #F --exposed-ports, show service exposed ports
30 | #F --id, show the service container id
31 | #F --internal-ip, show the service internal ip
32 | #F --initial-network, show the initial network being connected to
33 | #F --links, show the service app links
34 | #F --post-create-network, show the networks to attach to after service container creation
35 | #F --post-start-network, show the networks to attach to after service container start
36 | #F --service-root, show the service root directory
37 | #F --status, show the service running status
38 | #F --version, show the service image version
39 | declare desc="print the service information"
40 | local cmd="$PLUGIN_COMMAND_PREFIX:info" argv=("$@")
41 | [[ ${argv[0]} == "$cmd" ]] && shift 1
42 | declare SERVICE="$1" INFO_FLAG="$2"
43 |
44 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
45 | verify_service_name "$SERVICE"
46 | service_info "$SERVICE" "$INFO_FLAG"
47 | }
48 |
49 | service-info-cmd "$@"
50 |
--------------------------------------------------------------------------------
/subcommands/destroy:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-destroy-cmd() {
9 | #E destroy the service, it's data, and the running container
10 | #E dokku $PLUGIN_COMMAND_PREFIX:destroy lollipop
11 | #A service, service to run command against
12 | #F -f|--force, force destroy without asking for confirmation
13 | declare desc="delete the $PLUGIN_SERVICE service/data/container if there are no links left"
14 | local cmd="$PLUGIN_COMMAND_PREFIX:destroy" argv=("$@")
15 | [[ ${argv[0]} == "$cmd" ]] && shift 1
16 | declare SERVICE="$1" FORCE_FLAG="$2"
17 |
18 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
19 | verify_service_name "$SERVICE"
20 | SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
21 | LINKS_FILE="$SERVICE_ROOT/LINKS"
22 | SERVICE_HOST_ROOT="$PLUGIN_DATA_HOST_ROOT/$SERVICE"
23 | SERVICE_NAME="$(get_service_name "$SERVICE")"
24 |
25 | [[ -s "$LINKS_FILE" ]] && dokku_log_fail "Cannot delete linked service"
26 |
27 | if [[ "$FORCE_FLAG" == "force" ]] || [[ "$FORCE_FLAG" == "-f" ]] || [[ "$FORCE_FLAG" == "--force" ]]; then
28 | DOKKU_APPS_FORCE_DELETE=1
29 | fi
30 | if [[ -z "$DOKKU_APPS_FORCE_DELETE" ]]; then
31 | dokku_log_warn "WARNING: Potentially Destructive Action"
32 | dokku_log_warn "This command will destroy $SERVICE $PLUGIN_SERVICE service."
33 | dokku_log_warn "To proceed, type \"$SERVICE\""
34 | echo ""
35 |
36 | read -rp "> " service_name
37 | if [[ "$service_name" != "$SERVICE" ]]; then
38 | dokku_log_warn "Confirmation did not match $SERVICE. Aborted."
39 | exit 1
40 | fi
41 | fi
42 |
43 | dokku_log_info2_quiet "Deleting $SERVICE"
44 | plugn trigger service-action pre-delete "$PLUGIN_COMMAND_PREFIX" "$SERVICE"
45 | service_backup_unschedule "$SERVICE"
46 | service_container_rm "$SERVICE"
47 |
48 | dokku_log_verbose_quiet "Removing data"
49 | "$DOCKER_BIN" container run --rm -v "$SERVICE_HOST_ROOT/data:/data" -v "$SERVICE_HOST_ROOT/$PLUGIN_CONFIG_SUFFIX:/config" "$PLUGIN_BUSYBOX_IMAGE" chmod 777 -R /config /data
50 | rm -rf "$SERVICE_ROOT"
51 |
52 | fn-plugin-property-destroy "$PLUGIN_COMMAND_PREFIX" "$SERVICE"
53 |
54 | plugn trigger service-action post-delete "$PLUGIN_COMMAND_PREFIX" "$SERVICE"
55 | dokku_log_info2 "$PLUGIN_SERVICE container deleted: $SERVICE"
56 | }
57 |
58 | service-destroy-cmd "$@"
59 |
--------------------------------------------------------------------------------
/tests/service_info.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | }
7 |
8 | teardown() {
9 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
10 | }
11 |
12 | @test "($PLUGIN_COMMAND_PREFIX:info) error when there are no arguments" {
13 | run dokku "$PLUGIN_COMMAND_PREFIX:info"
14 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
15 | }
16 |
17 | @test "($PLUGIN_COMMAND_PREFIX:info) error when service does not exist" {
18 | run dokku "$PLUGIN_COMMAND_PREFIX:info" not_existing_service
19 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
20 | }
21 |
22 | @test "($PLUGIN_COMMAND_PREFIX:info) success" {
23 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l
24 | local password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")"
25 | assert_contains "${lines[*]}" "clickhouse://l:$password@dokku-clickhouse-l:9000/l"
26 | }
27 |
28 | @test "($PLUGIN_COMMAND_PREFIX:info) replaces underscores by dash in hostname" {
29 | dokku "$PLUGIN_COMMAND_PREFIX:create" test_with_underscores
30 | run dokku "$PLUGIN_COMMAND_PREFIX:info" test_with_underscores
31 | local password="$(sudo cat "$PLUGIN_DATA_ROOT/test_with_underscores/PASSWORD")"
32 | assert_contains "${lines[*]}" "clickhouse://test_with_underscores:$password@dokku-clickhouse-test-with-underscores:9000/test_with_underscores"
33 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" test_with_underscores
34 | }
35 |
36 | @test "($PLUGIN_COMMAND_PREFIX:info) success with flag" {
37 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --dsn
38 | local password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")"
39 | assert_output "clickhouse://l:$password@dokku-clickhouse-l:9000/l"
40 |
41 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --config-dir
42 | assert_success
43 |
44 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --data-dir
45 | assert_success
46 |
47 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --dsn
48 | assert_success
49 |
50 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --exposed-ports
51 | assert_success
52 |
53 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --id
54 | assert_success
55 |
56 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --internal-ip
57 | assert_success
58 |
59 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --links
60 | assert_success
61 |
62 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --service-root
63 | assert_success
64 |
65 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --service-root
66 | assert_success
67 |
68 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --status
69 | assert_success
70 |
71 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --version
72 | assert_success
73 | }
74 |
75 | @test "($PLUGIN_COMMAND_PREFIX:info) error when invalid flag" {
76 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --invalid-flag
77 | assert_failure
78 | }
79 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: CI
3 |
4 | # yamllint disable-line rule:truthy
5 | on:
6 | pull_request:
7 | branches:
8 | - "*"
9 | push:
10 | branches:
11 | - master
12 |
13 | concurrency:
14 | group: build-${{ github.event.pull_request.number || github.ref }}
15 | cancel-in-progress: true
16 |
17 | jobs:
18 | unit-tests-master:
19 | name: unit-tests
20 | runs-on: ubuntu-24.04
21 | env:
22 | DOKKU_VERSION: master
23 |
24 | steps:
25 | - uses: actions/checkout@v6
26 | with:
27 | fetch-depth: 0
28 |
29 | - uses: actions/setup-python@v6
30 | with:
31 | python-version: "3.13"
32 |
33 | - run: make setup
34 |
35 | - run: sudo sysctl -w vm.max_map_count=262144
36 |
37 | - run: |
38 | git fetch -q origin master
39 | changed=$(git --no-pager diff --name-only $GITHUB_SHA..origin/master)
40 | if [ $changed = "Dockerfile" ]; then
41 | echo "Please run 'make generate' to update the image version in the README.md"
42 | else
43 | make generate
44 | if ! git diff --quiet README.md; then
45 | echo "Please run 'make generate'"
46 | git status --short
47 | git --no-pager diff README.md
48 | exit 1
49 | fi
50 | fi
51 |
52 | - run: make test
53 |
54 | - uses: actions/upload-artifact@v6
55 | if: failure()
56 | with:
57 | name: tmp/test-results
58 | path: test-results
59 |
60 | unit-tests-0_19_0:
61 | name: unit-tests-0.19.0
62 | runs-on: ubuntu-24.04
63 | env:
64 | DOKKU_TAG: v0.19.0
65 |
66 | steps:
67 | - uses: actions/checkout@v6
68 | with:
69 | fetch-depth: 0
70 |
71 | - uses: actions/setup-python@v6
72 | with:
73 | python-version: "3.13"
74 |
75 | - run: make setup
76 |
77 | - run: sudo sysctl -w vm.max_map_count=262144
78 |
79 | - run: |
80 | git fetch -q origin master
81 | changed=$(git --no-pager diff --name-only $GITHUB_SHA..origin/master)
82 | if [ $changed = "Dockerfile" ]; then
83 | echo "Please run 'make generate' to update the image version in the README.md"
84 | else
85 | make generate
86 | if ! git diff --quiet README.md; then
87 | echo "Please run 'make generate'"
88 | git status --short
89 | git --no-pager diff README.md
90 | exit 1
91 | fi
92 | fi
93 |
94 | - run: make test
95 |
96 | - uses: actions/upload-artifact@v6
97 | if: failure()
98 | with:
99 | name: tmp/test-results
100 | path: test-results
101 |
--------------------------------------------------------------------------------
/tests/service_unlink.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku apps:create my-app
6 | dokku "$PLUGIN_COMMAND_PREFIX:create" ls
7 | }
8 |
9 | teardown() {
10 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" ls
11 | dokku --force apps:destroy my-app
12 | }
13 |
14 | @test "($PLUGIN_COMMAND_PREFIX:unlink) error when there are no arguments" {
15 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink"
16 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
17 | }
18 |
19 | @test "($PLUGIN_COMMAND_PREFIX:unlink) error when the app argument is missing" {
20 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls
21 | assert_contains "${lines[*]}" "Please specify an app to run the command on"
22 | }
23 |
24 | @test "($PLUGIN_COMMAND_PREFIX:unlink) error when the app does not exist" {
25 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls not_existing_app
26 | assert_contains "${lines[*]}" "App not_existing_app does not exist"
27 | }
28 |
29 | @test "($PLUGIN_COMMAND_PREFIX:unlink) error when the service does not exist" {
30 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" not_existing_service my-app
31 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
32 | }
33 |
34 | @test "($PLUGIN_COMMAND_PREFIX:unlink) error when service not linked to app" {
35 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
36 | assert_contains "${lines[*]}" "Not linked to app my-app"
37 | }
38 |
39 | @test "($PLUGIN_COMMAND_PREFIX:unlink) removes link from docker-options" {
40 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app >&2
41 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
42 |
43 | check_value="Docker options build: Docker options deploy: --restart=on-failure:10 Docker options run:"
44 | options=$(dokku --quiet docker-options:report my-app | xargs)
45 | assert_equal "$options" "$check_value"
46 | }
47 |
48 | @test "($PLUGIN_COMMAND_PREFIX:unlink) unsets config url from app" {
49 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app >&2
50 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
51 | config=$(dokku config:get my-app CLICKHOUSE_URL || true)
52 | assert_equal "$config" ""
53 | }
54 |
55 | @test "($PLUGIN_COMMAND_PREFIX:unlink) respects --no-restart" {
56 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
57 | echo "output: $output"
58 | echo "status: $status"
59 | assert_success
60 |
61 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
62 | echo "output: $output"
63 | echo "status: $status"
64 | assert_output_contains "Skipping restart of linked app" 0
65 | assert_success
66 |
67 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
68 | echo "output: $output"
69 | echo "status: $status"
70 | assert_success
71 |
72 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app --no-restart
73 | echo "output: $output"
74 | echo "status: $status"
75 | assert_output_contains "Skipping restart of linked app"
76 | assert_success
77 | }
78 |
--------------------------------------------------------------------------------
/tests/service_promote.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l
6 | dokku apps:create my-app
7 | dokku "$PLUGIN_COMMAND_PREFIX:link" l my-app
8 | }
9 |
10 | teardown() {
11 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" l my-app
12 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l
13 | dokku --force apps:destroy my-app
14 | }
15 |
16 | @test "($PLUGIN_COMMAND_PREFIX:promote) error when there are no arguments" {
17 | run dokku "$PLUGIN_COMMAND_PREFIX:promote"
18 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
19 | }
20 |
21 | @test "($PLUGIN_COMMAND_PREFIX:promote) error when the app argument is missing" {
22 | run dokku "$PLUGIN_COMMAND_PREFIX:promote" l
23 | assert_contains "${lines[*]}" "Please specify an app to run the command on"
24 | }
25 |
26 | @test "($PLUGIN_COMMAND_PREFIX:promote) error when the app does not exist" {
27 | run dokku "$PLUGIN_COMMAND_PREFIX:promote" l not_existing_app
28 | assert_contains "${lines[*]}" "App not_existing_app does not exist"
29 | }
30 |
31 | @test "($PLUGIN_COMMAND_PREFIX:promote) error when the service does not exist" {
32 | run dokku "$PLUGIN_COMMAND_PREFIX:promote" not_existing_service my-app
33 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
34 | }
35 |
36 | @test "($PLUGIN_COMMAND_PREFIX:promote) error when the service is already promoted" {
37 | run dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app
38 | assert_contains "${lines[*]}" "already promoted as CLICKHOUSE_URL"
39 | }
40 |
41 | @test "($PLUGIN_COMMAND_PREFIX:promote) changes CLICKHOUSE_URL" {
42 | password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")"
43 | dokku config:set my-app "CLICKHOUSE_URL=clickhouse://u:p@host:9000/db" "DOKKU_CLICKHOUSE_BLUE_URL=clickhouse://l:$password@dokku-clickhouse-l:9000/l"
44 | dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app
45 | url=$(dokku config:get my-app CLICKHOUSE_URL)
46 | assert_equal "$url" "clickhouse://l:$password@dokku-clickhouse-l:9000/l"
47 | }
48 |
49 | @test "($PLUGIN_COMMAND_PREFIX:promote) creates new config url when needed" {
50 | password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")"
51 | dokku config:set my-app "CLICKHOUSE_URL=clickhouse://u:p@host:9000/db" "DOKKU_CLICKHOUSE_BLUE_URL=clickhouse://l:$password@dokku-clickhouse-l:9000/l"
52 | dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app
53 | run dokku config my-app
54 | assert_contains "${lines[*]}" "DOKKU_CLICKHOUSE_"
55 | }
56 |
57 | @test "($PLUGIN_COMMAND_PREFIX:promote) uses CLICKHOUSE_DATABASE_SCHEME variable" {
58 | password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")"
59 | dokku config:set my-app "CLICKHOUSE_DATABASE_SCHEME=clickhouse2" "CLICKHOUSE_URL=clickhouse://u:p@host:9000/db" "DOKKU_CLICKHOUSE_BLUE_URL=clickhouse2://l:$password@dokku-clickhouse-l:9000/l"
60 | dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app
61 | url=$(dokku config:get my-app CLICKHOUSE_URL)
62 | assert_contains "$url" "clickhouse2://l:$password@dokku-clickhouse-l:9000/l"
63 | }
64 |
--------------------------------------------------------------------------------
/install:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
4 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
5 | set -eo pipefail
6 | [[ $DOKKU_TRACE ]] && set -x
7 |
8 | plugin-install() {
9 | pull-docker-image() {
10 | declare IMAGE="$1"
11 | if [[ "$PLUGIN_DISABLE_PULL" == "true" ]]; then
12 | echo " ! ${PLUGIN_DISABLE_PULL_VARIABLE} environment variable detected. Not running pull command." 1>&2
13 | echo " ! docker image pull ${IMAGE}" 1>&2
14 | return
15 | fi
16 | if [[ "$("$DOCKER_BIN" image ls -q "${IMAGE}" 2>/dev/null)" == "" ]]; then
17 | "$DOCKER_BIN" image pull "${IMAGE}"
18 | fi
19 | }
20 |
21 | fn-plugin-property-setup "$PLUGIN_COMMAND_PREFIX"
22 | pull-docker-image "${PLUGIN_IMAGE}:${PLUGIN_IMAGE_VERSION}"
23 | pull-docker-image "$PLUGIN_BUSYBOX_IMAGE"
24 | pull-docker-image "$PLUGIN_AMBASSADOR_IMAGE"
25 | pull-docker-image "$PLUGIN_S3BACKUP_IMAGE"
26 | pull-docker-image "$PLUGIN_WAIT_IMAGE"
27 |
28 | mkdir -p "$PLUGIN_DATA_ROOT" || echo "Failed to create $PLUGIN_SERVICE data directory"
29 | chown "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "$PLUGIN_DATA_ROOT"
30 |
31 | mkdir -p "$PLUGIN_CONFIG_ROOT" || echo "Failed to create $PLUGIN_SERVICE config directory"
32 | chown "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "$PLUGIN_CONFIG_ROOT"
33 |
34 | rm -f "/etc/sudoers.d/dokku-${PLUGIN_COMMAND_PREFIX}*"
35 | _SUDOERS_FILE="/etc/sudoers.d/dokku-${PLUGIN_COMMAND_PREFIX}"
36 |
37 | touch "$_SUDOERS_FILE"
38 | cat >"$_SUDOERS_FILE" <"$SERVICE_ROOT/IMAGE"
56 | echo "${image##*:}" >"$SERVICE_ROOT/IMAGE_VERSION"
57 | fi
58 | fi
59 |
60 | chown "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "$SERVICE_ROOT/IMAGE" "$SERVICE_ROOT/IMAGE_VERSION"
61 |
62 | if [[ -f "$SERVICE_ROOT/${PLUGIN_VARIABLE}_CONFIG_OPTIONS" ]]; then
63 | mv "$SERVICE_ROOT/${PLUGIN_VARIABLE}_CONFIG_OPTIONS" "$SERVICE_ROOT/CONFIG_OPTIONS"
64 | chown "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "$SERVICE_ROOT/CONFIG_OPTIONS"
65 | fi
66 | done
67 | }
68 |
69 | plugin-install "$@"
70 |
--------------------------------------------------------------------------------
/subcommands/clone:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-clone-cmd() {
9 | #E you can clone an existing service to a new one
10 | #E dokku $PLUGIN_COMMAND_PREFIX:clone lollipop lollipop-2
11 | #A service, service to run command against
12 | #A new-service, name of new service
13 | #F -c|--config-options "--args --go=here", extra arguments to pass to the container create command
14 | #F -C|--custom-env "USER=alpha;HOST=beta", semi-colon delimited environment variables to start the service with
15 | #F -i|--image IMAGE, the image name to start the service with
16 | #F -I|--image-version IMAGE_VERSION, the image version to start the service with
17 | #F -m|--memory MEMORY, container memory limit in megabytes (default: unlimited)
18 | #F -N|--initial-network INITIAL_NETWORK, the initial network to attach the service to
19 | #F -p|--password PASSWORD, override the user-level service password
20 | #F -P|--post-create-network NETWORKS, a comma-separated list of networks to attach the service container to after service creation
21 | #F -r|--root-password PASSWORD, override the root-level service password
22 | #F -S|--post-start-network NETWORKS, a comma-separated list of networks to attach the service container to after service start
23 | #F -s|--shm-size SHM_SIZE, override shared memory size for $PLUGIN_COMMAND_PREFIX docker container
24 | declare desc="create container then copy data from into "
25 | local cmd="$PLUGIN_COMMAND_PREFIX:clone" argv=("$@")
26 | [[ ${argv[0]} == "$cmd" ]] && shift 1
27 | declare SERVICE="$1" NEW_SERVICE="$2" CLONE_FLAGS_LIST=("${@:3}")
28 | is_implemented_command "$cmd" || dokku_log_fail "Not yet implemented"
29 |
30 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
31 | [[ -z "$NEW_SERVICE" ]] && dokku_log_fail "Please specify a name for the new service"
32 | verify_service_name "$SERVICE"
33 | if service_exists "$NEW_SERVICE"; then
34 | dokku_log_fail "Invalid service name $NEW_SERVICE. Verify the service name is not already in use."
35 | fi
36 |
37 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
38 | local ID="$(cat "$SERVICE_ROOT/ID")"
39 | is_container_status "$ID" "Running" || dokku_log_fail "Service ${SERVICE} container is not running"
40 |
41 | PLUGIN_IMAGE=$(service_version "$SERVICE" | grep -o "^.*:" | sed -r "s/://g")
42 | PLUGIN_IMAGE_VERSION=$(service_version "$SERVICE" | grep -o ":.*$" | sed -r "s/://g")
43 |
44 | service_parse_args "${@:3}"
45 |
46 | dokku_log_info2 "Cloning $SERVICE to $NEW_SERVICE @ $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION"
47 | service_create "$NEW_SERVICE" "${@:3}"
48 | dokku_log_info1 "Copying data from $SERVICE to $NEW_SERVICE"
49 | service_export "$SERVICE" | service_import "$NEW_SERVICE" >/dev/null 2>&1 || true
50 | dokku_log_info2 "Done"
51 | }
52 |
53 | service-clone-cmd "$@"
54 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | HARDWARE = $(shell uname -m)
2 | SYSTEM_NAME = $(shell uname -s | tr '[:upper:]' '[:lower:]')
3 | ARCH = $(shell dpkg --print-architecture)
4 | SHFMT_VERSION = 3.0.2
5 | XUNIT_TO_GITHUB_VERSION = 0.3.0
6 | XUNIT_READER_VERSION = 0.1.0
7 |
8 |
9 | bats:
10 | ifeq ($(SYSTEM_NAME),darwin)
11 | ifneq ($(shell bats --version >/dev/null 2>&1 ; echo $$?),0)
12 | brew install bats-core
13 | endif
14 | else
15 | git clone https://github.com/bats-core/bats-core.git /tmp/bats
16 | cd /tmp/bats && sudo ./install.sh /usr/local
17 | rm -rf /tmp/bats
18 | endif
19 |
20 | shellcheck:
21 | ifneq ($(shell shellcheck --version >/dev/null 2>&1 ; echo $$?),0)
22 | ifeq ($(SYSTEM_NAME),darwin)
23 | brew install shellcheck
24 | else
25 | ifeq ($(ARCH),arm64)
26 | sudo add-apt-repository 'deb http://ports.ubuntu.com/ubuntu-ports jammy-backports main restricted universe multiverse'
27 | else
28 | sudo add-apt-repository 'deb http://archive.ubuntu.com/ubuntu jammy-backports main restricted universe multiverse'
29 | endif
30 | sudo rm -rf /var/lib/apt/lists/* && sudo apt-get clean
31 | sudo apt-get update -qq && sudo apt-get install -qq -y shellcheck
32 | endif
33 | endif
34 |
35 | shfmt:
36 | ifneq ($(shell shfmt --version >/dev/null 2>&1 ; echo $$?),0)
37 | ifeq ($(shfmt),Darwin)
38 | brew install shfmt
39 | else
40 | wget -qO /tmp/shfmt https://github.com/mvdan/sh/releases/download/v$(SHFMT_VERSION)/shfmt_v$(SHFMT_VERSION)_linux_amd64
41 | chmod +x /tmp/shfmt
42 | sudo mv /tmp/shfmt /usr/local/bin/shfmt
43 | endif
44 | endif
45 |
46 | readlink:
47 | ifeq ($(shell uname),Darwin)
48 | ifeq ($(shell greadlink > /dev/null 2>&1 ; echo $$?),127)
49 | brew install coreutils
50 | endif
51 | ln -nfs `which greadlink` tests/bin/readlink
52 | endif
53 |
54 | ci-dependencies: shellcheck bats readlink
55 |
56 | lint-setup:
57 | @mkdir -p tmp/test-results/shellcheck tmp/shellcheck
58 | @find . -not -path '*/\.*' -type f | xargs file | grep text | awk -F ':' '{ print $$1 }' | xargs head -n1 | egrep -B1 "bash" | grep "==>" | awk '{ print $$2 }' > tmp/shellcheck/test-files
59 | @cat tests/shellcheck-exclude | sed -n -e '/^# SC/p' | cut -d' ' -f2 | paste -d, -s - > tmp/shellcheck/exclude
60 |
61 | lint: lint-setup
62 | # these are disabled due to their expansive existence in the codebase. we should clean it up though
63 | @cat tests/shellcheck-exclude | sed -n -e '/^# SC/p'
64 | @echo linting...
65 | @cat tmp/shellcheck/test-files | xargs shellcheck -e $(shell cat tmp/shellcheck/exclude) | tests/shellcheck-to-junit --output tmp/test-results/shellcheck/results.xml --files tmp/shellcheck/test-files --exclude $(shell cat tmp/shellcheck/exclude)
66 |
67 | unit-tests:
68 | @echo running unit tests...
69 | @mkdir -p tmp/test-results/bats
70 | @cd tests && echo "executing tests: $(shell cd tests ; ls *.bats | xargs)"
71 | cd tests && bats --report-formatter junit --timing -o ../tmp/test-results/bats *.bats
72 |
73 | tmp/xunit-reader:
74 | mkdir -p tmp
75 | curl -o tmp/xunit-reader.tgz -sL https://github.com/josegonzalez/go-xunit-reader/releases/download/v$(XUNIT_READER_VERSION)/xunit-reader_$(XUNIT_READER_VERSION)_$(SYSTEM_NAME)_$(HARDWARE).tgz
76 | tar xf tmp/xunit-reader.tgz -C tmp
77 | chmod +x tmp/xunit-reader
78 |
79 | setup:
80 | bash tests/setup.sh
81 | $(MAKE) ci-dependencies
82 |
83 | test: lint unit-tests
84 |
85 | report: tmp/xunit-reader
86 | tmp/xunit-reader -p 'tmp/test-results/bats/*.xml'
87 | tmp/xunit-reader -p 'tmp/test-results/shellcheck/*.xml'
88 |
89 | .PHONY: clean
90 | clean:
91 | rm -f README.md
92 |
93 | .PHONY: generate
94 | generate: clean README.md
95 |
96 | .PHONY: README.md
97 | README.md:
98 | bin/generate
99 |
--------------------------------------------------------------------------------
/subcommands/upgrade:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 | source "$PLUGIN_AVAILABLE_PATH/ps/functions"
8 |
9 | service-upgrade-cmd() {
10 | #E you can upgrade an existing service to a new image or image-version
11 | #E dokku $PLUGIN_COMMAND_PREFIX:upgrade lollipop
12 | #A service, service to run command against
13 | #F -c|--config-options "--args --go=here", extra arguments to pass to the container create command
14 | #F -C|--custom-env "USER=alpha;HOST=beta", semi-colon delimited environment variables to start the service with
15 | #F -i|--image IMAGE, the image name to start the service with
16 | #F -I|--image-version IMAGE_VERSION, the image version to start the service with
17 | #F -N|--initial-network INITIAL_NETWORK, the initial network to attach the service to
18 | #F -P|--post-create-network NETWORKS, a comma-separated list of networks to attach the service container to after service creation
19 | #F -R|--restart-apps "true", whether or not to force an app restart (default: false)
20 | #F -S|--post-start-network NETWORKS, a comma-separated list of networks to attach the service container to after service start
21 | #F -s|--shm-size SHM_SIZE, override shared memory size for $PLUGIN_COMMAND_PREFIX docker container
22 | declare desc="upgrade service to the specified versions"
23 | local cmd="$PLUGIN_COMMAND_PREFIX:upgrade" argv=("$@")
24 | [[ ${argv[0]} == "$cmd" ]] && shift 1
25 | declare SERVICE="$1" UPGRADE_FLAGS_LIST=("${@:2}")
26 |
27 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
28 | verify_service_name "$SERVICE"
29 |
30 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
31 |
32 | service_parse_args "${@:2}"
33 |
34 | if ! service_image_exists "$SERVICE" "$PLUGIN_IMAGE" "$PLUGIN_IMAGE_VERSION"; then
35 | if [[ "$PLUGIN_DISABLE_PULL" == "true" ]]; then
36 | dokku_log_warn "${PLUGIN_DISABLE_PULL_VARIABLE} environment variable detected. Not running pull command." 1>&2
37 | dokku_log_warn " docker image pull ${IMAGE}" 1>&2
38 | dokku_log_warn "$PLUGIN_SERVICE service $SERVICE upgrade failed"
39 | exit 1
40 | fi
41 | "$DOCKER_BIN" image pull "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" || dokku_log_fail "$PLUGIN_SERVICE image $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION pull failed"
42 | fi
43 |
44 | local NEW_PLUGIN_IMAGE_TAG="$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION"
45 | if [[ "$(service_version "$SERVICE")" == "$NEW_PLUGIN_IMAGE_TAG" ]]; then
46 | dokku_log_info1 "Service $SERVICE already running $NEW_PLUGIN_IMAGE_TAG"
47 | return
48 | fi
49 |
50 | service_commit_config "$SERVICE"
51 |
52 | dokku_log_info2 "Upgrading $SERVICE to $NEW_PLUGIN_IMAGE_TAG"
53 | if [[ "$SERVICE_RESTART_APPS" == "true" ]]; then
54 | dokku_log_info2 "Stopping all linked services"
55 | for app in $(service_linked_apps "$SERVICE"); do
56 | [[ "$app" == "-" ]] && continue
57 | ps_stop "$app"
58 | done
59 | fi
60 |
61 | dokku_log_info2 "Stopping $SERVICE"
62 | service_container_rm "$SERVICE"
63 | service_start "$SERVICE" "${@:2}"
64 |
65 | if [[ "$SERVICE_RESTART_APPS" == "true" ]]; then
66 | dokku_log_info2 "Starting all linked services"
67 | for app in $(service_linked_apps "$SERVICE"); do
68 | [[ "$app" == "-" ]] && continue
69 | ps_start "$app"
70 | done
71 | fi
72 |
73 | dokku_log_info2 "Done"
74 | }
75 |
76 | service-upgrade-cmd "$@"
77 |
--------------------------------------------------------------------------------
/subcommands/link:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")/functions"
7 |
8 | service-link-cmd() {
9 | #E a $PLUGIN_COMMAND_PREFIX service can be linked to a container.
10 | #E this will use native docker links via the docker-options plugin.
11 | #E here we link it to our 'playground' app.
12 | #E > NOTE: this will restart your app
13 | #E dokku $PLUGIN_COMMAND_PREFIX:link lollipop playground
14 | #E the following environment variables will be set automatically by docker
15 | #E (not on the app itself, so they won’t be listed when calling dokku config):
16 | #E
17 | #E DOKKU_${PLUGIN_VARIABLE}_LOLLIPOP_NAME=/lollipop/DATABASE
18 | #E DOKKU_${PLUGIN_VARIABLE}_LOLLIPOP_PORT=tcp://172.17.0.1:${PLUGIN_DATASTORE_PORTS[0]}
19 | #E DOKKU_${PLUGIN_VARIABLE}_LOLLIPOP_PORT_${PLUGIN_DATASTORE_PORTS[0]}_TCP=tcp://172.17.0.1:${PLUGIN_DATASTORE_PORTS[0]}
20 | #E DOKKU_${PLUGIN_VARIABLE}_LOLLIPOP_PORT_${PLUGIN_DATASTORE_PORTS[0]}_TCP_PROTO=tcp
21 | #E DOKKU_${PLUGIN_VARIABLE}_LOLLIPOP_PORT_${PLUGIN_DATASTORE_PORTS[0]}_TCP_PORT=${PLUGIN_DATASTORE_PORTS[0]}
22 | #E DOKKU_${PLUGIN_VARIABLE}_LOLLIPOP_PORT_${PLUGIN_DATASTORE_PORTS[0]}_TCP_ADDR=172.17.0.1
23 | #E
24 | #E the following will be set on the linked application by default:
25 | #E
26 | #E ${PLUGIN_DEFAULT_ALIAS}_URL=${PLUGIN_SCHEME}://lollipop:SOME_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-lollipop:${PLUGIN_DATASTORE_PORTS[0]}/lollipop
27 | #E
28 | #E the host exposed here only works internally in docker containers.
29 | #E if you want your container to be reachable from outside, you should
30 | #E use the 'expose' subcommand. another service can be linked to your app:
31 | #E dokku $PLUGIN_COMMAND_PREFIX:link other_service playground
32 | #E it is possible to change the protocol for ${PLUGIN_DEFAULT_ALIAS}_URL by setting the
33 | #E environment variable ${PLUGIN_VARIABLE}_DATABASE_SCHEME on the app. doing so will
34 | #E after linking will cause the plugin to think the service is not
35 | #E linked, and we advise you to unlink before proceeding.
36 | #E dokku config:set playground ${PLUGIN_VARIABLE}_DATABASE_SCHEME=${PLUGIN_SCHEME}2
37 | #E dokku $PLUGIN_COMMAND_PREFIX:link lollipop playground
38 | #E this will cause ${PLUGIN_DEFAULT_ALIAS}_URL to be set as:
39 | #E
40 | #E ${PLUGIN_SCHEME}2://lollipop:SOME_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-lollipop:${PLUGIN_DATASTORE_PORTS[0]}/lollipop
41 | #E
42 | #E If you specify ${PLUGIN_VARIABLE}_DATABASE_SCHEME to equal `http`, we'll also automatically adjust ${PLUGIN_DEFAULT_ALIAS}_URL to match the http interface:
43 | #E
44 | #E http://lollipop:SOME_PASSWORD@dokku-${PLUGIN_COMMAND_PREFIX}-lollipop:${PLUGIN_DATASTORE_PORTS[1]}
45 | #A service, service to run command against
46 | #A app, app to run command against
47 | #F -a|--alias "BLUE_DATABASE", an alternative alias to use for linking to an app via environment variable
48 | #F -q|--querystring "pool=5", ampersand delimited querystring arguments to append to the service link
49 | #F -n|--no-restart "false", whether or not to restart the app on link (default: true)
50 | declare desc="link the $PLUGIN_SERVICE service to the app"
51 | local cmd="$PLUGIN_COMMAND_PREFIX:link" argv=("$@")
52 | [[ ${argv[0]} == "$cmd" ]] && shift 1
53 | declare SERVICE="$1" APP="$2" LINK_FLAGS_LIST=("${@:3}")
54 | APP=${APP:="$DOKKU_APP_NAME"}
55 |
56 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
57 | [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on"
58 | verify_app_name "$APP"
59 | verify_service_name "$SERVICE"
60 |
61 | service_parse_args "${@:3}"
62 | service_link "$SERVICE" "$APP"
63 | }
64 |
65 | service-link-cmd "$@"
66 |
--------------------------------------------------------------------------------
/tests/service_link.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" ls
6 | dokku "$PLUGIN_COMMAND_PREFIX:create" ms
7 | dokku apps:create my-app
8 | }
9 |
10 | teardown() {
11 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" ms
12 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" ls
13 | dokku --force apps:destroy my-app
14 | }
15 |
16 | @test "($PLUGIN_COMMAND_PREFIX:link) error when there are no arguments" {
17 | run dokku "$PLUGIN_COMMAND_PREFIX:link"
18 | echo "output: $output"
19 | echo "status: $status"
20 | assert_contains "${lines[*]}" "Please specify a valid name for the service"
21 | assert_failure
22 | }
23 |
24 | @test "($PLUGIN_COMMAND_PREFIX:link) error when the app argument is missing" {
25 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls
26 | echo "output: $output"
27 | echo "status: $status"
28 | assert_contains "${lines[*]}" "Please specify an app to run the command on"
29 | assert_failure
30 | }
31 |
32 | @test "($PLUGIN_COMMAND_PREFIX:link) error when the app does not exist" {
33 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls not_existing_app
34 | echo "output: $output"
35 | echo "status: $status"
36 | assert_contains "${lines[*]}" "App not_existing_app does not exist"
37 | assert_failure
38 | }
39 |
40 | @test "($PLUGIN_COMMAND_PREFIX:link) error when the service does not exist" {
41 | run dokku "$PLUGIN_COMMAND_PREFIX:link" not_existing_service my-app
42 | echo "output: $output"
43 | echo "status: $status"
44 | assert_contains "${lines[*]}" "service not_existing_service does not exist"
45 | assert_failure
46 | }
47 |
48 | @test "($PLUGIN_COMMAND_PREFIX:link) error when the service is already linked to app" {
49 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
50 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
51 | echo "output: $output"
52 | echo "status: $status"
53 | assert_contains "${lines[*]}" "Already linked as CLICKHOUSE_URL"
54 | assert_failure
55 |
56 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
57 | }
58 |
59 | @test "($PLUGIN_COMMAND_PREFIX:link) exports CLICKHOUSE_URL to app" {
60 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
61 | echo "output: $output"
62 | echo "status: $status"
63 | url=$(dokku config:get my-app CLICKHOUSE_URL)
64 | password="$(sudo cat "$PLUGIN_DATA_ROOT/ls/PASSWORD")"
65 | assert_contains "$url" "clickhouse://ls:$password@dokku-clickhouse-ls:9000/ls"
66 | assert_success
67 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
68 | }
69 |
70 | @test "($PLUGIN_COMMAND_PREFIX:link) generates an alternate config url when CLICKHOUSE_URL already in use" {
71 | dokku config:set my-app CLICKHOUSE_URL=clickhouse://user:pass@host:9000/db
72 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
73 | run dokku config my-app
74 | assert_contains "${lines[*]}" "DOKKU_CLICKHOUSE_AQUA_URL"
75 | assert_success
76 |
77 | dokku "$PLUGIN_COMMAND_PREFIX:link" ms my-app
78 | run dokku config my-app
79 | assert_contains "${lines[*]}" "DOKKU_CLICKHOUSE_BLACK_URL"
80 | assert_success
81 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ms my-app
82 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
83 | }
84 |
85 | @test "($PLUGIN_COMMAND_PREFIX:link) links to app with docker-options" {
86 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
87 | run dokku docker-options:report my-app
88 | assert_contains "${lines[*]}" "--link dokku.clickhouse.ls:dokku-clickhouse-ls"
89 | assert_success
90 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
91 | }
92 |
93 | @test "($PLUGIN_COMMAND_PREFIX:link) uses apps CLICKHOUSE_DATABASE_SCHEME variable" {
94 | dokku config:set my-app CLICKHOUSE_DATABASE_SCHEME=clickhouse2
95 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
96 | url=$(dokku config:get my-app CLICKHOUSE_URL)
97 | password="$(sudo cat "$PLUGIN_DATA_ROOT/ls/PASSWORD")"
98 | assert_contains "$url" "clickhouse2://ls:$password@dokku-clickhouse-ls:9000/ls"
99 | assert_success
100 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
101 | }
102 |
103 | @test "($PLUGIN_COMMAND_PREFIX:link) adds a querystring" {
104 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app --querystring "pool=5"
105 | url=$(dokku config:get my-app CLICKHOUSE_URL)
106 | assert_contains "$url" "?pool=5"
107 | assert_success
108 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
109 | }
110 |
111 | @test "($PLUGIN_COMMAND_PREFIX:link) uses a specified config url when alias is specified" {
112 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app --alias "ALIAS"
113 | url=$(dokku config:get my-app ALIAS_URL)
114 | password="$(sudo cat "$PLUGIN_DATA_ROOT/ls/PASSWORD")"
115 | assert_contains "$url" "clickhouse://ls:$password@dokku-clickhouse-ls:9000/ls"
116 | assert_success
117 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
118 | }
119 |
120 | @test "($PLUGIN_COMMAND_PREFIX:link) respects --no-restart" {
121 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app
122 | echo "output: $output"
123 | echo "status: $status"
124 | assert_output_contains "Skipping restart of linked app" 0
125 | assert_success
126 |
127 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
128 | echo "output: $output"
129 | echo "status: $status"
130 | assert_success
131 |
132 | run dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app --no-restart
133 | echo "output: $output"
134 | echo "status: $status"
135 | assert_output_contains "Skipping restart of linked app"
136 | assert_success
137 |
138 | run dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app
139 | echo "output: $output"
140 | echo "status: $status"
141 | assert_success
142 | }
143 |
--------------------------------------------------------------------------------
/tests/shellcheck-to-junit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | from __future__ import print_function
4 | import argparse
5 | import collections
6 | import datetime
7 | import re
8 | import socket
9 | import sys
10 |
11 | from xml.etree import ElementTree
12 |
13 |
14 | def CDATA(text=None):
15 | element = ElementTree.Element('![CDATA[')
16 | element.text = text
17 | return element
18 |
19 |
20 | def _serialize_xml(write, elem, qnames, namespaces,short_empty_elements, **kwargs):
21 |
22 | if elem.tag == '![CDATA[':
23 | write("\n<{}{}]]>\n".format(elem.tag, elem.text))
24 | if elem.tail:
25 | write(ElementTree._escape_cdata(elem.tail))
26 | else:
27 | return ElementTree._original_serialize_xml(write, elem, qnames, namespaces,short_empty_elements, **kwargs)
28 |
29 |
30 | ElementTree._original_serialize_xml = ElementTree._serialize_xml
31 | ElementTree._serialize_xml = ElementTree._serialize['xml'] = _serialize_xml
32 |
33 |
34 | def read_in():
35 | lines = sys.stdin.readlines()
36 | for i in range(len(lines)):
37 | lines[i] = lines[i].rstrip()
38 | return lines
39 |
40 |
41 | def process_lines(lines):
42 | files = {}
43 | current_file = None
44 | previous_line = None
45 | line_no = None
46 | new_issues = []
47 | code = None
48 |
49 | RE_VIOLATION = re.compile(r"\^-- (SC[\w]+): (.*)")
50 | RE_VIOLATION_NEW = re.compile(r"\^[-]+\^ (SC[\w]+): (.*)")
51 |
52 | for line in lines:
53 | # start a new block
54 | if line == '':
55 | if current_file is not None:
56 | file_data = files.get(current_file, {})
57 | files[current_file] = file_data
58 |
59 | issue_data = file_data.get(line_no, {})
60 | issue_data['code'] = code
61 | files[current_file][line_no] = issue_data
62 |
63 | issues = issue_data.get('issues', [])
64 | issues.extend(new_issues)
65 | issue_data['issues'] = issues
66 |
67 | files[current_file][line_no] = issue_data
68 |
69 | code = None
70 | current_file = None
71 | line_no = None
72 | elif line.startswith('In ./') and not previous_line:
73 | current_file = line.split(' ')[1].replace('./', '')
74 | line_no = line.split(' ')[3]
75 | new_issues = []
76 | code = None
77 | elif code is None and len(new_issues) == 0:
78 | code = line
79 | else:
80 | match = RE_VIOLATION.match(line.strip())
81 | if not match:
82 | match = RE_VIOLATION_NEW.match(line.strip())
83 |
84 | if not match:
85 | if 'https://www.shellcheck.net/wiki/SC' in line:
86 | continue
87 | if 'For more information:' == line:
88 | continue
89 | print('Error: Issue parsing line "{0}"'.format(line.strip()))
90 | else:
91 | new_issues.append({
92 | 'shellcheck_id': match.group(1),
93 | 'message': match.group(2),
94 | 'original_message': line
95 | })
96 |
97 | previous_line = line
98 |
99 | return files
100 |
101 |
102 | def output_junit(files, args):
103 | timestamp = datetime.datetime.now().replace(microsecond=0).isoformat()
104 | failures = 0
105 | for file, data in files.items():
106 | for line, issue_data in data.items():
107 | code = issue_data.get('code')
108 | for issue in issue_data.get('issues', []):
109 | failures += 1
110 |
111 | tests = 0
112 | if args.files:
113 | with open(args.files, 'r') as f:
114 | tests = len(f.readlines())
115 |
116 | root = ElementTree.Element("testsuite",
117 | name="shellcheck",
118 | tests="{0}".format(tests),
119 | failures="{0}".format(failures),
120 | errors="0",
121 | skipped="0",
122 | timestamp=timestamp,
123 | time="0",
124 | hostname=socket.gethostname())
125 |
126 | properties = ElementTree.SubElement(root, "properties")
127 | if args.exclude:
128 | ElementTree.SubElement(properties,
129 | "property",
130 | name="exclude",
131 | value=args.exclude)
132 |
133 | if args.files:
134 | with open(args.files, 'r') as f:
135 | lines = f.readlines()
136 | for i in range(len(lines)):
137 | file = lines[i].rstrip().replace('./', '')
138 | data = files.get(file, None)
139 | if data:
140 | for line, issue_data in data.items():
141 | code = issue_data.get('code')
142 | for issue in issue_data.get('issues', []):
143 | testcase = ElementTree.SubElement(root,
144 | "testcase",
145 | classname=file,
146 | name=file,
147 | time="0")
148 | shellcheck_id = issue.get('shellcheck_id')
149 | message = 'line {0}: {1}'.format(
150 | line, issue.get('message'))
151 | original_message = issue.get('original_message')
152 | e = ElementTree.Element("failure",
153 | type=shellcheck_id,
154 | message=message)
155 | cdata = CDATA("\n".join([code, original_message]))
156 | e.append(cdata)
157 | testcase.append(e)
158 | ElementTree.SubElement(root,
159 | "testcase",
160 | classname=file,
161 | name=file,
162 | time="0")
163 |
164 | ElementTree.SubElement(root, "system-out")
165 | ElementTree.SubElement(root, "system-err")
166 |
167 | content = ElementTree.tostring(root, encoding='UTF-8', method='xml')
168 | if args.output:
169 | with open(args.output, 'w') as f:
170 | try:
171 | f.write(content)
172 | except TypeError:
173 | f.write(content.decode("utf-8"))
174 |
175 |
176 | def main():
177 | parser = argparse.ArgumentParser(
178 | description='Process shellcheck output to junit.')
179 | parser.add_argument('--output',
180 | dest='output',
181 | action='store',
182 | default=None,
183 | help='file to write shellcheck output')
184 | parser.add_argument('--files',
185 | dest='files',
186 | action='store',
187 | default=None,
188 | help='a file containing a list of all files processed by shellcheck')
189 | parser.add_argument('--exclude',
190 | dest='exclude',
191 | action='store',
192 | default=None,
193 | help='a comma-separated list of rules being excluded by shellcheck')
194 | args = parser.parse_args()
195 |
196 | lines = read_in()
197 | files = process_lines(lines)
198 | files = collections.OrderedDict(sorted(files.items()))
199 | output_junit(files, args)
200 | for line in lines:
201 | print(line)
202 |
203 |
204 | if __name__ == '__main__':
205 | main()
206 |
--------------------------------------------------------------------------------
/tests/link_networks.bats:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bats
2 | load test_helper
3 |
4 | setup() {
5 | dokku "$PLUGIN_COMMAND_PREFIX:create" ls
6 | dokku network:create custom-network
7 | }
8 |
9 | teardown() {
10 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" ls || true
11 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" lsa || true
12 | dokku network:destroy --force custom-network
13 | }
14 |
15 | @test "($PLUGIN_COMMAND_PREFIX:set) set initial-network" {
16 | run dokku "$PLUGIN_COMMAND_PREFIX:set" ls initial-network custom-network
17 | echo "output: $output"
18 | echo "status: $status"
19 | assert_success
20 |
21 | run dokku "$PLUGIN_COMMAND_PREFIX:info" ls --initial-network
22 | echo "output: $output"
23 | echo "status: $status"
24 | assert_output "custom-network"
25 | assert_success
26 |
27 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
28 | echo "output: $output"
29 | echo "status: $status"
30 | assert_success
31 | assert_output_contains bridge
32 | assert_output_contains custom-network 0
33 |
34 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" ls
35 | echo "output: $output"
36 | echo "status: $status"
37 | assert_success
38 |
39 | run dokku "$PLUGIN_COMMAND_PREFIX:start" ls
40 | echo "output: $output"
41 | echo "status: $status"
42 | assert_success
43 |
44 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
45 | echo "output: $output"
46 | echo "status: $status"
47 | assert_success
48 | assert_output_contains bridge 0
49 | assert_output_contains custom-network
50 |
51 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{range $k,$alias := $v.DNSNames}}{{printf "alias:%s\n" $alias}}{{end}}{{end}}'
52 | echo "output: $output"
53 | echo "status: $status"
54 | assert_success
55 | assert_output_contains "alias:dokku.$PLUGIN_COMMAND_PREFIX.ls"
56 | assert_output_contains "alias:dokku-$PLUGIN_COMMAND_PREFIX-ls"
57 |
58 | run dokku "$PLUGIN_COMMAND_PREFIX:set" ls initial-network
59 | echo "output: $output"
60 | echo "status: $status"
61 | assert_success
62 |
63 | run dokku "$PLUGIN_COMMAND_PREFIX:info" ls --initial-network
64 | echo "output: $output"
65 | echo "status: $status"
66 | assert_output ""
67 | assert_success
68 |
69 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" ls
70 | echo "output: $output"
71 | echo "status: $status"
72 | assert_success
73 |
74 | run dokku "$PLUGIN_COMMAND_PREFIX:start" ls
75 | echo "output: $output"
76 | echo "status: $status"
77 | assert_success
78 |
79 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
80 | echo "output: $output"
81 | echo "status: $status"
82 | assert_success
83 | assert_output_contains bridge
84 | assert_output_contains custom-network 0
85 | }
86 |
87 | @test "($PLUGIN_COMMAND_PREFIX:set) set post-create-network" {
88 | run dokku "$PLUGIN_COMMAND_PREFIX:set" ls post-create-network custom-network
89 | echo "output: $output"
90 | echo "status: $status"
91 | assert_success
92 |
93 | run dokku "$PLUGIN_COMMAND_PREFIX:info" ls --post-create-network
94 | echo "output: $output"
95 | echo "status: $status"
96 | assert_output "custom-network"
97 | assert_success
98 |
99 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
100 | echo "output: $output"
101 | echo "status: $status"
102 | assert_success
103 | assert_output_contains bridge
104 | assert_output_contains custom-network 0
105 |
106 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" ls
107 | echo "output: $output"
108 | echo "status: $status"
109 | assert_success
110 |
111 | run dokku "$PLUGIN_COMMAND_PREFIX:start" ls
112 | echo "output: $output"
113 | echo "status: $status"
114 | assert_success
115 |
116 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
117 | echo "output: $output"
118 | echo "status: $status"
119 | assert_success
120 | assert_output_contains custom-network
121 | assert_output_contains bridge
122 |
123 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{range $k,$alias := $v.DNSNames}}{{printf "alias:%s\n" $alias}}{{end}}{{end}}'
124 | echo "output: $output"
125 | echo "status: $status"
126 | assert_success
127 | assert_output_contains "alias:dokku.$PLUGIN_COMMAND_PREFIX.ls"
128 | assert_output_contains "alias:dokku-$PLUGIN_COMMAND_PREFIX-ls"
129 |
130 | run dokku "$PLUGIN_COMMAND_PREFIX:set" ls post-create-network
131 | echo "output: $output"
132 | echo "status: $status"
133 | assert_success
134 |
135 | run dokku "$PLUGIN_COMMAND_PREFIX:info" ls --post-create-network
136 | echo "output: $output"
137 | echo "status: $status"
138 | assert_output ""
139 | assert_success
140 |
141 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" ls
142 | echo "output: $output"
143 | echo "status: $status"
144 | assert_success
145 |
146 | run dokku "$PLUGIN_COMMAND_PREFIX:start" ls
147 | echo "output: $output"
148 | echo "status: $status"
149 | assert_success
150 |
151 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
152 | echo "output: $output"
153 | echo "status: $status"
154 | assert_success
155 | assert_output_contains bridge
156 | assert_output_contains custom-network 0
157 | }
158 |
159 | @test "($PLUGIN_COMMAND_PREFIX:set) set an post-start-network" {
160 | run dokku "$PLUGIN_COMMAND_PREFIX:set" ls post-start-network custom-network
161 | echo "output: $output"
162 | echo "status: $status"
163 | assert_success
164 |
165 | run dokku "$PLUGIN_COMMAND_PREFIX:info" ls --post-start-network
166 | echo "output: $output"
167 | echo "status: $status"
168 | assert_output "custom-network"
169 | assert_success
170 |
171 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
172 | echo "output: $output"
173 | echo "status: $status"
174 | assert_success
175 | assert_output_contains bridge
176 | assert_output_contains custom-network 0
177 |
178 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" ls
179 | echo "output: $output"
180 | echo "status: $status"
181 | assert_success
182 |
183 | run dokku "$PLUGIN_COMMAND_PREFIX:start" ls
184 | echo "output: $output"
185 | echo "status: $status"
186 | assert_success
187 |
188 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
189 | echo "output: $output"
190 | echo "status: $status"
191 | assert_success
192 | assert_output_contains bridge
193 | assert_output_contains custom-network
194 |
195 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{range $k,$alias := $v.DNSNames}}{{printf "alias:%s\n" $alias}}{{end}}{{end}}'
196 | echo "output: $output"
197 | echo "status: $status"
198 | assert_success
199 | assert_output_contains "alias:dokku.$PLUGIN_COMMAND_PREFIX.ls"
200 | assert_output_contains "alias:dokku-$PLUGIN_COMMAND_PREFIX-ls"
201 |
202 | run dokku "$PLUGIN_COMMAND_PREFIX:set" ls post-start-network
203 | echo "output: $output"
204 | echo "status: $status"
205 | assert_success
206 |
207 | run dokku "$PLUGIN_COMMAND_PREFIX:info" ls --post-start-network
208 | echo "output: $output"
209 | echo "status: $status"
210 | assert_output ""
211 | assert_success
212 |
213 | run dokku "$PLUGIN_COMMAND_PREFIX:stop" ls
214 | echo "output: $output"
215 | echo "status: $status"
216 | assert_success
217 |
218 | run dokku "$PLUGIN_COMMAND_PREFIX:start" ls
219 | echo "output: $output"
220 | echo "status: $status"
221 | assert_success
222 |
223 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.ls -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
224 | echo "output: $output"
225 | echo "status: $status"
226 | assert_success
227 | assert_output_contains bridge
228 | assert_output_contains custom-network 0
229 | }
230 |
231 | @test "($PLUGIN_COMMAND_PREFIX:create) flags" {
232 | run dokku "$PLUGIN_COMMAND_PREFIX:create" lsa --initial-network custom-network
233 | echo "output: $output"
234 | echo "status: $status"
235 | assert_success
236 |
237 | run docker inspect "dokku.$PLUGIN_COMMAND_PREFIX.lsa" -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
238 | echo "output: $output"
239 | echo "status: $status"
240 | assert_success
241 | assert_output_contains bridge 0
242 | assert_output_contains custom-network
243 |
244 | run dokku "$PLUGIN_COMMAND_PREFIX:destroy" lsa --force
245 | echo "output: $output"
246 | echo "status: $status"
247 | assert_success
248 |
249 | run dokku "$PLUGIN_COMMAND_PREFIX:create" lsa --post-create-network custom-network
250 | echo "output: $output"
251 | echo "status: $status"
252 | assert_success
253 |
254 | run docker inspect "dokku.$PLUGIN_COMMAND_PREFIX.lsa" -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
255 | echo "output: $output"
256 | echo "status: $status"
257 | assert_success
258 | assert_output_contains bridge
259 | assert_output_contains custom-network
260 |
261 | run docker inspect dokku.$PLUGIN_COMMAND_PREFIX.lsa -f '{{range $net,$v := .NetworkSettings.Networks}}{{range $k,$alias := $v.DNSNames}}{{printf "alias:%s\n" $alias}}{{end}}{{end}}'
262 | echo "output: $output"
263 | echo "status: $status"
264 | assert_success
265 | assert_output_contains "alias:dokku.$PLUGIN_COMMAND_PREFIX.lsa"
266 | assert_output_contains "alias:dokku-$PLUGIN_COMMAND_PREFIX-lsa"
267 |
268 | run dokku "$PLUGIN_COMMAND_PREFIX:destroy" lsa --force
269 | echo "output: $output"
270 | echo "status: $status"
271 | assert_success
272 |
273 | run dokku "$PLUGIN_COMMAND_PREFIX:create" lsa --post-start-network custom-network
274 | echo "output: $output"
275 | echo "status: $status"
276 | assert_success
277 |
278 | run docker inspect "dokku.$PLUGIN_COMMAND_PREFIX.lsa" -f '{{range $net,$v := .NetworkSettings.Networks}}{{printf "%s\n" $net}}{{end}}'
279 | echo "output: $output"
280 | echo "status: $status"
281 | assert_success
282 | assert_output_contains bridge
283 | assert_output_contains custom-network
284 |
285 | run dokku "$PLUGIN_COMMAND_PREFIX:destroy" lsa --force
286 | echo "output: $output"
287 | echo "status: $status"
288 | assert_success
289 | }
290 |
--------------------------------------------------------------------------------
/help-functions:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
6 | export SUBCOMMAND_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/subcommands"
7 |
8 | fn-help() {
9 | declare CMD="$1"
10 | local cmd EXIT_CODE
11 |
12 | if [[ "$CMD" == "help" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:help" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:default" ]]; then
13 | fn-help-all "$@"
14 | exit 0
15 | fi
16 |
17 | pushd "$SUBCOMMAND_ROOT" >/dev/null 2>&1
18 | for cmd in *; do
19 | if [[ "$CMD" == "${PLUGIN_COMMAND_PREFIX}:$cmd" ]]; then
20 | "$SUBCOMMAND_ROOT/$cmd" "$@"
21 | EXIT_CODE="$?"
22 | exit "$EXIT_CODE"
23 | fi
24 | done
25 | popd >/dev/null 2>&1
26 |
27 | exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
28 | }
29 |
30 | fn-help-all() {
31 | declare CMD="$1" SUBCOMMAND="$2"
32 | local CMD_OUTPUT BLUE BOLD FULL_OUTPUT NORMAL
33 | FULL_OUTPUT=true
34 |
35 | if [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:help" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:default" ]]; then
36 | BOLD="$(fn-help-fancy-tput bold)"
37 | NORMAL="$(fn-help-fancy-color "\033[m")"
38 | BLUE="$(fn-help-fancy-color "\033[0;34m")"
39 | CYAN="$(fn-help-fancy-color "\033[1;36m")"
40 | if [[ -n "$SUBCOMMAND" ]] && [[ "$SUBCOMMAND" != "--all" ]]; then
41 | fn-help-contents-subcommand "$SUBCOMMAND" "$FULL_OUTPUT"
42 | return "$?"
43 | fi
44 |
45 | echo -e "${BOLD}usage${NORMAL}: dokku ${PLUGIN_COMMAND_PREFIX}[:COMMAND]"
46 | echo ''
47 | echo -e "${BOLD}List your $PLUGIN_COMMAND_PREFIX services.${NORMAL}"
48 | echo ''
49 | echo -e "${BLUE}Example:${NORMAL}"
50 | echo ''
51 | echo " \$ dokku $PLUGIN_COMMAND_PREFIX:list"
52 | echo ''
53 | fn-help-list-example | column -c5 -t -s,
54 | echo ''
55 | echo -e "dokku ${BOLD}${PLUGIN_COMMAND_PREFIX}${NORMAL} commands: (get help with ${CYAN}dokku ${PLUGIN_COMMAND_PREFIX}:help SUBCOMMAND${NORMAL})"
56 | echo ''
57 | fn-help-contents | sort | column -c2 -t -s,
58 | echo ''
59 | elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then
60 | fn-help-contents
61 | else
62 | cat </dev/null 2>&1
72 | for cmd in *; do
73 | fn-help-contents-subcommand "$cmd" || true
74 | done
75 | }
76 |
77 | fn-help-contents-subcommand() {
78 | declare SUBCOMMAND="$1" FULL_OUTPUT="$2"
79 | local HELP_TMPDIR=$(mktemp -d --tmpdir)
80 | local UNCLEAN_FILE="${HELP_TMPDIR}/cmd-unclean" CLEAN_FILE="${HELP_TMPDIR}/cmd-clean"
81 | local BOLD CMD_OUTPUT CYAN EXAMPLE LIGHT_GRAY NORMAL
82 | trap 'rm -rf "$HELP_TMPDIR" > /dev/null' RETURN INT TERM EXIT
83 |
84 | rm -rf "$UNCLEAN_FILE" "$CLEAN_FILE"
85 | cat "$SUBCOMMAND_ROOT/$SUBCOMMAND" >"$UNCLEAN_FILE"
86 |
87 | fn-help-subcommand-sanitize "$UNCLEAN_FILE" "$CLEAN_FILE"
88 | if ! is_implemented_command "$SUBCOMMAND"; then
89 | return 1
90 | fi
91 |
92 | args="$(fn-help-subcommand-args "$CLEAN_FILE" "$FULL_OUTPUT")"
93 | SUBCOMMAND=":$SUBCOMMAND"
94 | [[ "$SUBCOMMAND" == ":default" ]] && SUBCOMMAND=""
95 | cmd_line="$(echo -e "${SUBCOMMAND} ${args}" | sed -e 's/[[:space:]]*$//')"
96 | desc="$(grep desc "$CLEAN_FILE" | head -1)"
97 | eval "$desc"
98 |
99 | BLUE="$(fn-help-fancy-color "\033[0;34m")"
100 | BOLD="$(fn-help-fancy-tput bold)"
101 | CYAN="$(fn-help-fancy-color "\033[1;36m")"
102 | NORMAL="$(fn-help-fancy-color "\033[m")"
103 | LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"
104 | LIGHT_RED="$(fn-help-fancy-color "\033[1;31m")"
105 | CMD_OUTPUT="$(echo -e " ${PLUGIN_COMMAND_PREFIX}${cmd_line}, ${LIGHT_GRAY}${desc}${NORMAL}")"
106 | if [[ "$FULL_OUTPUT" != "true" ]]; then
107 | echo "$CMD_OUTPUT"
108 | return 0
109 | fi
110 |
111 | echo -e "${BOLD}usage:${NORMAL} dokku ${PLUGIN_COMMAND_PREFIX}${cmd_line}"
112 | echo ''
113 | echo -e "${BOLD}${desc}${NORMAL}"
114 | echo ''
115 |
116 | ARGS="$(fn-help-subcommand-list-args "$CLEAN_FILE")"
117 | if [[ -n "$ARGS" ]]; then
118 | echo -e "${CYAN}arguments:${NORMAL}"
119 | echo ''
120 | echo "$ARGS" | column -c2 -t -s,
121 | echo ''
122 | fi
123 |
124 | FLAGS="$(fn-help-subcommand-list-flags "$CLEAN_FILE")"
125 | if [[ -n "$FLAGS" ]]; then
126 | echo -e "${BLUE}flags:${NORMAL}"
127 | echo ''
128 | echo "$FLAGS" | column -c2 -t -s,
129 | echo ''
130 | fi
131 |
132 | EXAMPLE="$(fn-help-subcommand-example "$CLEAN_FILE")"
133 | if [[ -n "$EXAMPLE" ]]; then
134 | echo -e "${LIGHT_RED}examples:${NORMAL}"
135 | echo ''
136 | echo "$EXAMPLE"
137 | echo ''
138 | fi
139 |
140 | return 0
141 | }
142 |
143 | fn-help-fancy-tput() {
144 | declare desc="a wrapper around tput"
145 |
146 | if [[ -n "$DOKKU_NO_COLOR" ]] || [[ "$TERM" == "unknown" ]] || [[ "$TERM" == "dumb" ]]; then
147 | return
148 | fi
149 |
150 | tput "$@"
151 | }
152 |
153 | fn-help-fancy-color() {
154 | declare desc="a wrapper around colors"
155 |
156 | if [[ -n "$DOKKU_NO_COLOR" ]] || [[ "$TERM" == "unknown" ]] || [[ "$TERM" == "dumb" ]]; then
157 | return
158 | fi
159 |
160 | echo "$@"
161 | }
162 |
163 | fn-help-list-example() {
164 | # shellcheck disable=SC2034
165 | declare desc="return $PLUGIN_COMMAND_PREFIX plugin help content"
166 | cat <"
205 | elif [[ "$arg" == *_OPTIONAL ]]; then
206 | argName="${arg/_OPTIONAL/}"
207 | args+=" [<${argName//_/-}>]"
208 | else
209 | args+=" <${arg//_/-}>"
210 | fi
211 | done
212 | args=$(echo "$args" | tr "\n" " ")
213 | # shellcheck disable=SC2001
214 | echo "${args,,}" | sed -e 's/^[[:space:]]*//'
215 | }
216 |
217 | fn-help-subcommand-example() {
218 | declare FUNC_FILE="$1"
219 | local EXAMPLE
220 |
221 | EXAMPLE=$(grep "#E" "$FUNC_FILE" | cut -d' ' -f2- || true)
222 | if [[ -z "$EXAMPLE" ]]; then
223 | return 0
224 | fi
225 |
226 | BOLD="$(fn-help-fancy-tput bold)"
227 | LAST_LINE=""
228 | LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"
229 | OTHER_GRAY="$(fn-help-fancy-color "\033[7;37m")"
230 | NEWLINE=""
231 | NORMAL="$(fn-help-fancy-color "\033[m")"
232 | _fn-help-apply-shell-expansion "$EXAMPLE" | while read -r line; do
233 | line="$(echo "$line" | cut -c 4-)"
234 | if [[ "$line" == export* ]] || [[ "$line" == dokku* ]]; then
235 | [[ "$LAST_LINE" == "command" ]] && NEWLINE=""
236 | [[ "$LAST_LINE" == "sentence" ]] && NEWLINE="\n"
237 | echo -e "${NEWLINE} ${LIGHT_GRAY}${line}${NORMAL}"
238 | LAST_LINE="command"
239 | else
240 | [[ "$LAST_LINE" == "command" ]] && NEWLINE="\n"
241 | [[ "$LAST_LINE" == "sentence" ]] && NEWLINE=""
242 | [[ "$line" == \>* ]] && line="\n ${BOLD}${line}${NORMAL}"
243 | # shellcheck disable=SC2001
244 | [[ "$line" == " "* ]] && line=" ${OTHER_GRAY}$(echo "$line" | sed -e 's/^[[:space:]]*//')${NORMAL}"
245 | echo -e "${NEWLINE}${line}"
246 | LAST_LINE="sentence"
247 | NEWLINE="\n"
248 | fi
249 | done
250 | }
251 |
252 | fn-help-subcommand-list-args() {
253 | declare FUNC_FILE="$1"
254 | local EXAMPLE LIGHT_GRAY NORMAL
255 |
256 | FLAGS=$(grep "#A" "$FUNC_FILE" | cut -d'A' -f2- | sed -e 's/^[[:space:]]*//' || true)
257 | if [[ -z "$FLAGS" ]]; then
258 | return 0
259 | fi
260 |
261 | NORMAL="$(fn-help-fancy-color "\033[m")"
262 | LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"
263 |
264 | _fn-help-apply-shell-expansion "$FLAGS" | while read -r line; do
265 | echo -e "$(echo "$line" | cut -d',' -f1),${LIGHT_GRAY}$(echo "$line" | cut -d',' -f2-)${NORMAL}"
266 | done
267 | }
268 |
269 | fn-help-subcommand-list-flags() {
270 | declare FUNC_FILE="$1"
271 | local EXAMPLE LIGHT_GRAY NORMAL
272 |
273 | FLAGS=$(grep "#F" "$FUNC_FILE" | cut -d'F' -f2- | sed -e 's/^[[:space:]]*//' || true)
274 | if [[ -z "$FLAGS" ]]; then
275 | return 0
276 | fi
277 |
278 | NORMAL="$(fn-help-fancy-color "\033[m")"
279 | LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"
280 |
281 | _fn-help-apply-shell-expansion "$FLAGS" | while read -r line; do
282 | echo -e "$(echo "$line" | cut -d',' -f1),${LIGHT_GRAY}$(echo "$line" | cut -d',' -f2-)${NORMAL}"
283 | done
284 | }
285 |
286 | fn-help-subcommand-sanitize() {
287 | declare FUNC_FILE="$1" OUTGOING_FUNC_FILE="$2"
288 | local FUNCTION_FOUND=false
289 | local IFS OIFS
290 |
291 | touch "$OUTGOING_FUNC_FILE"
292 |
293 | OIFS="$IFS"
294 | IFS=,
295 | while read -r p; do
296 | IFS="$OIFS"
297 | if [[ "$p" == *"-cmd \"\$@\""* ]] || [[ "$p" == "" ]]; then
298 | continue
299 | fi
300 |
301 | if [[ "$FUNCTION_FOUND" == true ]]; then
302 | echo "$p" >>"$OUTGOING_FUNC_FILE"
303 | continue
304 | fi
305 |
306 | if [[ "$p" == *"()"* ]]; then
307 | FUNCTION_FOUND=true
308 | echo "$p" >>"$OUTGOING_FUNC_FILE"
309 | continue
310 | fi
311 | done <"$FUNC_FILE"
312 | }
313 |
314 | _fn-help-apply-shell-expansion() {
315 | declare desc="expand environment variables for a shell command"
316 | declare data="$1"
317 | declare delimiter="__apply_shell_expansion_delimiter__"
318 | declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter"
319 | eval "$command"
320 | }
321 |
--------------------------------------------------------------------------------
/functions:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
3 | set -eo pipefail
4 | [[ $DOKKU_TRACE ]] && set -x
5 | source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
6 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
7 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
8 | source "$PLUGIN_AVAILABLE_PATH/config/functions"
9 | if [[ -f "$PLUGIN_AVAILABLE_PATH/docker-options/functions" ]]; then
10 | source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
11 | fi
12 |
13 | service_connect() {
14 | local SERVICE="$1"
15 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
16 | local SERVICE_NAME="$(get_service_name "$SERVICE")"
17 | local PASSWORD="$(service_password "$SERVICE")"
18 | local SERVICE_TTY_OPTS
19 | has_tty && SERVICE_TTY_OPTS="-t"
20 |
21 | "$DOCKER_BIN" container exec --env=LANG=C.UTF-8 --env=LC_ALL=C.UTF-8 -i $SERVICE_TTY_OPTS "$SERVICE_NAME" clickhouse client --user="$SERVICE" --password="$PASSWORD"
22 | }
23 |
24 | service_create() {
25 | local SERVICE="$1"
26 | is_valid_service_name "$SERVICE" || dokku_log_fail "Please specify a valid name for the service. Valid characters are: [A-Za-z0-9_]+"
27 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service"
28 | [[ ! -d "$PLUGIN_DATA_ROOT/$SERVICE" ]] || dokku_log_fail "$PLUGIN_SERVICE service $SERVICE already exists"
29 | SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
30 | LINKS_FILE="$SERVICE_ROOT/LINKS"
31 |
32 | service_parse_args "${@:2}"
33 |
34 | if ! service_image_exists "$SERVICE"; then
35 | if [[ "$PLUGIN_DISABLE_PULL" == "true" ]]; then
36 | dokku_log_warn "${PLUGIN_DISABLE_PULL_VARIABLE} environment variable detected. Not running pull command." 1>&2
37 | dokku_log_warn " docker image pull ${IMAGE}" 1>&2
38 | dokku_log_warn "$PLUGIN_SERVICE service creation failed"
39 | exit 1
40 | fi
41 | "$DOCKER_BIN" image pull "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" || dokku_log_fail "$PLUGIN_SERVICE image $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION pull failed"
42 | fi
43 |
44 | plugn trigger service-action pre-create "$PLUGIN_COMMAND_PREFIX" "$SERVICE"
45 | mkdir -p "$SERVICE_ROOT" || dokku_log_fail "Unable to create service directory"
46 | mkdir -p "$SERVICE_ROOT/data" || dokku_log_fail "Unable to create service data directory"
47 | mkdir -p "$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX" || dokku_log_fail "Unable to create service config directory"
48 | mkdir -p "$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/config.d/" || dokku_log_fail "Unable to create config.d directory"
49 | mkdir -p "$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/users.d/" || dokku_log_fail "Unable to create users.d directory"
50 | touch "$LINKS_FILE"
51 |
52 | "$DOCKER_BIN" run --rm --entrypoint cat "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" /etc/clickhouse-server/config.xml >"$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/config.xml" || dokku_log_fail "Unable to get the default config.xml from the image to the config directory"
53 | "$DOCKER_BIN" run --rm --entrypoint cat "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" /etc/clickhouse-server/config.d/docker_related_config.xml >"$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/config.d/docker_related_config.xml" || dokku_log_fail "Unable to get the extra docker config (docker_related_config.xml) from the image to the config directory"
54 | "$DOCKER_BIN" run --rm --entrypoint cat "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" /etc/clickhouse-server/users.xml >"$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/users.xml" || dokku_log_fail "Unable to get the default users.xml from the image to the config directory"
55 |
56 | cp "/var/lib/dokku/plugins/available/$PLUGIN_COMMAND_PREFIX/system_log_ttl_config.xml" "$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/config.d/system_log_ttl_config.xml" || dokku_log_fail "Unable to copy the default system log TTL config (system_log_ttl_config.xml) to the config directory"
57 | cp "/var/lib/dokku/plugins/available/$PLUGIN_COMMAND_PREFIX/logger_log_to_console.xml" "$SERVICE_ROOT/$PLUGIN_CONFIG_SUFFIX/config.d/logger_log_to_console.xml" || dokku_log_fail "Unable to copy the default console logger config (logger_log_to_console.xml) to the config directory"
58 |
59 | PASSWORD=$(openssl rand -hex 8)
60 | if [[ -n "$SERVICE_PASSWORD" ]]; then
61 | PASSWORD="$SERVICE_PASSWORD"
62 | dokku_log_warn "Specified password may not be as secure as the auto-generated password"
63 | fi
64 |
65 | echo "$PASSWORD" >"$SERVICE_ROOT/PASSWORD"
66 | chmod 640 "$SERVICE_ROOT/PASSWORD"
67 |
68 | service_commit_config "$SERVICE"
69 | write_database_name "$SERVICE"
70 | plugn trigger service-action post-create "$PLUGIN_COMMAND_PREFIX" "$SERVICE"
71 | service_create_container "$SERVICE"
72 | plugn trigger service-action post-create-complete "$PLUGIN_COMMAND_PREFIX" "$SERVICE"
73 | }
74 |
75 | service_create_container() {
76 | local SERVICE="$1"
77 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
78 | local SERVICE_HOST_ROOT="$PLUGIN_DATA_HOST_ROOT/$SERVICE"
79 | local SERVICE_NAME="$(get_service_name "$SERVICE")"
80 | local PASSWORD="$(service_password "$SERVICE")"
81 | local DATABASE_NAME="$(get_database_name "$SERVICE")"
82 |
83 | if [[ -f "$SERVICE_ROOT/CONFIG_OPTIONS" ]]; then
84 | export CONFIG_OPTIONS="$(cat "$SERVICE_ROOT/CONFIG_OPTIONS")"
85 | fi
86 |
87 | local network_alias="$(service_dns_hostname "$SERVICE")"
88 |
89 | rm -f "$SERVICE_ROOT/ID"
90 | declare -a DOCKER_ARGS
91 | DOCKER_ARGS=()
92 | DOCKER_ARGS+=("--cidfile=$SERVICE_ROOT/ID")
93 | DOCKER_ARGS+=("--env-file=$SERVICE_ROOT/ENV")
94 | DOCKER_ARGS+=("--env=CLICKHOUSE_DB=$DATABASE_NAME")
95 | DOCKER_ARGS+=("--env=CLICKHOUSE_PASSWORD=$PASSWORD")
96 | DOCKER_ARGS+=("--env=CLICKHOUSE_USER=$SERVICE")
97 | DOCKER_ARGS+=("--hostname=$SERVICE_NAME")
98 | DOCKER_ARGS+=("--label=dokku.service=$PLUGIN_COMMAND_PREFIX")
99 | DOCKER_ARGS+=("--label=dokku=service")
100 | DOCKER_ARGS+=("--name=$SERVICE_NAME")
101 | DOCKER_ARGS+=("--restart=always")
102 | DOCKER_ARGS+=("--volume=$SERVICE_HOST_ROOT/$PLUGIN_CONFIG_SUFFIX:/etc/clickhouse-server/")
103 | DOCKER_ARGS+=("--volume=$SERVICE_HOST_ROOT/data:/var/lib/clickhouse")
104 |
105 | declare -a LINK_CONTAINER_DOCKER_ARGS
106 | LINK_CONTAINER_DOCKER_ARGS=()
107 | LINK_CONTAINER_DOCKER_ARGS+=("--rm")
108 | LINK_CONTAINER_DOCKER_ARGS+=("--link")
109 | LINK_CONTAINER_DOCKER_ARGS+=("$SERVICE_NAME:$network_alias")
110 |
111 | [[ -f "$SERVICE_ROOT/SERVICE_MEMORY" ]] && SERVICE_MEMORY="$(cat "$SERVICE_ROOT/SERVICE_MEMORY")"
112 | if [[ -n "$SERVICE_MEMORY" ]]; then
113 | DOCKER_ARGS+=("--memory=${SERVICE_MEMORY}m")
114 | fi
115 |
116 | [[ -f "$SERVICE_ROOT/SHM_SIZE" ]] && SERVICE_SHM_SIZE="$(cat "$SERVICE_ROOT/SHM_SIZE")"
117 | if [[ -n "$SERVICE_SHM_SIZE" ]]; then
118 | DOCKER_ARGS+=("--shm-size=${SERVICE_SHM_SIZE}")
119 | fi
120 |
121 | [[ -f "$SERVICE_ROOT/IMAGE" ]] && PLUGIN_IMAGE="$(cat "$SERVICE_ROOT/IMAGE")"
122 | [[ -f "$SERVICE_ROOT/IMAGE_VERSION" ]] && PLUGIN_IMAGE_VERSION="$(cat "$SERVICE_ROOT/IMAGE_VERSION")"
123 |
124 | local network="$(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "initial-network")"
125 | if [[ -n "$network" ]]; then
126 | DOCKER_ARGS+=("--network=${network}")
127 | DOCKER_ARGS+=("--network-alias=${network_alias}")
128 | LINK_CONTAINER_DOCKER_ARGS+=("--network=${network}")
129 | fi
130 |
131 | # shellcheck disable=SC2086
132 | suppress_output "$DOCKER_BIN" container create "${DOCKER_ARGS[@]}" "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" $CONFIG_OPTIONS
133 |
134 | if [[ -n "$(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-create-network")" ]]; then
135 | dokku_log_verbose_quiet "Connecting to networks after container create"
136 | while read -r line || [[ -n "$line" ]]; do
137 | dokku_log_verbose_quiet "- $line"
138 | "$DOCKER_BIN" network connect --alias "$network_alias" "$line" "$SERVICE_NAME"
139 | done < <(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-create-network" | tr "," "\n")
140 | fi
141 | suppress_output "$DOCKER_BIN" container start "$(cat "$SERVICE_ROOT/ID")"
142 | service_port_reconcile_status "$SERVICE"
143 |
144 | if [[ -n "$(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-start-network")" ]]; then
145 | dokku_log_verbose_quiet "Connecting to networks after container start"
146 | while read -r line || [[ -n "$line" ]]; do
147 | dokku_log_verbose_quiet "- $line"
148 | "$DOCKER_BIN" network connect --alias "$network_alias" "$line" "$SERVICE_NAME"
149 | done < <(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-start-network" | tr "," "\n")
150 | fi
151 |
152 | dokku_log_verbose_quiet "Waiting for container to be ready"
153 | if ! suppress_output "$DOCKER_BIN" container run "${LINK_CONTAINER_DOCKER_ARGS[@]}" "$PLUGIN_WAIT_IMAGE" -c "$network_alias:$PLUGIN_DATASTORE_WAIT_PORT"; then
154 | dokku_log_info2_quiet "Start of $SERVICE container output"
155 | dokku_container_log_verbose_quiet "$SERVICE_NAME"
156 | dokku_log_info2_quiet "End of $SERVICE container output"
157 | return 1
158 | fi
159 |
160 | dokku_log_info2 "$PLUGIN_SERVICE container created: $SERVICE"
161 | service_info "$SERVICE"
162 | }
163 |
164 | service_export() {
165 | local SERVICE="$1"
166 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
167 |
168 | dokku_log_fail "Not yet implemented"
169 | }
170 |
171 | service_import() {
172 | local SERVICE="$1"
173 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
174 | local SERVICE_HOST_ROOT="$PLUGIN_DATA_HOST_ROOT/$SERVICE"
175 | local SERVICE_NAME="$(get_service_name "$SERVICE")"
176 |
177 | dokku_log_fail "Not yet implemented"
178 | }
179 |
180 | service_start() {
181 | local SERVICE="$1"
182 | local QUIET="$2"
183 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE"
184 | local SERVICE_NAME="$(get_service_name "$SERVICE")"
185 | local ID=$("$DOCKER_BIN" container ps -aq --no-trunc --filter "status=running" --filter "name=^/$SERVICE_NAME$") || true
186 | if [[ -n $ID ]]; then
187 | [[ -z $QUIET ]] && dokku_log_warn "Service is already started"
188 | if [[ ! -f "$SERVICE_ROOT/ID" ]] || [[ "$(cat "$SERVICE_ROOT/ID")" != "$ID" ]]; then
189 | [[ -z $QUIET ]] && dokku_log_warn "Updating local container ID"
190 | echo "$ID" >"$SERVICE_ROOT/ID"
191 | fi
192 | return 0
193 | fi
194 |
195 | dokku_log_info2_quiet "Starting container"
196 | local PREVIOUS_ID=$("$DOCKER_BIN" container ps -aq --no-trunc --filter "status=exited" --filter "name=^/$SERVICE_NAME$") || true
197 | local PASSWORD="$(service_password "$SERVICE")"
198 |
199 | if [[ -n $PREVIOUS_ID ]]; then
200 | "$DOCKER_BIN" container start "$PREVIOUS_ID" >/dev/null
201 | service_port_reconcile_status "$SERVICE"
202 | dokku_log_info2 "Container started"
203 | elif service_image_exists "$SERVICE" && [[ -n "$PASSWORD" ]]; then
204 | service_create_container "$SERVICE"
205 | else
206 | if ! service_image_exists "$SERVICE"; then
207 | [[ -f "$SERVICE_ROOT/IMAGE" ]] && PLUGIN_IMAGE="$(cat "$SERVICE_ROOT/IMAGE")"
208 | [[ -f "$SERVICE_ROOT/IMAGE_VERSION" ]] && PLUGIN_IMAGE_VERSION="$(cat "$SERVICE_ROOT/IMAGE_VERSION")"
209 | dokku_log_verbose_quiet "Missing image $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION for $SERVICE"
210 | else
211 | dokku_log_verbose_quiet "Neither container nor valid configuration exists for $SERVICE"
212 | fi
213 | fi
214 | }
215 |
216 | service_url() {
217 | local SERVICE="$1"
218 | local SERVICE_DNS_HOSTNAME="$(service_dns_hostname "$SERVICE")"
219 | local DATABASE_NAME="$(get_database_name "$SERVICE")"
220 | local PASSWORD="$(service_password "$SERVICE")"
221 |
222 | if [[ $PLUGIN_SCHEME == "http" ]]; then
223 | echo "http://$SERVICE:$PASSWORD@$SERVICE_DNS_HOSTNAME:${PLUGIN_DATASTORE_PORTS[1]}"
224 | else
225 | echo "$PLUGIN_SCHEME://$SERVICE:$PASSWORD@$SERVICE_DNS_HOSTNAME:${PLUGIN_DATASTORE_PORTS[0]}/$DATABASE_NAME"
226 | fi
227 | }
228 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dokku clickhouse [](https://github.com/dokku/dokku-clickhouse/actions/workflows/ci.yml?query=branch%3Amaster) [](https://webchat.libera.chat/?channels=dokku)
2 |
3 | Official clickhouse plugin for dokku. Currently defaults to installing [clickhouse/clickhouse-server 25.12.1.649](https://hub.docker.com/r/clickhouse/clickhouse-server/).
4 |
5 | ## Sponsors
6 |
7 | The clickhouse plugin was generously sponsored by the following:
8 |
9 | - [coding-socks](https://github.com/coding-socks)
10 |
11 | ## Requirements
12 |
13 | - dokku 0.19.x+
14 | - docker 1.8.x
15 |
16 | ## Installation
17 |
18 | ```shell
19 | # on 0.19.x+
20 | sudo dokku plugin:install https://github.com/dokku/dokku-clickhouse.git --name clickhouse
21 | ```
22 |
23 | ## Commands
24 |
25 | ```
26 | clickhouse:app-links # list all clickhouse service links for a given app
27 | clickhouse:backup-set-public-key-encryption # set GPG Public Key encryption for all future backups of clickhouse service
28 | clickhouse:backup-unset-public-key-encryption # unset GPG Public Key encryption for future backups of the clickhouse service
29 | clickhouse:connect # connect to the service via the clickhouse connection tool
30 | clickhouse:create [--create-flags...] # create a clickhouse service
31 | clickhouse:destroy [-f|--force] # delete the clickhouse service/data/container if there are no links left
32 | clickhouse:enter # enter or run a command in a running clickhouse service container
33 | clickhouse:exists # check if the clickhouse service exists
34 | clickhouse:expose # expose a clickhouse service on custom host:port if provided (random port on the 0.0.0.0 interface if otherwise unspecified)
35 | clickhouse:info [--single-info-flag] # print the service information
36 | clickhouse:link [--link-flags...] # link the clickhouse service to the app
37 | clickhouse:linked # check if the clickhouse service is linked to an app
38 | clickhouse:links # list all apps linked to the clickhouse service
39 | clickhouse:list # list all clickhouse services
40 | clickhouse:logs [-t|--tail] # print the most recent log(s) for this service
41 | clickhouse:pause # pause a running clickhouse service
42 | clickhouse:promote # promote service as CLICKHOUSE_URL in
43 | clickhouse:restart # graceful shutdown and restart of the clickhouse service container
44 | clickhouse:set # set or clear a property for a service
45 | clickhouse:start # start a previously stopped clickhouse service
46 | clickhouse:stop # stop a running clickhouse service
47 | clickhouse:unexpose # unexpose a previously exposed clickhouse service
48 | clickhouse:unlink # unlink the clickhouse service from the app
49 | clickhouse:upgrade [--upgrade-flags...] # upgrade service to the specified versions
50 | ```
51 |
52 | ## Usage
53 |
54 | Help for any commands can be displayed by specifying the command as an argument to clickhouse:help. Plugin help output in conjunction with any files in the `docs/` folder is used to generate the plugin documentation. Please consult the `clickhouse:help` command for any undocumented commands.
55 |
56 | ### Basic Usage
57 |
58 | ### create a clickhouse service
59 |
60 | ```shell
61 | # usage
62 | dokku clickhouse:create [--create-flags...]
63 | ```
64 |
65 | flags:
66 |
67 | - `-c|--config-options "--args --go=here"`: extra arguments to pass to the container create command (default: `None`)
68 | - `-C|--custom-env "USER=alpha;HOST=beta"`: semi-colon delimited environment variables to start the service with
69 | - `-i|--image IMAGE`: the image name to start the service with
70 | - `-I|--image-version IMAGE_VERSION`: the image version to start the service with
71 | - `-m|--memory MEMORY`: container memory limit in megabytes (default: unlimited)
72 | - `-N|--initial-network INITIAL_NETWORK`: the initial network to attach the service to
73 | - `-p|--password PASSWORD`: override the user-level service password
74 | - `-P|--post-create-network NETWORKS`: a comma-separated list of networks to attach the service container to after service creation
75 | - `-r|--root-password PASSWORD`: override the root-level service password
76 | - `-S|--post-start-network NETWORKS`: a comma-separated list of networks to attach the service container to after service start
77 | - `-s|--shm-size SHM_SIZE`: override shared memory size for clickhouse docker container
78 |
79 | Create a clickhouse service named lollipop:
80 |
81 | ```shell
82 | dokku clickhouse:create lollipop
83 | ```
84 |
85 | You can also specify the image and image version to use for the service. It *must* be compatible with the clickhouse/clickhouse-server image.
86 |
87 | ```shell
88 | export CLICKHOUSE_IMAGE="clickhouse/clickhouse-server"
89 | export CLICKHOUSE_IMAGE_VERSION="${PLUGIN_IMAGE_VERSION}"
90 | dokku clickhouse:create lollipop
91 | ```
92 |
93 | You can also specify custom environment variables to start the clickhouse service in semicolon-separated form.
94 |
95 | ```shell
96 | export CLICKHOUSE_CUSTOM_ENV="USER=alpha;HOST=beta"
97 | dokku clickhouse:create lollipop
98 | ```
99 |
100 | ### print the service information
101 |
102 | ```shell
103 | # usage
104 | dokku clickhouse:info [--single-info-flag]
105 | ```
106 |
107 | flags:
108 |
109 | - `--config-dir`: show the service configuration directory
110 | - `--data-dir`: show the service data directory
111 | - `--dsn`: show the service DSN
112 | - `--exposed-ports`: show service exposed ports
113 | - `--id`: show the service container id
114 | - `--internal-ip`: show the service internal ip
115 | - `--initial-network`: show the initial network being connected to
116 | - `--links`: show the service app links
117 | - `--post-create-network`: show the networks to attach to after service container creation
118 | - `--post-start-network`: show the networks to attach to after service container start
119 | - `--service-root`: show the service root directory
120 | - `--status`: show the service running status
121 | - `--version`: show the service image version
122 |
123 | Get connection information as follows:
124 |
125 | ```shell
126 | dokku clickhouse:info lollipop
127 | ```
128 |
129 | You can also retrieve a specific piece of service info via flags:
130 |
131 | ```shell
132 | dokku clickhouse:info lollipop --config-dir
133 | dokku clickhouse:info lollipop --data-dir
134 | dokku clickhouse:info lollipop --dsn
135 | dokku clickhouse:info lollipop --exposed-ports
136 | dokku clickhouse:info lollipop --id
137 | dokku clickhouse:info lollipop --internal-ip
138 | dokku clickhouse:info lollipop --initial-network
139 | dokku clickhouse:info lollipop --links
140 | dokku clickhouse:info lollipop --post-create-network
141 | dokku clickhouse:info lollipop --post-start-network
142 | dokku clickhouse:info lollipop --service-root
143 | dokku clickhouse:info lollipop --status
144 | dokku clickhouse:info lollipop --version
145 | ```
146 |
147 | ### list all clickhouse services
148 |
149 | ```shell
150 | # usage
151 | dokku clickhouse:list
152 | ```
153 |
154 | List all services:
155 |
156 | ```shell
157 | dokku clickhouse:list
158 | ```
159 |
160 | ### print the most recent log(s) for this service
161 |
162 | ```shell
163 | # usage
164 | dokku clickhouse:logs [-t|--tail]
165 | ```
166 |
167 | flags:
168 |
169 | - `-t|--tail []`: do not stop when end of the logs are reached and wait for additional output
170 |
171 | You can tail logs for a particular service:
172 |
173 | ```shell
174 | dokku clickhouse:logs lollipop
175 | ```
176 |
177 | By default, logs will not be tailed, but you can do this with the --tail flag:
178 |
179 | ```shell
180 | dokku clickhouse:logs lollipop --tail
181 | ```
182 |
183 | The default tail setting is to show all logs, but an initial count can also be specified:
184 |
185 | ```shell
186 | dokku clickhouse:logs lollipop --tail 5
187 | ```
188 |
189 | ### link the clickhouse service to the app
190 |
191 | ```shell
192 | # usage
193 | dokku clickhouse:link [--link-flags...]
194 | ```
195 |
196 | flags:
197 |
198 | - `-a|--alias "BLUE_DATABASE"`: an alternative alias to use for linking to an app via environment variable
199 | - `-q|--querystring "pool=5"`: ampersand delimited querystring arguments to append to the service link
200 | - `-n|--no-restart "false"`: whether or not to restart the app on link (default: true)
201 |
202 | A clickhouse service can be linked to a container. This will use native docker links via the docker-options plugin. Here we link it to our `playground` app.
203 |
204 | > NOTE: this will restart your app
205 |
206 | ```shell
207 | dokku clickhouse:link lollipop playground
208 | ```
209 |
210 | The following environment variables will be set automatically by docker (not on the app itself, so they won’t be listed when calling dokku config):
211 |
212 | ```
213 | DOKKU_CLICKHOUSE_LOLLIPOP_NAME=/lollipop/DATABASE
214 | DOKKU_CLICKHOUSE_LOLLIPOP_PORT=tcp://172.17.0.1:9000
215 | DOKKU_CLICKHOUSE_LOLLIPOP_PORT_9000_TCP=tcp://172.17.0.1:9000
216 | DOKKU_CLICKHOUSE_LOLLIPOP_PORT_9000_TCP_PROTO=tcp
217 | DOKKU_CLICKHOUSE_LOLLIPOP_PORT_9000_TCP_PORT=9000
218 | DOKKU_CLICKHOUSE_LOLLIPOP_PORT_9000_TCP_ADDR=172.17.0.1
219 | ```
220 |
221 | The following will be set on the linked application by default:
222 |
223 | ```
224 | CLICKHOUSE_URL=clickhouse://lollipop:SOME_PASSWORD@dokku-clickhouse-lollipop:9000/lollipop
225 | ```
226 |
227 | The host exposed here only works internally in docker containers. If you want your container to be reachable from outside, you should use the `expose` subcommand. Another service can be linked to your app:
228 |
229 | ```shell
230 | dokku clickhouse:link other_service playground
231 | ```
232 |
233 | It is possible to change the protocol for `CLICKHOUSE_URL` by setting the environment variable `CLICKHOUSE_DATABASE_SCHEME` on the app. Doing so will after linking will cause the plugin to think the service is not linked, and we advise you to unlink before proceeding.
234 |
235 | ```shell
236 | dokku config:set playground CLICKHOUSE_DATABASE_SCHEME=clickhouse2
237 | dokku clickhouse:link lollipop playground
238 | ```
239 |
240 | This will cause `CLICKHOUSE_URL` to be set as:
241 |
242 | ```
243 | clickhouse2://lollipop:SOME_PASSWORD@dokku-clickhouse-lollipop:9000/lollipop
244 | ```
245 |
246 | If you specify `CLICKHOUSE_DATABASE_SCHEME` to equal `http`, we`ll also automatically adjust `CLICKHOUSE_URL` to match the http interface:
247 |
248 | ```
249 | http://lollipop:SOME_PASSWORD@dokku-clickhouse-lollipop:${PLUGIN_DATASTORE_PORTS[1]}
250 | ```
251 |
252 | ### unlink the clickhouse service from the app
253 |
254 | ```shell
255 | # usage
256 | dokku clickhouse:unlink
257 | ```
258 |
259 | flags:
260 |
261 | - `-n|--no-restart "false"`: whether or not to restart the app on unlink (default: true)
262 |
263 | You can unlink a clickhouse service:
264 |
265 | > NOTE: this will restart your app and unset related environment variables
266 |
267 | ```shell
268 | dokku clickhouse:unlink lollipop playground
269 | ```
270 |
271 | ### set or clear a property for a service
272 |
273 | ```shell
274 | # usage
275 | dokku clickhouse:set
276 | ```
277 |
278 | Set the network to attach after the service container is started:
279 |
280 | ```shell
281 | dokku clickhouse:set lollipop post-create-network custom-network
282 | ```
283 |
284 | Set multiple networks:
285 |
286 | ```shell
287 | dokku clickhouse:set lollipop post-create-network custom-network,other-network
288 | ```
289 |
290 | Unset the post-create-network value:
291 |
292 | ```shell
293 | dokku clickhouse:set lollipop post-create-network
294 | ```
295 |
296 | ### Service Lifecycle
297 |
298 | The lifecycle of each service can be managed through the following commands:
299 |
300 | ### connect to the service via the clickhouse connection tool
301 |
302 | ```shell
303 | # usage
304 | dokku clickhouse:connect
305 | ```
306 |
307 | Connect to the service via the clickhouse connection tool:
308 |
309 | > NOTE: disconnecting from ssh while running this command may leave zombie processes due to moby/moby#9098
310 |
311 | ```shell
312 | dokku clickhouse:connect lollipop
313 | ```
314 |
315 | ### enter or run a command in a running clickhouse service container
316 |
317 | ```shell
318 | # usage
319 | dokku clickhouse:enter
320 | ```
321 |
322 | A bash prompt can be opened against a running service. Filesystem changes will not be saved to disk.
323 |
324 | > NOTE: disconnecting from ssh while running this command may leave zombie processes due to moby/moby#9098
325 |
326 | ```shell
327 | dokku clickhouse:enter lollipop
328 | ```
329 |
330 | You may also run a command directly against the service. Filesystem changes will not be saved to disk.
331 |
332 | ```shell
333 | dokku clickhouse:enter lollipop touch /tmp/test
334 | ```
335 |
336 | ### expose a clickhouse service on custom host:port if provided (random port on the 0.0.0.0 interface if otherwise unspecified)
337 |
338 | ```shell
339 | # usage
340 | dokku clickhouse:expose
341 | ```
342 |
343 | Expose the service on the service's normal ports, allowing access to it from the public interface (`0.0.0.0`):
344 |
345 | ```shell
346 | dokku clickhouse:expose lollipop 9000 8123
347 | ```
348 |
349 | Expose the service on the service's normal ports, with the first on a specified ip address (127.0.0.1):
350 |
351 | ```shell
352 | dokku clickhouse:expose lollipop 127.0.0.1:9000 8123
353 | ```
354 |
355 | ### unexpose a previously exposed clickhouse service
356 |
357 | ```shell
358 | # usage
359 | dokku clickhouse:unexpose
360 | ```
361 |
362 | Unexpose the service, removing access to it from the public interface (`0.0.0.0`):
363 |
364 | ```shell
365 | dokku clickhouse:unexpose lollipop
366 | ```
367 |
368 | ### promote service as CLICKHOUSE_URL in
369 |
370 | ```shell
371 | # usage
372 | dokku clickhouse:promote
373 | ```
374 |
375 | If you have a clickhouse service linked to an app and try to link another clickhouse service another link environment variable will be generated automatically:
376 |
377 | ```
378 | DOKKU_CLICKHOUSE_BLUE_URL=clickhouse://other_service:ANOTHER_PASSWORD@dokku-clickhouse-other-service:9000/other_service
379 | ```
380 |
381 | You can promote the new service to be the primary one:
382 |
383 | > NOTE: this will restart your app
384 |
385 | ```shell
386 | dokku clickhouse:promote other_service playground
387 | ```
388 |
389 | This will replace `CLICKHOUSE_URL` with the url from other_service and generate another environment variable to hold the previous value if necessary. You could end up with the following for example:
390 |
391 | ```
392 | CLICKHOUSE_URL=clickhouse://other_service:ANOTHER_PASSWORD@dokku-clickhouse-other-service:9000/other_service
393 | DOKKU_CLICKHOUSE_BLUE_URL=clickhouse://other_service:ANOTHER_PASSWORD@dokku-clickhouse-other-service:9000/other_service
394 | DOKKU_CLICKHOUSE_SILVER_URL=clickhouse://lollipop:SOME_PASSWORD@dokku-clickhouse-lollipop:9000/lollipop
395 | ```
396 |
397 | ### start a previously stopped clickhouse service
398 |
399 | ```shell
400 | # usage
401 | dokku clickhouse:start
402 | ```
403 |
404 | Start the service:
405 |
406 | ```shell
407 | dokku clickhouse:start lollipop
408 | ```
409 |
410 | ### stop a running clickhouse service
411 |
412 | ```shell
413 | # usage
414 | dokku clickhouse:stop
415 | ```
416 |
417 | Stop the service and removes the running container:
418 |
419 | ```shell
420 | dokku clickhouse:stop lollipop
421 | ```
422 |
423 | ### pause a running clickhouse service
424 |
425 | ```shell
426 | # usage
427 | dokku clickhouse:pause
428 | ```
429 |
430 | Pause the running container for the service:
431 |
432 | ```shell
433 | dokku clickhouse:pause lollipop
434 | ```
435 |
436 | ### graceful shutdown and restart of the clickhouse service container
437 |
438 | ```shell
439 | # usage
440 | dokku clickhouse:restart
441 | ```
442 |
443 | Restart the service:
444 |
445 | ```shell
446 | dokku clickhouse:restart lollipop
447 | ```
448 |
449 | ### upgrade service to the specified versions
450 |
451 | ```shell
452 | # usage
453 | dokku clickhouse:upgrade [--upgrade-flags...]
454 | ```
455 |
456 | flags:
457 |
458 | - `-c|--config-options "--args --go=here"`: extra arguments to pass to the container create command (default: `None`)
459 | - `-C|--custom-env "USER=alpha;HOST=beta"`: semi-colon delimited environment variables to start the service with
460 | - `-i|--image IMAGE`: the image name to start the service with
461 | - `-I|--image-version IMAGE_VERSION`: the image version to start the service with
462 | - `-N|--initial-network INITIAL_NETWORK`: the initial network to attach the service to
463 | - `-P|--post-create-network NETWORKS`: a comma-separated list of networks to attach the service container to after service creation
464 | - `-R|--restart-apps "true"`: whether or not to force an app restart (default: false)
465 | - `-S|--post-start-network NETWORKS`: a comma-separated list of networks to attach the service container to after service start
466 | - `-s|--shm-size SHM_SIZE`: override shared memory size for clickhouse docker container
467 |
468 | You can upgrade an existing service to a new image or image-version:
469 |
470 | ```shell
471 | dokku clickhouse:upgrade lollipop
472 | ```
473 |
474 | ### Service Automation
475 |
476 | Service scripting can be executed using the following commands:
477 |
478 | ### list all clickhouse service links for a given app
479 |
480 | ```shell
481 | # usage
482 | dokku clickhouse:app-links
483 | ```
484 |
485 | List all clickhouse services that are linked to the `playground` app.
486 |
487 | ```shell
488 | dokku clickhouse:app-links playground
489 | ```
490 |
491 | ### check if the clickhouse service exists
492 |
493 | ```shell
494 | # usage
495 | dokku clickhouse:exists
496 | ```
497 |
498 | Here we check if the lollipop clickhouse service exists.
499 |
500 | ```shell
501 | dokku clickhouse:exists lollipop
502 | ```
503 |
504 | ### check if the clickhouse service is linked to an app
505 |
506 | ```shell
507 | # usage
508 | dokku clickhouse:linked
509 | ```
510 |
511 | Here we check if the lollipop clickhouse service is linked to the `playground` app.
512 |
513 | ```shell
514 | dokku clickhouse:linked lollipop playground
515 | ```
516 |
517 | ### list all apps linked to the clickhouse service
518 |
519 | ```shell
520 | # usage
521 | dokku clickhouse:links
522 | ```
523 |
524 | List all apps linked to the `lollipop` clickhouse service.
525 |
526 | ```shell
527 | dokku clickhouse:links lollipop
528 | ```
529 | ### Backups
530 |
531 | Datastore backups are supported via AWS S3 and S3 compatible services like [minio](https://github.com/minio/minio).
532 |
533 | You may skip the `backup-auth` step if your dokku install is running within EC2 and has access to the bucket via an IAM profile. In that case, use the `--use-iam` option with the `backup` command.
534 |
535 | If both passphrase and public key forms of encryption are set, the public key encryption will take precedence.
536 |
537 | The underlying core backup script is present [here](https://github.com/dokku/docker-s3backup/blob/main/backup.sh).
538 |
539 | Backups can be performed using the backup commands:
540 |
541 | ### set GPG Public Key encryption for all future backups of clickhouse service
542 |
543 | ```shell
544 | # usage
545 | dokku clickhouse:backup-set-public-key-encryption
546 | ```
547 |
548 | Set the `GPG` Public Key for encrypting backups:
549 |
550 | ```shell
551 | dokku clickhouse:backup-set-public-key-encryption lollipop
552 | ```
553 |
554 | This method currently requires the to be present on the keyserver `keyserver.ubuntu.com`:
555 |
556 | ### unset GPG Public Key encryption for future backups of the clickhouse service
557 |
558 | ```shell
559 | # usage
560 | dokku clickhouse:backup-unset-public-key-encryption
561 | ```
562 |
563 | Unset the `GPG` Public Key encryption for backups:
564 |
565 | ```shell
566 | dokku clickhouse:backup-unset-public-key-encryption lollipop
567 | ```
568 |
569 | ### Disabling `docker image pull` calls
570 |
571 | If you wish to disable the `docker image pull` calls that the plugin triggers, you may set the `CLICKHOUSE_DISABLE_PULL` environment variable to `true`. Once disabled, you will need to pull the service image you wish to deploy as shown in the `stderr` output.
572 |
573 | Please ensure the proper images are in place when `docker image pull` is disabled.
574 |
--------------------------------------------------------------------------------
/bin/generate:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | from __future__ import print_function
4 |
5 | import os
6 | import re
7 |
8 |
9 | def compile(
10 | service,
11 | version,
12 | variable,
13 | alias,
14 | image,
15 | scheme,
16 | ports,
17 | sponsors,
18 | options,
19 | unimplemented,
20 | dokku_version,
21 | ):
22 | prefix = "\n\n".join(
23 | [
24 | header(service),
25 | description(service, image, version),
26 | ]
27 | )
28 |
29 | if len(sponsors) > 0:
30 | prefix += "\n\n"
31 | prefix += sponsors_section(service, sponsors)
32 |
33 | return (
34 | "\n\n".join(
35 | [
36 | prefix,
37 | requirements_section(dokku_version),
38 | installation_section(service, dokku_version),
39 | commands_section(
40 | service, variable, alias, image, scheme, ports, unimplemented
41 | ),
42 | usage_section(
43 | service,
44 | variable,
45 | alias,
46 | image,
47 | scheme,
48 | ports,
49 | options,
50 | unimplemented,
51 | ),
52 | ]
53 | )
54 | .replace("\n\n\n\n\n", "\n")
55 | .replace("\n\n\n\n", "\n")
56 | .replace("\n\n\n", "\n\n")
57 | )
58 |
59 |
60 | def header(service):
61 | return " ".join(
62 | [
63 | f"# dokku {service}",
64 | f'[](https://github.com/dokku/dokku-{service}/actions/workflows/ci.yml?query=branch%3Amaster)',
65 | f'[](https://webchat.libera.chat/?channels=dokku)',
66 | ]
67 | )
68 |
69 |
70 | def description(service, full_image, version):
71 | base = "_"
72 | image = full_image
73 | if "/" in full_image:
74 | base = "r/" + full_image.split("/")[0]
75 | image = full_image.split("/")[1]
76 |
77 | return f"Official {service} plugin for dokku. Currently defaults to installing [{full_image} {version}](https://hub.docker.com/{base}/{image}/)."
78 |
79 |
80 | def sponsors_section(service, sponsors):
81 | if len(sponsors) == 0:
82 | return ""
83 |
84 | sponsor_data = [
85 | "## Sponsors",
86 | "",
87 | f"The {service} plugin was generously sponsored by the following:",
88 | "",
89 | ]
90 | sponsor_data.extend([f"- [{s}](https://github.com/{s})" for s in sponsors])
91 |
92 | return "\n".join(sponsor_data)
93 |
94 |
95 | def requirements_section(dokku_version):
96 | return "\n".join(
97 | [
98 | "## Requirements",
99 | "",
100 | f"- dokku {dokku_version}",
101 | "- docker 1.8.x",
102 | ]
103 | )
104 |
105 |
106 | def installation_section(service, dokku_version):
107 | return "\n".join(
108 | [
109 | "## Installation",
110 | "",
111 | "```shell",
112 | f"# on {dokku_version}",
113 | f"sudo dokku plugin:install https://github.com/dokku/dokku-{service}.git --name {service}",
114 | "```",
115 | ]
116 | )
117 |
118 |
119 | def commands_section(service, variable, alias, image, scheme, ports, unimplemented):
120 | content = [
121 | "## Commands",
122 | "",
123 | "```",
124 | ]
125 |
126 | subcommands = os.listdir("subcommands")
127 | subcommands.sort()
128 |
129 | command_list = []
130 | descriptions = []
131 | for filename in subcommands:
132 | if filename in unimplemented:
133 | continue
134 | data = command_data(filename, service, variable, alias, image, scheme, ports)
135 | description = data["description"]
136 | arguments = data["arguments_string"]
137 |
138 | command_list.append(f"{service}:{filename} {arguments}")
139 | descriptions.append(description)
140 |
141 | maxlen = max(map(len, command_list))
142 | if maxlen > 50:
143 | maxlen = 50
144 | for command, description in zip(command_list, descriptions):
145 | space_count = maxlen - len(command)
146 | content.append("{0}{1} # {2}".format(command, " " * space_count, description))
147 |
148 | content.append("```")
149 | return "\n".join(content)
150 |
151 |
152 | def usage_section(
153 | service, variable, alias, image, scheme, ports, options, unimplemented
154 | ):
155 | return "\n\n".join(
156 | [
157 | "## Usage",
158 | f"Help for any commands can be displayed by specifying the command as an argument to {service}:help. Plugin help output in conjunction with any files in the `docs/` folder is used to generate the plugin documentation. Please consult the `{service}:help` command for any undocumented commands.",
159 | usage_intro(
160 | service, variable, alias, image, scheme, ports, options, unimplemented
161 | ),
162 | usage_lifecycle(
163 | service, variable, alias, image, scheme, ports, options, unimplemented
164 | ),
165 | usage_automation(
166 | service, variable, alias, image, scheme, ports, options, unimplemented
167 | ),
168 | usage_data_management(
169 | service, variable, alias, image, scheme, ports, options, unimplemented
170 | ),
171 | usage_backup(
172 | service, variable, alias, image, scheme, ports, options, unimplemented
173 | ),
174 | usage_docker_pull(
175 | service, variable, alias, image, scheme, ports, options, unimplemented
176 | ),
177 | ]
178 | )
179 |
180 |
181 | def usage_intro(service, variable, alias, image, scheme, ports, options, unimplemented):
182 | commands = ["create", "info", "list", "logs", "link", "unlink", "set"]
183 | content = ["### Basic Usage"]
184 |
185 | return fetch_commands_content(
186 | service,
187 | variable,
188 | alias,
189 | image,
190 | scheme,
191 | ports,
192 | options,
193 | unimplemented,
194 | commands,
195 | content,
196 | )
197 |
198 |
199 | def usage_lifecycle(
200 | service, variable, alias, image, scheme, ports, options, unimplemented
201 | ):
202 | commands = [
203 | "connect",
204 | "enter",
205 | "expose",
206 | "unexpose",
207 | "promote",
208 | "start",
209 | "stop",
210 | "pause",
211 | "restart",
212 | "upgrade",
213 | ]
214 | content = [
215 | "### Service Lifecycle",
216 | "",
217 | "The lifecycle of each service can be managed through the following commands:",
218 | "",
219 | ]
220 |
221 | return fetch_commands_content(
222 | service,
223 | variable,
224 | alias,
225 | image,
226 | scheme,
227 | ports,
228 | options,
229 | unimplemented,
230 | commands,
231 | content,
232 | )
233 |
234 |
235 | def usage_automation(
236 | service, variable, alias, image, scheme, ports, options, unimplemented
237 | ):
238 | commands = ["app-links", "clone", "exists", "linked", "links"]
239 | content = [
240 | "### Service Automation",
241 | "",
242 | "Service scripting can be executed using the following commands:",
243 | "",
244 | ]
245 |
246 | return fetch_commands_content(
247 | service,
248 | variable,
249 | alias,
250 | image,
251 | scheme,
252 | ports,
253 | options,
254 | unimplemented,
255 | commands,
256 | content,
257 | )
258 |
259 |
260 | def usage_data_management(
261 | service, variable, alias, image, scheme, ports, options, unimplemented
262 | ):
263 | commands = ["import", "export"]
264 | content = [
265 | "### Data Management",
266 | "",
267 | "The underlying service data can be imported and exported with the following commands:",
268 | "",
269 | ]
270 |
271 | return fetch_commands_content(
272 | service,
273 | variable,
274 | alias,
275 | image,
276 | scheme,
277 | ports,
278 | options,
279 | unimplemented,
280 | commands,
281 | content,
282 | )
283 |
284 |
285 | def usage_backup(
286 | service, variable, alias, image, scheme, ports, options, unimplemented
287 | ):
288 | commands = [
289 | "backup-auth",
290 | "backup-deauth",
291 | "backup",
292 | "backup-set-encryption",
293 | "backup-set-public-key-encryption",
294 | "backup-unset-encryption",
295 | "backup-unset-public-key-encryption",
296 | "backup-schedule",
297 | "backup-schedule-cat",
298 | "backup-unschedule",
299 | ]
300 | content = [
301 | "### Backups",
302 | "",
303 | "Datastore backups are supported via AWS S3 and S3 compatible services like [minio](https://github.com/minio/minio).",
304 | "",
305 | "You may skip the `backup-auth` step if your dokku install is running within EC2 and has access to the bucket via an IAM profile. In that case, use the `--use-iam` option with the `backup` command.",
306 | "",
307 | "If both passphrase and public key forms of encryption are set, the public key encryption will take precedence.",
308 | "",
309 | "The underlying core backup script is present [here](https://github.com/dokku/docker-s3backup/blob/main/backup.sh).",
310 | "",
311 | "Backups can be performed using the backup commands:",
312 | "",
313 | ]
314 |
315 | return fetch_commands_content(
316 | service,
317 | variable,
318 | alias,
319 | image,
320 | scheme,
321 | ports,
322 | options,
323 | unimplemented,
324 | commands,
325 | content,
326 | )
327 |
328 |
329 | def usage_docker_pull(
330 | service, variable, alias, image, scheme, ports, options, unimplemented
331 | ):
332 | service_prefix = service.upper()
333 | return "\n".join(
334 | [
335 | "### Disabling `docker image pull` calls",
336 | "",
337 | f"If you wish to disable the `docker image pull` calls that the plugin triggers, you may set the `{service_prefix}_DISABLE_PULL` environment variable to `true`. Once disabled, you will need to pull the service image you wish to deploy as shown in the `stderr` output.",
338 | "",
339 | "Please ensure the proper images are in place when `docker image pull` is disabled.",
340 | ]
341 | )
342 |
343 |
344 | def fetch_commands_content(
345 | service,
346 | variable,
347 | alias,
348 | image,
349 | scheme,
350 | ports,
351 | options,
352 | unimplemented,
353 | commands,
354 | content,
355 | ):
356 | i = 0
357 | for command in commands:
358 | output = command_help(
359 | command,
360 | service,
361 | variable,
362 | alias,
363 | image,
364 | scheme,
365 | ports,
366 | options,
367 | unimplemented,
368 | )
369 | if output == "":
370 | continue
371 | content.append(output)
372 | i += 1
373 |
374 | if i == 0:
375 | return ""
376 |
377 | return "\n".join(content)
378 |
379 |
380 | def parse_args(line):
381 | line = line.strip()
382 | arguments = []
383 | for arg in re.findall("([A-Z_]+)", line):
384 | arg = arg.replace("_", "-").lower()
385 | if arg.endswith("optional-flag"):
386 | arg = arg.replace("-optional-flag", "")
387 | arguments.append(f"[--{arg}]")
388 | elif arg.endswith("-flag"):
389 | if arg == "info-flag":
390 | arguments.append(f"[--single-info-flag]")
391 | else:
392 | arg = arg.replace("-flag", "")
393 | first_letter = arg[0]
394 | arguments.append(f"[-{first_letter}|--{arg}]")
395 | elif arg.endswith("-flags-list"):
396 | arg = arg.replace("-list", "")
397 | arguments.append(f"[--{arg}...]")
398 | elif arg.endswith("list"):
399 | arg = arg.replace("-list", "")
400 | arguments.append(f"<{arg}...>")
401 | else:
402 | arguments.append(f"<{arg}>")
403 | return " ".join(arguments)
404 |
405 |
406 | def command_help(
407 | command, service, variable, alias, image, scheme, ports, options, unimplemented
408 | ):
409 | if command in unimplemented:
410 | return ""
411 |
412 | data = command_data(command, service, variable, alias, image, scheme, ports)
413 | content = [
414 | f"### {data['description']}",
415 | "",
416 | "```shell",
417 | "# usage",
418 | f"dokku {service}:{command} {data['arguments_string']}".strip(),
419 | "```",
420 | ]
421 |
422 | # if len(data["arguments"]) > 0:
423 | # content.append("")
424 | # content.append("arguments:")
425 | # content.append("")
426 | # for argument in data["arguments"]:
427 | # content.append(f"- {argument}")
428 |
429 | if len(data["flags"]) > 0:
430 | content.append("")
431 | content.append("flags:")
432 | content.append("")
433 | for flag in data["flags"]:
434 | if "--config-options" in flag and options != "":
435 | flag = f"{flag} (default: `{options}`)"
436 | content.append(f"- {flag}")
437 |
438 | if len(data["examples"]) > 0:
439 | content.append("")
440 | content.append(data["examples"])
441 |
442 | doc_file = os.path.join("docs", f"{command}.md")
443 | if os.path.isfile(doc_file):
444 | content.append("")
445 | with open(doc_file) as f:
446 | content.append(f.read())
447 |
448 | return "\n" + "\n".join(content)
449 |
450 |
451 | def command_data(command, service, variable, alias, image, scheme, ports):
452 | description = None
453 | arguments = []
454 | arguments_string = ""
455 | example_lines = []
456 | flags = []
457 | with open(os.path.join("subcommands", command)) as f:
458 | for line in f.readlines():
459 | line = line.strip()
460 | line = line.replace("$PLUGIN_SERVICE", service)
461 | line = line.replace("$PLUGIN_COMMAND_PREFIX", service)
462 | line = line.replace("${PLUGIN_COMMAND_PREFIX}", service)
463 | line = line.replace("${PLUGIN_VARIABLE}", variable)
464 | line = line.replace("${PLUGIN_DEFAULT_ALIAS}", alias)
465 | line = line.replace("${PLUGIN_IMAGE}", image)
466 | line = line.replace("${PLUGIN_SCHEME}", scheme)
467 | line = line.replace("${PLUGIN_DATASTORE_PORTS[0]}", ports[0])
468 | line = line.replace("${PLUGIN_DATASTORE_PORTS[@]}", " ".join(ports))
469 |
470 | if "declare desc" in line:
471 | description = re.search('"(.+)"', line).group(1)
472 | elif "$1" in line:
473 | arguments_string = parse_args(line)
474 | elif line.startswith("#A "):
475 | argument = line.replace("#A ", "")
476 | parts = [a.strip() for a in argument.split(",", 1)]
477 | arguments.append(f"`{parts[0]}`: {parts[1]}")
478 | elif line.startswith("#F "):
479 | flag = line.replace("#F ", "")
480 | parts = [a.strip() for a in flag.split(",", 1)]
481 | flags.append(f"`{parts[0]}`: {parts[1]}")
482 | elif line.startswith("#E "):
483 | example_lines.append(line.replace("#E ", ""))
484 |
485 | examples = []
486 | sentence_lines = []
487 | command_lines = []
488 | codeblock_lines = []
489 | blockquote_lines = []
490 | for line in example_lines:
491 | if line.startswith("export") or line.startswith("dokku"):
492 | if len(blockquote_lines) > 0:
493 | examples.append("\n" + process_blockquote(blockquote_lines))
494 | blockquote_lines = []
495 | if len(codeblock_lines) > 0:
496 | examples.append("\n" + process_codeblock(codeblock_lines))
497 | codeblock_lines = []
498 | if len(sentence_lines) > 0:
499 | examples.append("\n" + process_sentence(sentence_lines))
500 | sentence_lines = []
501 |
502 | command_lines.append(line)
503 | elif line.startswith(" "):
504 | if len(blockquote_lines) > 0:
505 | examples.append("\n" + process_blockquote(blockquote_lines))
506 | blockquote_lines = []
507 | if len(command_lines) > 0:
508 | examples.append("\n" + process_command(command_lines))
509 | command_lines = []
510 | if len(sentence_lines) > 0:
511 | examples.append("\n" + process_sentence(sentence_lines))
512 | sentence_lines = []
513 |
514 | codeblock_lines.append(line.strip())
515 | elif line.startswith(">"):
516 | if len(codeblock_lines) > 0:
517 | examples.append("\n" + process_codeblock(codeblock_lines))
518 | codeblock_lines = []
519 | if len(command_lines) > 0:
520 | examples.append("\n" + process_command(command_lines))
521 | command_lines = []
522 | if len(sentence_lines) > 0:
523 | examples.append("\n" + process_sentence(sentence_lines))
524 | sentence_lines = []
525 |
526 | blockquote_lines.append(line)
527 | else:
528 | if len(blockquote_lines) > 0:
529 | examples.append("\n" + process_blockquote(blockquote_lines))
530 | blockquote_lines = []
531 | if len(codeblock_lines) > 0:
532 | examples.append("\n" + process_codeblock(codeblock_lines))
533 | codeblock_lines = []
534 | if len(command_lines) > 0:
535 | examples.append("\n" + process_command(command_lines))
536 | command_lines = []
537 |
538 | sentence_lines.append(line)
539 |
540 | if len(blockquote_lines) > 0:
541 | examples.append("\n" + process_blockquote(blockquote_lines))
542 | blockquote_lines = []
543 | if len(codeblock_lines) > 0:
544 | examples.append("\n" + process_codeblock(codeblock_lines))
545 | codeblock_lines = []
546 | if len(command_lines) > 0:
547 | examples.append("\n" + process_command(command_lines))
548 | command_lines = []
549 | if len(sentence_lines) > 0:
550 | examples.append("\n" + process_sentence(sentence_lines))
551 | sentence_lines = []
552 |
553 | return {
554 | "description": description,
555 | "arguments_string": arguments_string,
556 | "arguments": arguments,
557 | "flags": flags,
558 | "examples": "\n".join(examples).strip(),
559 | }
560 |
561 |
562 | def process_sentence(sentence_lines):
563 | sentence_lines = " ".join(sentence_lines)
564 | sentences = ". ".join(
565 | upperfirst(i.strip()) for i in sentence_lines.split(". ")
566 | ).strip()
567 | if not sentences.endswith(".") and not sentences.endswith(":"):
568 | sentences += ":"
569 |
570 | text = []
571 | for sentence in sentences.split(". "):
572 | parts = []
573 | for word in sentence.strip().split(" "):
574 | if word.isupper() and len(word) > 1:
575 | for ending in [":", "."]:
576 | if word.endswith(ending):
577 | word = "`{0}`{1}".format(word[:-1], ending)
578 | else:
579 | word = "`{0}`".format(word)
580 | parts.append(word)
581 | text.append(" ".join(parts))
582 |
583 | text = ". ".join(text)
584 |
585 | # some cleanup
586 | text = text.replace("(0.0.0.0)", "(`0.0.0.0`)")
587 | text = text.replace("'", "`")
588 | text = text.replace("`s", "'s")
589 | text = text.replace("``", "`")
590 | text = text.strip(" ")
591 |
592 | return text
593 |
594 |
595 | def upperfirst(x):
596 | return x[:1].upper() + x[1:]
597 |
598 |
599 | def process_blockquote(blockquote_lines):
600 | return "\n".join(blockquote_lines)
601 |
602 |
603 | def process_command(command_lines):
604 | command_lines = "\n".join(command_lines)
605 | return f"```shell\n{command_lines}\n```"
606 |
607 |
608 | def process_codeblock(codeblock_lines):
609 | codeblock_lines = "\n".join(codeblock_lines)
610 | return f"```\n{codeblock_lines}\n```"
611 |
612 |
613 | def main():
614 | service = None
615 | version = None
616 | variable = None
617 | image = None
618 | alias = None
619 | options = None
620 | unimplemented = []
621 |
622 | with open("Dockerfile") as f:
623 | for line in f.readlines():
624 | if "FROM " in line:
625 | image, version = line.split(" ")[1].split(":")
626 | image = image.strip()
627 | version = version.strip()
628 |
629 | with open("config") as f:
630 | for line in f.readlines():
631 | if "PLUGIN_COMMAND_PREFIX=" in line:
632 | service = re.search('"(.+)"', line).group(1)
633 | if "PLUGIN_DEFAULT_ALIAS=" in line:
634 | alias = re.search('"(.+)"', line).group(1)
635 | if "PLUGIN_VARIABLE=" in line:
636 | variable = re.search('"(.+)"', line).group(1)
637 | if "PLUGIN_SCHEME=" in line:
638 | scheme = re.search('"(.+)"', line).group(1)
639 | if "PLUGIN_DATASTORE_PORTS=" in line:
640 | ports = re.search("\((.+)\)", line).group(1).split(" ")
641 | if "PLUGIN_UNIMPLEMENTED_SUBCOMMANDS=" in line:
642 | match = re.search("\((.+)\)", line)
643 | if match is not None:
644 | unimplemented = [s.strip('"') for s in match.group(1).split(" ")]
645 |
646 | with open("config") as f:
647 | for line in f.readlines():
648 | if f"{variable}_CONFIG_OPTIONS" in line:
649 | match = re.search('"(.+)"', line)
650 | if match is not None:
651 | options = match.group(1)
652 |
653 | sponsors = []
654 | with open("plugin.toml") as f:
655 | for line in f.readlines():
656 | if line.startswith("sponsors"):
657 | sponsors = re.search('\[(["\w\s,_-]+)\]', line).group(1)
658 | sponsors = [s.strip('"') for s in sponsors.split(",")]
659 |
660 | text = compile(
661 | service,
662 | version,
663 | variable,
664 | alias,
665 | image,
666 | scheme,
667 | ports,
668 | sponsors,
669 | options,
670 | unimplemented,
671 | "0.19.x+",
672 | )
673 |
674 | base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
675 | readme_file = os.path.join(base_path, "README.md")
676 | with open(readme_file, "w") as f:
677 | f.write(text + "\n")
678 |
679 |
680 | if __name__ == "__main__":
681 | main()
682 |
--------------------------------------------------------------------------------