├── .devcontainer ├── 20_init_plugin ├── Dockerfile ├── bin │ └── copy-file └── devcontainer.json ├── .editorconfig ├── .github ├── dependabot.yml ├── labels.yml └── workflows │ ├── ci.yml │ └── tagged-release.yml ├── .gitignore ├── Dockerfile ├── LICENSE.txt ├── Makefile ├── README.md ├── Vagrantfile ├── bin └── generate ├── commands ├── common-functions ├── config ├── docs ├── README.md ├── create.md ├── export.md └── upgrade.md ├── functions ├── help-functions ├── install ├── plugin.toml ├── post-app-clone-setup ├── post-app-rename-setup ├── pre-delete ├── pre-restore ├── pre-start ├── scripts ├── create_ssl_certs.sh └── enable_ssl.sh ├── service-list ├── subcommands ├── app-links ├── backup ├── backup-auth ├── backup-deauth ├── backup-schedule ├── backup-schedule-cat ├── backup-set-encryption ├── backup-set-public-key-encryption ├── backup-unschedule ├── backup-unset-encryption ├── backup-unset-public-key-encryption ├── clone ├── connect ├── create ├── destroy ├── enter ├── exists ├── export ├── expose ├── import ├── info ├── link ├── linked ├── links ├── list ├── logs ├── pause ├── promote ├── restart ├── set ├── start ├── stop ├── unexpose ├── unlink └── upgrade ├── tests ├── hook_pre_delete.bats ├── link_networks.bats ├── service_clone.bats ├── service_connect.bats ├── service_create.bats ├── service_destroy.bats ├── service_export.bats ├── service_expose.bats ├── service_import.bats ├── service_info.bats ├── service_link.bats ├── service_list.bats ├── service_logs.bats ├── service_pause.bats ├── service_promote.bats ├── service_restart.bats ├── service_start.bats ├── service_stop.bats ├── service_unexpose.bats ├── service_unlink.bats ├── setup.sh ├── shellcheck-exclude ├── shellcheck-to-junit └── test_helper.bash └── update /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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@v4 26 | with: 27 | fetch-depth: 0 28 | 29 | - uses: actions/setup-python@v5 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@v4 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@v4 68 | with: 69 | fetch-depth: 0 70 | 71 | - uses: actions/setup-python@v5 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@v4 97 | if: failure() 98 | with: 99 | name: tmp/test-results 100 | path: test-results 101 | -------------------------------------------------------------------------------- /.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.2.2 18 | with: 19 | generate_release_notes: true 20 | make_latest: "true" 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | .vagrant 3 | bootstrap.sh 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM postgres:17.5 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dokku postgres [![Build Status](https://img.shields.io/github/actions/workflow/status/dokku/dokku-postgres/ci.yml?branch=master&style=flat-square "Build Status")](https://github.com/dokku/dokku-postgres/actions/workflows/ci.yml?query=branch%3Amaster) [![IRC Network](https://img.shields.io/badge/irc-libera-blue.svg?style=flat-square "IRC Libera")](https://webchat.libera.chat/?channels=dokku) 2 | 3 | Official postgres plugin for dokku. Currently defaults to installing [postgres 17.5](https://hub.docker.com/_/postgres/). 4 | 5 | ## Requirements 6 | 7 | - dokku 0.19.x+ 8 | - docker 1.8.x 9 | 10 | ## Installation 11 | 12 | ```shell 13 | # on 0.19.x+ 14 | sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git --name postgres 15 | ``` 16 | 17 | ## Commands 18 | 19 | ``` 20 | postgres:app-links # list all postgres service links for a given app 21 | postgres:backup [--use-iam] # create a backup of the postgres service to an existing s3 bucket 22 | postgres:backup-auth # set up authentication for backups on the postgres service 23 | postgres:backup-deauth # remove backup authentication for the postgres service 24 | postgres:backup-schedule [--use-iam] # schedule a backup of the postgres service 25 | postgres:backup-schedule-cat # cat the contents of the configured backup cronfile for the service 26 | postgres:backup-set-encryption # set encryption for all future backups of postgres service 27 | postgres:backup-set-public-key-encryption # set GPG Public Key encryption for all future backups of postgres service 28 | postgres:backup-unschedule # unschedule the backup of the postgres service 29 | postgres:backup-unset-encryption # unset encryption for future backups of the postgres service 30 | postgres:backup-unset-public-key-encryption # unset GPG Public Key encryption for future backups of the postgres service 31 | postgres:clone [--clone-flags...] # create container then copy data from into 32 | postgres:connect # connect to the service via the postgres connection tool 33 | postgres:create [--create-flags...] # create a postgres service 34 | postgres:destroy [-f|--force] # delete the postgres service/data/container if there are no links left 35 | postgres:enter # enter or run a command in a running postgres service container 36 | postgres:exists # check if the postgres service exists 37 | postgres:export # export a dump of the postgres service database 38 | postgres:expose # expose a postgres service on custom host:port if provided (random port on the 0.0.0.0 interface if otherwise unspecified) 39 | postgres:import # import a dump into the postgres service database 40 | postgres:info [--single-info-flag] # print the service information 41 | postgres:link [--link-flags...] # link the postgres service to the app 42 | postgres:linked # check if the postgres service is linked to an app 43 | postgres:links # list all apps linked to the postgres service 44 | postgres:list # list all postgres services 45 | postgres:logs [-t|--tail] # print the most recent log(s) for this service 46 | postgres:pause # pause a running postgres service 47 | postgres:promote # promote service as DATABASE_URL in 48 | postgres:restart # graceful shutdown and restart of the postgres service container 49 | postgres:set # set or clear a property for a service 50 | postgres:start # start a previously stopped postgres service 51 | postgres:stop # stop a running postgres service 52 | postgres:unexpose # unexpose a previously exposed postgres service 53 | postgres:unlink # unlink the postgres service from the app 54 | postgres:upgrade [--upgrade-flags...] # upgrade service to the specified versions 55 | ``` 56 | 57 | ## Usage 58 | 59 | Help for any commands can be displayed by specifying the command as an argument to postgres:help. Plugin help output in conjunction with any files in the `docs/` folder is used to generate the plugin documentation. Please consult the `postgres:help` command for any undocumented commands. 60 | 61 | ### Basic Usage 62 | 63 | ### create a postgres service 64 | 65 | ```shell 66 | # usage 67 | dokku postgres:create [--create-flags...] 68 | ``` 69 | 70 | flags: 71 | 72 | - `-c|--config-options "--args --go=here"`: extra arguments to pass to the container create command (default: `None`) 73 | - `-C|--custom-env "USER=alpha;HOST=beta"`: semi-colon delimited environment variables to start the service with 74 | - `-i|--image IMAGE`: the image name to start the service with 75 | - `-I|--image-version IMAGE_VERSION`: the image version to start the service with 76 | - `-m|--memory MEMORY`: container memory limit in megabytes (default: unlimited) 77 | - `-N|--initial-network INITIAL_NETWORK`: the initial network to attach the service to 78 | - `-p|--password PASSWORD`: override the user-level service password 79 | - `-P|--post-create-network NETWORKS`: a comma-separated list of networks to attach the service container to after service creation 80 | - `-r|--root-password PASSWORD`: override the root-level service password 81 | - `-S|--post-start-network NETWORKS`: a comma-separated list of networks to attach the service container to after service start 82 | - `-s|--shm-size SHM_SIZE`: override shared memory size for postgres docker container 83 | 84 | Create a postgres service named lollipop: 85 | 86 | ```shell 87 | dokku postgres:create lollipop 88 | ``` 89 | 90 | You can also specify the image and image version to use for the service. It *must* be compatible with the postgres image. 91 | 92 | ```shell 93 | export POSTGRES_IMAGE="postgres" 94 | export POSTGRES_IMAGE_VERSION="${PLUGIN_IMAGE_VERSION}" 95 | dokku postgres:create lollipop 96 | ``` 97 | 98 | You can also specify custom environment variables to start the postgres service in semicolon-separated form. 99 | 100 | ```shell 101 | export POSTGRES_CUSTOM_ENV="USER=alpha;HOST=beta" 102 | dokku postgres:create lollipop 103 | ``` 104 | 105 | Official Postgres "$DOCKER_BIN" image ls does not include postgis extension (amongst others). The following example creates a new postgres service using `postgis/postgis:13-3.1` image, which includes the `postgis` extension. 106 | 107 | ```shell 108 | # use the appropriate image-version for your use-case 109 | dokku postgres:create postgis-database --image "postgis/postgis" --image-version "13-3.1" 110 | ``` 111 | 112 | To use pgvector instead, run the following: 113 | 114 | ```shell 115 | # use the appropriate image-version for your use-case 116 | dokku postgres:create pgvector-database --image "pgvector/pgvector" --image-version "pg17" 117 | ``` 118 | 119 | ### print the service information 120 | 121 | ```shell 122 | # usage 123 | dokku postgres:info [--single-info-flag] 124 | ``` 125 | 126 | flags: 127 | 128 | - `--config-dir`: show the service configuration directory 129 | - `--data-dir`: show the service data directory 130 | - `--dsn`: show the service DSN 131 | - `--exposed-ports`: show service exposed ports 132 | - `--id`: show the service container id 133 | - `--internal-ip`: show the service internal ip 134 | - `--initial-network`: show the initial network being connected to 135 | - `--links`: show the service app links 136 | - `--post-create-network`: show the networks to attach to after service container creation 137 | - `--post-start-network`: show the networks to attach to after service container start 138 | - `--service-root`: show the service root directory 139 | - `--status`: show the service running status 140 | - `--version`: show the service image version 141 | 142 | Get connection information as follows: 143 | 144 | ```shell 145 | dokku postgres:info lollipop 146 | ``` 147 | 148 | You can also retrieve a specific piece of service info via flags: 149 | 150 | ```shell 151 | dokku postgres:info lollipop --config-dir 152 | dokku postgres:info lollipop --data-dir 153 | dokku postgres:info lollipop --dsn 154 | dokku postgres:info lollipop --exposed-ports 155 | dokku postgres:info lollipop --id 156 | dokku postgres:info lollipop --internal-ip 157 | dokku postgres:info lollipop --initial-network 158 | dokku postgres:info lollipop --links 159 | dokku postgres:info lollipop --post-create-network 160 | dokku postgres:info lollipop --post-start-network 161 | dokku postgres:info lollipop --service-root 162 | dokku postgres:info lollipop --status 163 | dokku postgres:info lollipop --version 164 | ``` 165 | 166 | ### list all postgres services 167 | 168 | ```shell 169 | # usage 170 | dokku postgres:list 171 | ``` 172 | 173 | List all services: 174 | 175 | ```shell 176 | dokku postgres:list 177 | ``` 178 | 179 | ### print the most recent log(s) for this service 180 | 181 | ```shell 182 | # usage 183 | dokku postgres:logs [-t|--tail] 184 | ``` 185 | 186 | flags: 187 | 188 | - `-t|--tail []`: do not stop when end of the logs are reached and wait for additional output 189 | 190 | You can tail logs for a particular service: 191 | 192 | ```shell 193 | dokku postgres:logs lollipop 194 | ``` 195 | 196 | By default, logs will not be tailed, but you can do this with the --tail flag: 197 | 198 | ```shell 199 | dokku postgres:logs lollipop --tail 200 | ``` 201 | 202 | The default tail setting is to show all logs, but an initial count can also be specified: 203 | 204 | ```shell 205 | dokku postgres:logs lollipop --tail 5 206 | ``` 207 | 208 | ### link the postgres service to the app 209 | 210 | ```shell 211 | # usage 212 | dokku postgres:link [--link-flags...] 213 | ``` 214 | 215 | flags: 216 | 217 | - `-a|--alias "BLUE_DATABASE"`: an alternative alias to use for linking to an app via environment variable 218 | - `-q|--querystring "pool=5"`: ampersand delimited querystring arguments to append to the service link 219 | - `-n|--no-restart "false"`: whether or not to restart the app on link (default: true) 220 | 221 | A postgres 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. 222 | 223 | > NOTE: this will restart your app 224 | 225 | ```shell 226 | dokku postgres:link lollipop playground 227 | ``` 228 | 229 | 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): 230 | 231 | ``` 232 | DOKKU_POSTGRES_LOLLIPOP_NAME=/lollipop/DATABASE 233 | DOKKU_POSTGRES_LOLLIPOP_PORT=tcp://172.17.0.1:5432 234 | DOKKU_POSTGRES_LOLLIPOP_PORT_5432_TCP=tcp://172.17.0.1:5432 235 | DOKKU_POSTGRES_LOLLIPOP_PORT_5432_TCP_PROTO=tcp 236 | DOKKU_POSTGRES_LOLLIPOP_PORT_5432_TCP_PORT=5432 237 | DOKKU_POSTGRES_LOLLIPOP_PORT_5432_TCP_ADDR=172.17.0.1 238 | ``` 239 | 240 | The following will be set on the linked application by default: 241 | 242 | ``` 243 | DATABASE_URL=postgres://lollipop:SOME_PASSWORD@dokku-postgres-lollipop:5432/lollipop 244 | ``` 245 | 246 | 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: 247 | 248 | ```shell 249 | dokku postgres:link other_service playground 250 | ``` 251 | 252 | It is possible to change the protocol for `DATABASE_URL` by setting the environment variable `POSTGRES_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. 253 | 254 | ```shell 255 | dokku config:set playground POSTGRES_DATABASE_SCHEME=postgres2 256 | dokku postgres:link lollipop playground 257 | ``` 258 | 259 | This will cause `DATABASE_URL` to be set as: 260 | 261 | ``` 262 | postgres2://lollipop:SOME_PASSWORD@dokku-postgres-lollipop:5432/lollipop 263 | ``` 264 | 265 | ### unlink the postgres service from the app 266 | 267 | ```shell 268 | # usage 269 | dokku postgres:unlink 270 | ``` 271 | 272 | flags: 273 | 274 | - `-n|--no-restart "false"`: whether or not to restart the app on unlink (default: true) 275 | 276 | You can unlink a postgres service: 277 | 278 | > NOTE: this will restart your app and unset related environment variables 279 | 280 | ```shell 281 | dokku postgres:unlink lollipop playground 282 | ``` 283 | 284 | ### set or clear a property for a service 285 | 286 | ```shell 287 | # usage 288 | dokku postgres:set 289 | ``` 290 | 291 | Set the network to attach after the service container is started: 292 | 293 | ```shell 294 | dokku postgres:set lollipop post-create-network custom-network 295 | ``` 296 | 297 | Set multiple networks: 298 | 299 | ```shell 300 | dokku postgres:set lollipop post-create-network custom-network,other-network 301 | ``` 302 | 303 | Unset the post-create-network value: 304 | 305 | ```shell 306 | dokku postgres:set lollipop post-create-network 307 | ``` 308 | 309 | ### Service Lifecycle 310 | 311 | The lifecycle of each service can be managed through the following commands: 312 | 313 | ### connect to the service via the postgres connection tool 314 | 315 | ```shell 316 | # usage 317 | dokku postgres:connect 318 | ``` 319 | 320 | Connect to the service via the postgres connection tool: 321 | 322 | > NOTE: disconnecting from ssh while running this command may leave zombie processes due to moby/moby#9098 323 | 324 | ```shell 325 | dokku postgres:connect lollipop 326 | ``` 327 | 328 | ### enter or run a command in a running postgres service container 329 | 330 | ```shell 331 | # usage 332 | dokku postgres:enter 333 | ``` 334 | 335 | A bash prompt can be opened against a running service. Filesystem changes will not be saved to disk. 336 | 337 | > NOTE: disconnecting from ssh while running this command may leave zombie processes due to moby/moby#9098 338 | 339 | ```shell 340 | dokku postgres:enter lollipop 341 | ``` 342 | 343 | You may also run a command directly against the service. Filesystem changes will not be saved to disk. 344 | 345 | ```shell 346 | dokku postgres:enter lollipop touch /tmp/test 347 | ``` 348 | 349 | ### expose a postgres service on custom host:port if provided (random port on the 0.0.0.0 interface if otherwise unspecified) 350 | 351 | ```shell 352 | # usage 353 | dokku postgres:expose 354 | ``` 355 | 356 | Expose the service on the service's normal ports, allowing access to it from the public interface (`0.0.0.0`): 357 | 358 | ```shell 359 | dokku postgres:expose lollipop 5432 360 | ``` 361 | 362 | Expose the service on the service's normal ports, with the first on a specified ip address (127.0.0.1): 363 | 364 | ```shell 365 | dokku postgres:expose lollipop 127.0.0.1:5432 366 | ``` 367 | 368 | ### unexpose a previously exposed postgres service 369 | 370 | ```shell 371 | # usage 372 | dokku postgres:unexpose 373 | ``` 374 | 375 | Unexpose the service, removing access to it from the public interface (`0.0.0.0`): 376 | 377 | ```shell 378 | dokku postgres:unexpose lollipop 379 | ``` 380 | 381 | ### promote service as DATABASE_URL in 382 | 383 | ```shell 384 | # usage 385 | dokku postgres:promote 386 | ``` 387 | 388 | If you have a postgres service linked to an app and try to link another postgres service another link environment variable will be generated automatically: 389 | 390 | ``` 391 | DOKKU_DATABASE_BLUE_URL=postgres://other_service:ANOTHER_PASSWORD@dokku-postgres-other-service:5432/other_service 392 | ``` 393 | 394 | You can promote the new service to be the primary one: 395 | 396 | > NOTE: this will restart your app 397 | 398 | ```shell 399 | dokku postgres:promote other_service playground 400 | ``` 401 | 402 | This will replace `DATABASE_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: 403 | 404 | ``` 405 | DATABASE_URL=postgres://other_service:ANOTHER_PASSWORD@dokku-postgres-other-service:5432/other_service 406 | DOKKU_DATABASE_BLUE_URL=postgres://other_service:ANOTHER_PASSWORD@dokku-postgres-other-service:5432/other_service 407 | DOKKU_DATABASE_SILVER_URL=postgres://lollipop:SOME_PASSWORD@dokku-postgres-lollipop:5432/lollipop 408 | ``` 409 | 410 | ### start a previously stopped postgres service 411 | 412 | ```shell 413 | # usage 414 | dokku postgres:start 415 | ``` 416 | 417 | Start the service: 418 | 419 | ```shell 420 | dokku postgres:start lollipop 421 | ``` 422 | 423 | ### stop a running postgres service 424 | 425 | ```shell 426 | # usage 427 | dokku postgres:stop 428 | ``` 429 | 430 | Stop the service and removes the running container: 431 | 432 | ```shell 433 | dokku postgres:stop lollipop 434 | ``` 435 | 436 | ### pause a running postgres service 437 | 438 | ```shell 439 | # usage 440 | dokku postgres:pause 441 | ``` 442 | 443 | Pause the running container for the service: 444 | 445 | ```shell 446 | dokku postgres:pause lollipop 447 | ``` 448 | 449 | ### graceful shutdown and restart of the postgres service container 450 | 451 | ```shell 452 | # usage 453 | dokku postgres:restart 454 | ``` 455 | 456 | Restart the service: 457 | 458 | ```shell 459 | dokku postgres:restart lollipop 460 | ``` 461 | 462 | ### upgrade service to the specified versions 463 | 464 | ```shell 465 | # usage 466 | dokku postgres:upgrade [--upgrade-flags...] 467 | ``` 468 | 469 | flags: 470 | 471 | - `-c|--config-options "--args --go=here"`: extra arguments to pass to the container create command (default: `None`) 472 | - `-C|--custom-env "USER=alpha;HOST=beta"`: semi-colon delimited environment variables to start the service with 473 | - `-i|--image IMAGE`: the image name to start the service with 474 | - `-I|--image-version IMAGE_VERSION`: the image version to start the service with 475 | - `-N|--initial-network INITIAL_NETWORK`: the initial network to attach the service to 476 | - `-P|--post-create-network NETWORKS`: a comma-separated list of networks to attach the service container to after service creation 477 | - `-R|--restart-apps "true"`: whether or not to force an app restart (default: false) 478 | - `-S|--post-start-network NETWORKS`: a comma-separated list of networks to attach the service container to after service start 479 | - `-s|--shm-size SHM_SIZE`: override shared memory size for postgres docker container 480 | 481 | You can upgrade an existing service to a new image or image-version: 482 | 483 | ```shell 484 | dokku postgres:upgrade lollipop 485 | ``` 486 | 487 | Postgres does not handle upgrading data for major versions automatically (eg. 11 => 12). Upgrades should be done manually. Users are encouraged to upgrade to the latest minor release for their postgres version before performing a major upgrade. 488 | 489 | While there are many ways to upgrade a postgres database, for safety purposes, it is recommended that an upgrade is performed by exporting the data from an existing database and importing it into a new database. This also allows testing to ensure that applications interact with the database correctly after the upgrade, and can be used in a staging environment. 490 | 491 | The following is an example of how to upgrade a postgres database named `lollipop-11` from 11.13 to 12.8. 492 | 493 | ```shell 494 | # stop any linked apps 495 | dokku ps:stop linked-app 496 | 497 | # export the database contents 498 | dokku postgres:export lollipop-11 > /tmp/lollipop-11.export 499 | 500 | # create a new database at the desired version 501 | dokku postgres:create lollipop-12 --image-version 12.8 502 | 503 | # import the export file 504 | dokku postgres:import lollipop-12 < /tmp/lollipop-11.export 505 | 506 | # run any sql tests against the new database to verify the import went smoothly 507 | 508 | # unlink the old database from your apps 509 | dokku postgres:unlink lollipop-11 linked-app 510 | 511 | # link the new database to your apps 512 | dokku postgres:link lollipop-12 linked-app 513 | 514 | # start the linked apps again 515 | dokku ps:start linked-app 516 | ``` 517 | 518 | ### Service Automation 519 | 520 | Service scripting can be executed using the following commands: 521 | 522 | ### list all postgres service links for a given app 523 | 524 | ```shell 525 | # usage 526 | dokku postgres:app-links 527 | ``` 528 | 529 | List all postgres services that are linked to the `playground` app. 530 | 531 | ```shell 532 | dokku postgres:app-links playground 533 | ``` 534 | 535 | ### create container then copy data from into 536 | 537 | ```shell 538 | # usage 539 | dokku postgres:clone [--clone-flags...] 540 | ``` 541 | 542 | flags: 543 | 544 | - `-c|--config-options "--args --go=here"`: extra arguments to pass to the container create command (default: `None`) 545 | - `-C|--custom-env "USER=alpha;HOST=beta"`: semi-colon delimited environment variables to start the service with 546 | - `-i|--image IMAGE`: the image name to start the service with 547 | - `-I|--image-version IMAGE_VERSION`: the image version to start the service with 548 | - `-m|--memory MEMORY`: container memory limit in megabytes (default: unlimited) 549 | - `-N|--initial-network INITIAL_NETWORK`: the initial network to attach the service to 550 | - `-p|--password PASSWORD`: override the user-level service password 551 | - `-P|--post-create-network NETWORKS`: a comma-separated list of networks to attach the service container to after service creation 552 | - `-r|--root-password PASSWORD`: override the root-level service password 553 | - `-S|--post-start-network NETWORKS`: a comma-separated list of networks to attach the service container to after service start 554 | - `-s|--shm-size SHM_SIZE`: override shared memory size for postgres docker container 555 | 556 | You can clone an existing service to a new one: 557 | 558 | ```shell 559 | dokku postgres:clone lollipop lollipop-2 560 | ``` 561 | 562 | ### check if the postgres service exists 563 | 564 | ```shell 565 | # usage 566 | dokku postgres:exists 567 | ``` 568 | 569 | Here we check if the lollipop postgres service exists. 570 | 571 | ```shell 572 | dokku postgres:exists lollipop 573 | ``` 574 | 575 | ### check if the postgres service is linked to an app 576 | 577 | ```shell 578 | # usage 579 | dokku postgres:linked 580 | ``` 581 | 582 | Here we check if the lollipop postgres service is linked to the `playground` app. 583 | 584 | ```shell 585 | dokku postgres:linked lollipop playground 586 | ``` 587 | 588 | ### list all apps linked to the postgres service 589 | 590 | ```shell 591 | # usage 592 | dokku postgres:links 593 | ``` 594 | 595 | List all apps linked to the `lollipop` postgres service. 596 | 597 | ```shell 598 | dokku postgres:links lollipop 599 | ``` 600 | 601 | ### Data Management 602 | 603 | The underlying service data can be imported and exported with the following commands: 604 | 605 | ### import a dump into the postgres service database 606 | 607 | ```shell 608 | # usage 609 | dokku postgres:import 610 | ``` 611 | 612 | Import a datastore dump: 613 | 614 | ```shell 615 | dokku postgres:import lollipop < data.dump 616 | ``` 617 | 618 | ### export a dump of the postgres service database 619 | 620 | ```shell 621 | # usage 622 | dokku postgres:export 623 | ``` 624 | 625 | By default, datastore output is exported to stdout: 626 | 627 | ```shell 628 | dokku postgres:export lollipop 629 | ``` 630 | 631 | You can redirect this output to a file: 632 | 633 | ```shell 634 | dokku postgres:export lollipop > data.dump 635 | ``` 636 | 637 | Note that the export will result in a file containing the binary postgres export data. It can be converted to plain text using `pg_restore` as follows 638 | 639 | ```shell 640 | pg_restore data.dump -f plain.sql 641 | ``` 642 | 643 | ### Backups 644 | 645 | Datastore backups are supported via AWS S3 and S3 compatible services like [minio](https://github.com/minio/minio). 646 | 647 | 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. 648 | 649 | Backups can be performed using the backup commands: 650 | 651 | ### set up authentication for backups on the postgres service 652 | 653 | ```shell 654 | # usage 655 | dokku postgres:backup-auth 656 | ``` 657 | 658 | Setup s3 backup authentication: 659 | 660 | ```shell 661 | dokku postgres:backup-auth lollipop AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY 662 | ``` 663 | 664 | Setup s3 backup authentication with different region: 665 | 666 | ```shell 667 | dokku postgres:backup-auth lollipop AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION 668 | ``` 669 | 670 | Setup s3 backup authentication with different signature version and endpoint: 671 | 672 | ```shell 673 | dokku postgres:backup-auth lollipop AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION AWS_SIGNATURE_VERSION ENDPOINT_URL 674 | ``` 675 | 676 | More specific example for minio auth: 677 | 678 | ```shell 679 | dokku postgres:backup-auth lollipop MINIO_ACCESS_KEY_ID MINIO_SECRET_ACCESS_KEY us-east-1 s3v4 https://YOURMINIOSERVICE 680 | ``` 681 | 682 | ### remove backup authentication for the postgres service 683 | 684 | ```shell 685 | # usage 686 | dokku postgres:backup-deauth 687 | ``` 688 | 689 | Remove s3 authentication: 690 | 691 | ```shell 692 | dokku postgres:backup-deauth lollipop 693 | ``` 694 | 695 | ### create a backup of the postgres service to an existing s3 bucket 696 | 697 | ```shell 698 | # usage 699 | dokku postgres:backup [--use-iam] 700 | ``` 701 | 702 | flags: 703 | 704 | - `-u|--use-iam`: use the IAM profile associated with the current server 705 | 706 | Backup the `lollipop` service to the `my-s3-bucket` bucket on `AWS`:` 707 | 708 | ```shell 709 | dokku postgres:backup lollipop my-s3-bucket --use-iam 710 | ``` 711 | 712 | Restore a backup file (assuming it was extracted via `tar -xf backup.tgz`): 713 | 714 | ```shell 715 | dokku postgres:import lollipop < backup-folder/export 716 | ``` 717 | 718 | ### set encryption for all future backups of postgres service 719 | 720 | ```shell 721 | # usage 722 | dokku postgres:backup-set-encryption 723 | ``` 724 | 725 | Set the GPG-compatible passphrase for encrypting backups for backups: 726 | 727 | ```shell 728 | dokku postgres:backup-set-encryption lollipop 729 | ``` 730 | 731 | ### set GPG Public Key encryption for all future backups of postgres service 732 | 733 | ```shell 734 | # usage 735 | dokku postgres:backup-set-public-key-encryption 736 | ``` 737 | 738 | Set the `GPG` Public Key for encrypting backups: 739 | 740 | ```shell 741 | dokku postgres:backup-set-public-key-encryption lollipop 742 | ``` 743 | 744 | ### unset encryption for future backups of the postgres service 745 | 746 | ```shell 747 | # usage 748 | dokku postgres:backup-unset-encryption 749 | ``` 750 | 751 | Unset the `GPG` encryption passphrase for backups: 752 | 753 | ```shell 754 | dokku postgres:backup-unset-encryption lollipop 755 | ``` 756 | 757 | ### unset GPG Public Key encryption for future backups of the postgres service 758 | 759 | ```shell 760 | # usage 761 | dokku postgres:backup-unset-public-key-encryption 762 | ``` 763 | 764 | Unset the `GPG` Public Key encryption for backups: 765 | 766 | ```shell 767 | dokku postgres:backup-unset-public-key-encryption lollipop 768 | ``` 769 | 770 | ### schedule a backup of the postgres service 771 | 772 | ```shell 773 | # usage 774 | dokku postgres:backup-schedule [--use-iam] 775 | ``` 776 | 777 | flags: 778 | 779 | - `-u|--use-iam`: use the IAM profile associated with the current server 780 | 781 | Schedule a backup: 782 | 783 | > 'schedule' is a crontab expression, eg. "0 3 * * *" for each day at 3am 784 | 785 | ```shell 786 | dokku postgres:backup-schedule lollipop "0 3 * * *" my-s3-bucket 787 | ``` 788 | 789 | Schedule a backup and authenticate via iam: 790 | 791 | ```shell 792 | dokku postgres:backup-schedule lollipop "0 3 * * *" my-s3-bucket --use-iam 793 | ``` 794 | 795 | ### cat the contents of the configured backup cronfile for the service 796 | 797 | ```shell 798 | # usage 799 | dokku postgres:backup-schedule-cat 800 | ``` 801 | 802 | Cat the contents of the configured backup cronfile for the service: 803 | 804 | ```shell 805 | dokku postgres:backup-schedule-cat lollipop 806 | ``` 807 | 808 | ### unschedule the backup of the postgres service 809 | 810 | ```shell 811 | # usage 812 | dokku postgres:backup-unschedule 813 | ``` 814 | 815 | Remove the scheduled backup from cron: 816 | 817 | ```shell 818 | dokku postgres:backup-unschedule lollipop 819 | ``` 820 | 821 | ### Disabling `docker image pull` calls 822 | 823 | If you wish to disable the `docker image pull` calls that the plugin triggers, you may set the `POSTGRES_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. 824 | 825 | Please ensure the proper images are in place when `docker image pull` is disabled. 826 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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'[![Build Status](https://img.shields.io/github/actions/workflow/status/dokku/dokku-{service}/ci.yml?branch=master&style=flat-square "Build Status")](https://github.com/dokku/dokku-{service}/actions/workflows/ci.yml?query=branch%3Amaster)', 65 | f'[![IRC Network](https://img.shields.io/badge/irc-libera-blue.svg?style=flat-square "IRC Libera")](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 | "Backups can be performed using the backup commands:", 308 | "", 309 | ] 310 | 311 | return fetch_commands_content( 312 | service, 313 | variable, 314 | alias, 315 | image, 316 | scheme, 317 | ports, 318 | options, 319 | unimplemented, 320 | commands, 321 | content, 322 | ) 323 | 324 | 325 | def usage_docker_pull( 326 | service, variable, alias, image, scheme, ports, options, unimplemented 327 | ): 328 | service_prefix = service.upper() 329 | return "\n".join( 330 | [ 331 | "### Disabling `docker image pull` calls", 332 | "", 333 | 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.", 334 | "", 335 | "Please ensure the proper images are in place when `docker image pull` is disabled.", 336 | ] 337 | ) 338 | 339 | 340 | def fetch_commands_content( 341 | service, 342 | variable, 343 | alias, 344 | image, 345 | scheme, 346 | ports, 347 | options, 348 | unimplemented, 349 | commands, 350 | content, 351 | ): 352 | i = 0 353 | for command in commands: 354 | output = command_help( 355 | command, 356 | service, 357 | variable, 358 | alias, 359 | image, 360 | scheme, 361 | ports, 362 | options, 363 | unimplemented, 364 | ) 365 | if output == "": 366 | continue 367 | content.append(output) 368 | i += 1 369 | 370 | if i == 0: 371 | return "" 372 | 373 | return "\n".join(content) 374 | 375 | 376 | def parse_args(line): 377 | line = line.strip() 378 | arguments = [] 379 | for arg in re.findall("([A-Z_]+)", line): 380 | arg = arg.replace("_", "-").lower() 381 | if arg.endswith("optional-flag"): 382 | arg = arg.replace("-optional-flag", "") 383 | arguments.append(f"[--{arg}]") 384 | elif arg.endswith("-flag"): 385 | if arg == "info-flag": 386 | arguments.append(f"[--single-info-flag]") 387 | else: 388 | arg = arg.replace("-flag", "") 389 | first_letter = arg[0] 390 | arguments.append(f"[-{first_letter}|--{arg}]") 391 | elif arg.endswith("-flags-list"): 392 | arg = arg.replace("-list", "") 393 | arguments.append(f"[--{arg}...]") 394 | elif arg.endswith("list"): 395 | arg = arg.replace("-list", "") 396 | arguments.append(f"<{arg}...>") 397 | else: 398 | arguments.append(f"<{arg}>") 399 | return " ".join(arguments) 400 | 401 | 402 | def command_help( 403 | command, service, variable, alias, image, scheme, ports, options, unimplemented 404 | ): 405 | if command in unimplemented: 406 | return "" 407 | 408 | data = command_data(command, service, variable, alias, image, scheme, ports) 409 | content = [ 410 | f"### {data['description']}", 411 | "", 412 | "```shell", 413 | "# usage", 414 | f"dokku {service}:{command} {data['arguments_string']}".strip(), 415 | "```", 416 | ] 417 | 418 | # if len(data["arguments"]) > 0: 419 | # content.append("") 420 | # content.append("arguments:") 421 | # content.append("") 422 | # for argument in data["arguments"]: 423 | # content.append(f"- {argument}") 424 | 425 | if len(data["flags"]) > 0: 426 | content.append("") 427 | content.append("flags:") 428 | content.append("") 429 | for flag in data["flags"]: 430 | if "--config-options" in flag and options != "": 431 | flag = f"{flag} (default: `{options}`)" 432 | content.append(f"- {flag}") 433 | 434 | if len(data["examples"]) > 0: 435 | content.append("") 436 | content.append(data["examples"]) 437 | 438 | doc_file = os.path.join("docs", f"{command}.md") 439 | if os.path.isfile(doc_file): 440 | content.append("") 441 | with open(doc_file) as f: 442 | content.append(f.read()) 443 | 444 | return "\n" + "\n".join(content) 445 | 446 | 447 | def command_data(command, service, variable, alias, image, scheme, ports): 448 | description = None 449 | arguments = [] 450 | arguments_string = "" 451 | example_lines = [] 452 | flags = [] 453 | with open(os.path.join("subcommands", command)) as f: 454 | for line in f.readlines(): 455 | line = line.strip() 456 | line = line.replace("$PLUGIN_SERVICE", service) 457 | line = line.replace("$PLUGIN_COMMAND_PREFIX", service) 458 | line = line.replace("${PLUGIN_COMMAND_PREFIX}", service) 459 | line = line.replace("${PLUGIN_VARIABLE}", variable) 460 | line = line.replace("${PLUGIN_DEFAULT_ALIAS}", alias) 461 | line = line.replace("${PLUGIN_IMAGE}", image) 462 | line = line.replace("${PLUGIN_SCHEME}", scheme) 463 | line = line.replace("${PLUGIN_DATASTORE_PORTS[0]}", ports[0]) 464 | line = line.replace("${PLUGIN_DATASTORE_PORTS[@]}", " ".join(ports)) 465 | 466 | if "declare desc" in line: 467 | description = re.search('"(.+)"', line).group(1) 468 | elif "$1" in line: 469 | arguments_string = parse_args(line) 470 | elif line.startswith("#A "): 471 | argument = line.replace("#A ", "") 472 | parts = [a.strip() for a in argument.split(",", 1)] 473 | arguments.append(f"`{parts[0]}`: {parts[1]}") 474 | elif line.startswith("#F "): 475 | flag = line.replace("#F ", "") 476 | parts = [a.strip() for a in flag.split(",", 1)] 477 | flags.append(f"`{parts[0]}`: {parts[1]}") 478 | elif line.startswith("#E "): 479 | example_lines.append(line.replace("#E ", "")) 480 | 481 | examples = [] 482 | sentence_lines = [] 483 | command_lines = [] 484 | codeblock_lines = [] 485 | blockquote_lines = [] 486 | for line in example_lines: 487 | if line.startswith("export") or line.startswith("dokku"): 488 | if len(blockquote_lines) > 0: 489 | examples.append("\n" + process_blockquote(blockquote_lines)) 490 | blockquote_lines = [] 491 | if len(codeblock_lines) > 0: 492 | examples.append("\n" + process_codeblock(codeblock_lines)) 493 | codeblock_lines = [] 494 | if len(sentence_lines) > 0: 495 | examples.append("\n" + process_sentence(sentence_lines)) 496 | sentence_lines = [] 497 | 498 | command_lines.append(line) 499 | elif line.startswith(" "): 500 | if len(blockquote_lines) > 0: 501 | examples.append("\n" + process_blockquote(blockquote_lines)) 502 | blockquote_lines = [] 503 | if len(command_lines) > 0: 504 | examples.append("\n" + process_command(command_lines)) 505 | command_lines = [] 506 | if len(sentence_lines) > 0: 507 | examples.append("\n" + process_sentence(sentence_lines)) 508 | sentence_lines = [] 509 | 510 | codeblock_lines.append(line.strip()) 511 | elif line.startswith(">"): 512 | if len(codeblock_lines) > 0: 513 | examples.append("\n" + process_codeblock(codeblock_lines)) 514 | codeblock_lines = [] 515 | if len(command_lines) > 0: 516 | examples.append("\n" + process_command(command_lines)) 517 | command_lines = [] 518 | if len(sentence_lines) > 0: 519 | examples.append("\n" + process_sentence(sentence_lines)) 520 | sentence_lines = [] 521 | 522 | blockquote_lines.append(line) 523 | else: 524 | if len(blockquote_lines) > 0: 525 | examples.append("\n" + process_blockquote(blockquote_lines)) 526 | blockquote_lines = [] 527 | if len(codeblock_lines) > 0: 528 | examples.append("\n" + process_codeblock(codeblock_lines)) 529 | codeblock_lines = [] 530 | if len(command_lines) > 0: 531 | examples.append("\n" + process_command(command_lines)) 532 | command_lines = [] 533 | 534 | sentence_lines.append(line) 535 | 536 | if len(blockquote_lines) > 0: 537 | examples.append("\n" + process_blockquote(blockquote_lines)) 538 | blockquote_lines = [] 539 | if len(codeblock_lines) > 0: 540 | examples.append("\n" + process_codeblock(codeblock_lines)) 541 | codeblock_lines = [] 542 | if len(command_lines) > 0: 543 | examples.append("\n" + process_command(command_lines)) 544 | command_lines = [] 545 | if len(sentence_lines) > 0: 546 | examples.append("\n" + process_sentence(sentence_lines)) 547 | sentence_lines = [] 548 | 549 | return { 550 | "description": description, 551 | "arguments_string": arguments_string, 552 | "arguments": arguments, 553 | "flags": flags, 554 | "examples": "\n".join(examples).strip(), 555 | } 556 | 557 | 558 | def process_sentence(sentence_lines): 559 | sentence_lines = " ".join(sentence_lines) 560 | sentences = ". ".join( 561 | upperfirst(i.strip()) for i in sentence_lines.split(". ") 562 | ).strip() 563 | if not sentences.endswith(".") and not sentences.endswith(":"): 564 | sentences += ":" 565 | 566 | text = [] 567 | for sentence in sentences.split(". "): 568 | parts = [] 569 | for word in sentence.strip().split(" "): 570 | if word.isupper() and len(word) > 1: 571 | for ending in [":", "."]: 572 | if word.endswith(ending): 573 | word = "`{0}`{1}".format(word[:-1], ending) 574 | else: 575 | word = "`{0}`".format(word) 576 | parts.append(word) 577 | text.append(" ".join(parts)) 578 | 579 | text = ". ".join(text) 580 | 581 | # some cleanup 582 | text = text.replace("(0.0.0.0)", "(`0.0.0.0`)") 583 | text = text.replace("'", "`") 584 | text = text.replace("`s", "'s") 585 | text = text.replace("``", "`") 586 | text = text.strip(" ") 587 | 588 | return text 589 | 590 | 591 | def upperfirst(x): 592 | return x[:1].upper() + x[1:] 593 | 594 | 595 | def process_blockquote(blockquote_lines): 596 | return "\n".join(blockquote_lines) 597 | 598 | 599 | def process_command(command_lines): 600 | command_lines = "\n".join(command_lines) 601 | return f"```shell\n{command_lines}\n```" 602 | 603 | 604 | def process_codeblock(codeblock_lines): 605 | codeblock_lines = "\n".join(codeblock_lines) 606 | return f"```\n{codeblock_lines}\n```" 607 | 608 | 609 | def main(): 610 | service = None 611 | version = None 612 | variable = None 613 | image = None 614 | alias = None 615 | options = None 616 | unimplemented = [] 617 | 618 | with open("Dockerfile") as f: 619 | for line in f.readlines(): 620 | if "FROM " in line: 621 | image, version = line.split(" ")[1].split(":") 622 | image = image.strip() 623 | version = version.strip() 624 | 625 | with open("config") as f: 626 | for line in f.readlines(): 627 | if "PLUGIN_COMMAND_PREFIX=" in line: 628 | service = re.search('"(.+)"', line).group(1) 629 | if "PLUGIN_DEFAULT_ALIAS=" in line: 630 | alias = re.search('"(.+)"', line).group(1) 631 | if "PLUGIN_VARIABLE=" in line: 632 | variable = re.search('"(.+)"', line).group(1) 633 | if "PLUGIN_SCHEME=" in line: 634 | scheme = re.search('"(.+)"', line).group(1) 635 | if "PLUGIN_DATASTORE_PORTS=" in line: 636 | ports = re.search("\((.+)\)", line).group(1).split(" ") 637 | if "PLUGIN_UNIMPLEMENTED_SUBCOMMANDS=" in line: 638 | match = re.search("\((.+)\)", line) 639 | if match is not None: 640 | unimplemented = [s.strip('"') for s in match.group(1).split(" ")] 641 | 642 | with open("config") as f: 643 | for line in f.readlines(): 644 | if f"{variable}_CONFIG_OPTIONS" in line: 645 | match = re.search('"(.+)"', line) 646 | if match is not None: 647 | options = match.group(1) 648 | 649 | sponsors = [] 650 | with open("plugin.toml") as f: 651 | for line in f.readlines(): 652 | if line.startswith("sponsors"): 653 | sponsors = re.search('\[(["\w\s,_-]+)\]', line).group(1) 654 | sponsors = [s.strip('"') for s in sponsors.split(",")] 655 | 656 | text = compile( 657 | service, 658 | version, 659 | variable, 660 | alias, 661 | image, 662 | scheme, 663 | ports, 664 | sponsors, 665 | options, 666 | unimplemented, 667 | "0.19.x+", 668 | ) 669 | 670 | base_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 671 | readme_file = os.path.join(base_path, "README.md") 672 | with open(readme_file, "w") as f: 673 | f.write(text + "\n") 674 | 675 | 676 | if __name__ == "__main__": 677 | main() 678 | -------------------------------------------------------------------------------- /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 | if [[ ! -d $PLUGIN_CONFIG_ROOT ]]; then 12 | dokku_log_fail "$PLUGIN_SERVICE: Please run: sudo dokku plugin:install" 13 | fi 14 | 15 | if [[ ! -d $PLUGIN_DATA_ROOT ]]; then 16 | dokku_log_fail "$PLUGIN_SERVICE: Please run: sudo dokku plugin:install" 17 | fi 18 | 19 | fn-help "$@" 20 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | _DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 3 | export POSTGRES_IMAGE=${POSTGRES_IMAGE:="$(awk -F '[ :]' '{print $2}' "${_DIR}/Dockerfile")"} 4 | export POSTGRES_IMAGE_VERSION=${POSTGRES_IMAGE_VERSION:="$(awk -F '[ :]' '{print $3}' "${_DIR}/Dockerfile")"} 5 | export POSTGRES_ROOT=${POSTGRES_ROOT:="$DOKKU_LIB_ROOT/services/postgres"} 6 | export DOKKU_LIB_HOST_ROOT=${DOKKU_LIB_HOST_ROOT:=$DOKKU_LIB_ROOT} 7 | export POSTGRES_HOST_ROOT=${POSTGRES_HOST_ROOT:="$DOKKU_LIB_HOST_ROOT/services/postgres"} 8 | 9 | export PLUGIN_UNIMPLEMENTED_SUBCOMMANDS=() 10 | export PLUGIN_COMMAND_PREFIX="postgres" 11 | export PLUGIN_CONFIG_ROOT=${PLUGIN_CONFIG_ROOT:="$DOKKU_LIB_ROOT/config/$PLUGIN_COMMAND_PREFIX"} 12 | export PLUGIN_DATA_ROOT=$POSTGRES_ROOT 13 | export PLUGIN_DATA_HOST_ROOT=$POSTGRES_HOST_ROOT 14 | export PLUGIN_DATASTORE_PORTS=(5432) 15 | export PLUGIN_DATASTORE_WAIT_PORT=5432 16 | export PLUGIN_DEFAULT_ALIAS="DATABASE" 17 | export PLUGIN_DISABLE_PULL=${POSTGRES_DISABLE_PULL:=} 18 | export PLUGIN_DISABLE_PULL_VARIABLE="POSTGRES_DISABLE_PULL" 19 | export PLUGIN_ALT_ALIAS="DOKKU_POSTGRES" 20 | export PLUGIN_IMAGE=$POSTGRES_IMAGE 21 | export PLUGIN_IMAGE_VERSION=$POSTGRES_IMAGE_VERSION 22 | export PLUGIN_SCHEME="postgres" 23 | export PLUGIN_SERVICE="Postgres" 24 | export PLUGIN_VARIABLE="POSTGRES" 25 | export PLUGIN_BASE_PATH="$PLUGIN_PATH" 26 | export PLUGIN_CONFIG_SUFFIX="data" 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 POSTGRES_CONFIG_OPTIONS=${POSTGRES_CONFIG_OPTIONS:=""} 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /docs/create.md: -------------------------------------------------------------------------------- 1 | Official Postgres "$DOCKER_BIN" image ls does not include postgis extension (amongst others). The following example creates a new postgres service using `postgis/postgis:13-3.1` image, which includes the `postgis` extension. 2 | 3 | ```shell 4 | # use the appropriate image-version for your use-case 5 | dokku postgres:create postgis-database --image "postgis/postgis" --image-version "13-3.1" 6 | ``` 7 | 8 | To use pgvector instead, run the following: 9 | 10 | ```shell 11 | # use the appropriate image-version for your use-case 12 | dokku postgres:create pgvector-database --image "pgvector/pgvector" --image-version "pg17" 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/export.md: -------------------------------------------------------------------------------- 1 | Note that the export will result in a file containing the binary postgres export data. It can be converted to plain text using `pg_restore` as follows 2 | 3 | ```shell 4 | pg_restore data.dump -f plain.sql 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/upgrade.md: -------------------------------------------------------------------------------- 1 | Postgres does not handle upgrading data for major versions automatically (eg. 11 => 12). Upgrades should be done manually. Users are encouraged to upgrade to the latest minor release for their postgres version before performing a major upgrade. 2 | 3 | While there are many ways to upgrade a postgres database, for safety purposes, it is recommended that an upgrade is performed by exporting the data from an existing database and importing it into a new database. This also allows testing to ensure that applications interact with the database correctly after the upgrade, and can be used in a staging environment. 4 | 5 | The following is an example of how to upgrade a postgres database named `lollipop-11` from 11.13 to 12.8. 6 | 7 | ```shell 8 | # stop any linked apps 9 | dokku ps:stop linked-app 10 | 11 | # export the database contents 12 | dokku postgres:export lollipop-11 > /tmp/lollipop-11.export 13 | 14 | # create a new database at the desired version 15 | dokku postgres:create lollipop-12 --image-version 12.8 16 | 17 | # import the export file 18 | dokku postgres:import lollipop-12 < /tmp/lollipop-11.export 19 | 20 | # run any sql tests against the new database to verify the import went smoothly 21 | 22 | # unlink the old database from your apps 23 | dokku postgres:unlink lollipop-11 linked-app 24 | 25 | # link the new database to your apps 26 | dokku postgres:link lollipop-12 linked-app 27 | 28 | # start the linked apps again 29 | dokku ps:start linked-app 30 | ``` 31 | -------------------------------------------------------------------------------- /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 DATABASE_NAME="$(get_database_name "$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" psql -v ON_ERROR_STOP=1 -h localhost -U postgres "$DATABASE_NAME" 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 | touch "$LINKS_FILE" 48 | 49 | PASSWORD=$(openssl rand -hex 16) 50 | if [[ -n "$SERVICE_PASSWORD" ]]; then 51 | PASSWORD="$SERVICE_PASSWORD" 52 | dokku_log_warn "Specified password may not be as secure as the auto-generated password" 53 | fi 54 | echo "$PASSWORD" >"$SERVICE_ROOT/PASSWORD" 55 | chmod 640 "$SERVICE_ROOT/PASSWORD" 56 | 57 | service_commit_config "$SERVICE" 58 | write_database_name "$SERVICE" 59 | plugn trigger service-action post-create "$PLUGIN_COMMAND_PREFIX" "$SERVICE" 60 | service_create_container "$SERVICE" 61 | plugn trigger service-action post-create-complete "$PLUGIN_COMMAND_PREFIX" "$SERVICE" 62 | } 63 | 64 | service_create_container() { 65 | local SERVICE="$1" 66 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" 67 | local SERVICE_HOST_ROOT="$PLUGIN_DATA_HOST_ROOT/$SERVICE" 68 | local SERVICE_NAME="$(get_service_name "$SERVICE")" 69 | local PASSWORD="$(service_password "$SERVICE")" 70 | local DATABASE_NAME="$(get_database_name "$SERVICE")" 71 | local PREVIOUS_ID 72 | 73 | if [[ -f "$SERVICE_ROOT/CONFIG_OPTIONS" ]]; then 74 | export CONFIG_OPTIONS="$(cat "$SERVICE_ROOT/CONFIG_OPTIONS")" 75 | fi 76 | 77 | local network_alias="$(service_dns_hostname "$SERVICE")" 78 | 79 | rm -f "$SERVICE_ROOT/ID" 80 | declare -a DOCKER_ARGS 81 | DOCKER_ARGS=() 82 | DOCKER_ARGS+=("--cidfile=$SERVICE_ROOT/ID") 83 | DOCKER_ARGS+=("--env-file=$SERVICE_ROOT/ENV") 84 | DOCKER_ARGS+=("--env=POSTGRES_PASSWORD=$PASSWORD") 85 | DOCKER_ARGS+=("--hostname=$SERVICE_NAME") 86 | DOCKER_ARGS+=("--label=dokku.service=$PLUGIN_COMMAND_PREFIX") 87 | DOCKER_ARGS+=("--label=dokku=service") 88 | DOCKER_ARGS+=("--name=$SERVICE_NAME") 89 | DOCKER_ARGS+=("--restart=always") 90 | DOCKER_ARGS+=("--volume=$SERVICE_HOST_ROOT/data:/var/lib/postgresql/data") 91 | 92 | declare -a LINK_CONTAINER_DOCKER_ARGS 93 | LINK_CONTAINER_DOCKER_ARGS=() 94 | LINK_CONTAINER_DOCKER_ARGS+=("--rm") 95 | LINK_CONTAINER_DOCKER_ARGS+=("--link") 96 | LINK_CONTAINER_DOCKER_ARGS+=("$SERVICE_NAME:$network_alias") 97 | 98 | [[ -f "$SERVICE_ROOT/SERVICE_MEMORY" ]] && SERVICE_MEMORY="$(cat "$SERVICE_ROOT/SERVICE_MEMORY")" 99 | if [[ -n "$SERVICE_MEMORY" ]]; then 100 | DOCKER_ARGS+=("--memory=${SERVICE_MEMORY}m") 101 | fi 102 | 103 | [[ -f "$SERVICE_ROOT/SHM_SIZE" ]] && SERVICE_SHM_SIZE="$(cat "$SERVICE_ROOT/SHM_SIZE")" 104 | if [[ -n "$SERVICE_SHM_SIZE" ]]; then 105 | DOCKER_ARGS+=("--shm-size=${SERVICE_SHM_SIZE}") 106 | fi 107 | 108 | [[ -f "$SERVICE_ROOT/IMAGE" ]] && PLUGIN_IMAGE="$(cat "$SERVICE_ROOT/IMAGE")" 109 | [[ -f "$SERVICE_ROOT/IMAGE_VERSION" ]] && PLUGIN_IMAGE_VERSION="$(cat "$SERVICE_ROOT/IMAGE_VERSION")" 110 | 111 | local network="$(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "initial-network")" 112 | if [[ -n "$network" ]]; then 113 | DOCKER_ARGS+=("--network=${network}") 114 | DOCKER_ARGS+=("--network-alias=${network_alias}") 115 | LINK_CONTAINER_DOCKER_ARGS+=("--network=${network}") 116 | fi 117 | 118 | # shellcheck disable=SC2086 119 | suppress_output "$DOCKER_BIN" container create "${DOCKER_ARGS[@]}" "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" $CONFIG_OPTIONS 120 | 121 | if [[ -n "$(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-create-network")" ]]; then 122 | dokku_log_verbose_quiet "Connecting to networks after container create" 123 | while read -r line || [[ -n "$line" ]]; do 124 | dokku_log_verbose_quiet "- $line" 125 | "$DOCKER_BIN" network connect --alias "$network_alias" "$line" "$SERVICE_NAME" 126 | done < <(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-create-network" | tr "," "\n") 127 | fi 128 | suppress_output "$DOCKER_BIN" container start "$(cat "$SERVICE_ROOT/ID")" 129 | service_port_reconcile_status "$SERVICE" 130 | 131 | if [[ -n "$(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-start-network")" ]]; then 132 | dokku_log_verbose_quiet "Connecting to networks after container start" 133 | while read -r line || [[ -n "$line" ]]; do 134 | dokku_log_verbose_quiet "- $line" 135 | "$DOCKER_BIN" network connect --alias "$network_alias" "$line" "$SERVICE_NAME" 136 | done < <(fn-plugin-property-get "$PLUGIN_COMMAND_PREFIX" "$SERVICE" "post-start-network" | tr "," "\n") 137 | fi 138 | 139 | dokku_log_verbose_quiet "Waiting for container to be ready" 140 | if ! suppress_output "$DOCKER_BIN" container run "${LINK_CONTAINER_DOCKER_ARGS[@]}" "$PLUGIN_WAIT_IMAGE" -c "$network_alias:$PLUGIN_DATASTORE_WAIT_PORT"; then 141 | dokku_log_info2_quiet "Start of $SERVICE container output" 142 | dokku_container_log_verbose_quiet "$SERVICE_NAME" 143 | dokku_log_info2_quiet "End of $SERVICE container output" 144 | return 1 145 | fi 146 | 147 | dokku_log_verbose_quiet "Creating container database" 148 | "$DOCKER_BIN" container exec "$SERVICE_NAME" su - postgres -c "createdb -E utf8 $DATABASE_NAME" 2>/dev/null || dokku_log_verbose_quiet 'Already exists' 149 | 150 | dokku_log_verbose_quiet "Securing connection to database" 151 | service_pause "$SERVICE" >/dev/null 152 | "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/scripts/create_ssl_certs.sh" "$SERVICE_ROOT" &>/dev/null 153 | "$DOCKER_BIN" container run --rm -i -v "$SERVICE_HOST_ROOT/data:/var/lib/postgresql/data" -v "$SERVICE_HOST_ROOT/certs:/var/lib/postgresql/certs" "$PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION" bash -s <"$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/scripts/enable_ssl.sh" &>/dev/null 154 | rm -rf "$SERVICE_HOST_ROOT/certs" 155 | 156 | suppress_output "$DOCKER_BIN" container start "$(cat "$SERVICE_ROOT/ID")" 157 | service_port_reconcile_status "$SERVICE" 158 | 159 | dokku_log_info2 "$PLUGIN_SERVICE container created: $SERVICE" 160 | service_info "$SERVICE" 161 | } 162 | 163 | service_export() { 164 | local SERVICE="$1" 165 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" 166 | local SERVICE_NAME="$(get_service_name "$SERVICE")" 167 | local DATABASE_NAME="$(get_database_name "$SERVICE")" 168 | local PASSWORD="$(service_password "$SERVICE")" 169 | 170 | [[ -n $SSH_TTY ]] && stty -opost 171 | "$DOCKER_BIN" container exec "$SERVICE_NAME" env PGPASSWORD="$PASSWORD" pg_dump -Fc --no-acl --no-owner -h localhost -U postgres -w "$DATABASE_NAME" 172 | status=$? 173 | [[ -n $SSH_TTY ]] && stty opost 174 | exit $status 175 | } 176 | 177 | service_import() { 178 | local SERVICE="$1" 179 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" 180 | local SERVICE_HOST_ROOT="$PLUGIN_DATA_HOST_ROOT/$SERVICE" 181 | local SERVICE_NAME="$(get_service_name "$SERVICE")" 182 | local DATABASE_NAME="$(get_database_name "$SERVICE")" 183 | local PASSWORD="$(service_password "$SERVICE")" 184 | 185 | if [[ -t 0 ]]; then 186 | dokku_log_fail "No data provided on stdin." 187 | fi 188 | "$DOCKER_BIN" container exec -i "$SERVICE_NAME" env PGPASSWORD="$PASSWORD" pg_restore -h localhost -cO --if-exists -d "$DATABASE_NAME" -U postgres -w 189 | } 190 | 191 | service_start() { 192 | local SERVICE="$1" 193 | local QUIET="$2" 194 | local SERVICE_ROOT="$PLUGIN_DATA_ROOT/$SERVICE" 195 | local SERVICE_NAME="$(get_service_name "$SERVICE")" 196 | local ID=$("$DOCKER_BIN" container ps -aq --no-trunc --filter "status=running" --filter "name=^/$SERVICE_NAME$") || true 197 | if [[ -n $ID ]]; then 198 | [[ -z $QUIET ]] && dokku_log_warn "Service is already started" 199 | if [[ ! -f "$SERVICE_ROOT/ID" ]] || [[ "$(cat "$SERVICE_ROOT/ID")" != "$ID" ]]; then 200 | [[ -z $QUIET ]] && dokku_log_warn "Updating local container ID" 201 | echo "$ID" >"$SERVICE_ROOT/ID" 202 | fi 203 | return 0 204 | fi 205 | 206 | dokku_log_info2_quiet "Starting container" 207 | local PREVIOUS_ID=$("$DOCKER_BIN" container ps -aq --no-trunc --filter "status=exited" --filter "name=^/$SERVICE_NAME$") || true 208 | local PASSWORD="$(service_password "$SERVICE")" 209 | 210 | if [[ -n $PREVIOUS_ID ]]; then 211 | "$DOCKER_BIN" container start "$PREVIOUS_ID" >/dev/null 212 | service_port_reconcile_status "$SERVICE" 213 | dokku_log_info2 "Container started" 214 | elif service_image_exists "$SERVICE" && [[ -n "$PASSWORD" ]]; then 215 | service_create_container "$SERVICE" 216 | else 217 | if ! service_image_exists "$SERVICE"; then 218 | [[ -f "$SERVICE_ROOT/IMAGE" ]] && PLUGIN_IMAGE="$(cat "$SERVICE_ROOT/IMAGE")" 219 | [[ -f "$SERVICE_ROOT/IMAGE_VERSION" ]] && PLUGIN_IMAGE_VERSION="$(cat "$SERVICE_ROOT/IMAGE_VERSION")" 220 | dokku_log_verbose_quiet "Missing image $PLUGIN_IMAGE:$PLUGIN_IMAGE_VERSION for $SERVICE" 221 | else 222 | dokku_log_verbose_quiet "Neither container nor valid configuration exists for $SERVICE" 223 | fi 224 | fi 225 | } 226 | 227 | service_url() { 228 | local SERVICE="$1" 229 | local SERVICE_DNS_HOSTNAME="$(service_dns_hostname "$SERVICE")" 230 | local DATABASE_NAME="$(get_database_name "$SERVICE")" 231 | local PASSWORD="$(service_password "$SERVICE")" 232 | echo "$PLUGIN_SCHEME://postgres:$PASSWORD@$SERVICE_DNS_HOSTNAME:${PLUGIN_DATASTORE_PORTS[0]}/$DATABASE_NAME" 233 | } 234 | -------------------------------------------------------------------------------- /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 <* ]] && 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plugin.toml: -------------------------------------------------------------------------------- 1 | [plugin] 2 | description = "dokku postgres service plugin" 3 | version = "1.44.0" 4 | [plugin.config] 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/create_ssl_certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | postgres_service_dir="$1" 6 | 7 | cd "$postgres_service_dir" 8 | mkdir certs && cd certs 9 | openssl req -new -newkey rsa:4096 -x509 -days 365000 -nodes -out server.crt -keyout server.key -batch 10 | -------------------------------------------------------------------------------- /scripts/enable_ssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | cd /var/lib/postgresql/data 6 | 7 | cp ../certs/* . 8 | chown postgres:postgres server.key 9 | chmod 600 server.key 10 | 11 | sed -i "s/^#ssl = off/ssl = on/" postgresql.conf 12 | sed -i "s/^#ssl_ciphers =.*/ssl_ciphers = 'AES256+EECDH:AES256+EDH'/" postgresql.conf 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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-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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | #A service, service to run command against 12 | #A passphrase, a GPG-compatible passphrase 13 | declare desc="set encryption for all future backups of $PLUGIN_SERVICE service" 14 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-set-encryption" argv=("$@") 15 | [[ ${argv[0]} == "$cmd" ]] && shift 1 16 | declare SERVICE="$1" PASSPHRASE="$2" 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 | [[ -z "$PASSPHRASE" ]] && dokku_log_fail "Please specify a GPG backup passphrase" 21 | verify_service_name "$SERVICE" 22 | service_backup_set_encryption "$SERVICE" "$PASSPHRASE" 23 | } 24 | 25 | service-backup-set-encryption-cmd "$@" 26 | -------------------------------------------------------------------------------- /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 | #A service, service to run command against 12 | #A public-key-id, a GPG Public Key ID (or fingerprint) to use for encryption. Must be uploaded to the GPG keyserver beforehand. 13 | declare desc="set GPG Public Key encryption for all future backups of $PLUGIN_SERVICE service" 14 | local cmd="$PLUGIN_COMMAND_PREFIX:backup-set-public-key-encryption" argv=("$@") 15 | [[ ${argv[0]} == "$cmd" ]] && shift 1 16 | declare SERVICE="$1" PUBLIC_KEY_ID="$2" 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 | [[ -z "$PUBLIC_KEY_ID" ]] && dokku_log_fail "Please specify a valid GPG Public Key ID (or fingerprint)" 21 | verify_service_name "$SERVICE" 22 | service_backup_set_public_key_encryption "$SERVICE" "$PUBLIC_KEY_ID" 23 | } 24 | 25 | service-backup-set-public-key-encryption-cmd "$@" 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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" # TODO: [22.03.2024 by Mykola] 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" # TODO: [22.03.2024 by Mykola] 21 | } 22 | 23 | service-backup-unset-encryption-cmd "$@" 24 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | #A service, service to run command against 42 | #A app, app to run command against 43 | #F -a|--alias "BLUE_DATABASE", an alternative alias to use for linking to an app via environment variable 44 | #F -q|--querystring "pool=5", ampersand delimited querystring arguments to append to the service link 45 | #F -n|--no-restart "false", whether or not to restart the app on link (default: true) 46 | declare desc="link the $PLUGIN_SERVICE service to the app" 47 | local cmd="$PLUGIN_COMMAND_PREFIX:link" argv=("$@") 48 | [[ ${argv[0]} == "$cmd" ]] && shift 1 49 | declare SERVICE="$1" APP="$2" LINK_FLAGS_LIST=("${@:3}") 50 | APP=${APP:="$DOKKU_APP_NAME"} 51 | 52 | [[ -z "$SERVICE" ]] && dokku_log_fail "Please specify a valid name for the service" 53 | [[ -z "$APP" ]] && dokku_log_fail "Please specify an app to run the command on" 54 | verify_app_name "$APP" 55 | verify_service_name "$SERVICE" 56 | 57 | service_parse_args "${@:3}" 58 | service_link "$SERVICE" "$APP" 59 | } 60 | 61 | service-link-cmd "$@" 62 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /tests/service_clone.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:clone) error when there are no arguments" { 13 | run dokku "$PLUGIN_COMMAND_PREFIX:clone" 14 | assert_contains "${lines[*]}" "Please specify a valid name for the service" 15 | assert_failure 16 | } 17 | 18 | @test "($PLUGIN_COMMAND_PREFIX:clone) error when service does not exist" { 19 | run dokku "$PLUGIN_COMMAND_PREFIX:clone" not_existing_service new_service 20 | assert_contains "${lines[*]}" "service not_existing_service does not exist" 21 | assert_failure 22 | } 23 | 24 | @test "($PLUGIN_COMMAND_PREFIX:clone) error when new service isn't provided" { 25 | run dokku "$PLUGIN_COMMAND_PREFIX:clone" l 26 | assert_contains "${lines[*]}" "Please specify a name for the new service" 27 | assert_failure 28 | } 29 | 30 | @test "($PLUGIN_COMMAND_PREFIX:clone) error when new service already exists" { 31 | dokku "$PLUGIN_COMMAND_PREFIX:create" new_service 32 | run dokku "$PLUGIN_COMMAND_PREFIX:clone" l new_service 33 | assert_contains "${lines[*]}" "Invalid service name new_service" 34 | assert_failure 35 | 36 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" new_service 37 | } 38 | 39 | @test "($PLUGIN_COMMAND_PREFIX:clone) success" { 40 | run dokku "$PLUGIN_COMMAND_PREFIX:clone" l new_service 41 | [[ -f $PLUGIN_DATA_ROOT/new_service/ID ]] 42 | assert_contains "${lines[*]}" "Copying data from l to new_service" 43 | assert_contains "${lines[*]}" "Done" 44 | assert_success 45 | 46 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" new_service 47 | } 48 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests/service_export.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:export) error when there are no arguments" { 13 | run dokku "$PLUGIN_COMMAND_PREFIX:export" 14 | assert_contains "${lines[*]}" "Please specify a valid name for the service" 15 | } 16 | 17 | @test "($PLUGIN_COMMAND_PREFIX:export) error when service does not exist" { 18 | run dokku "$PLUGIN_COMMAND_PREFIX:export" not_existing_service 19 | assert_contains "${lines[*]}" "service not_existing_service does not exist" 20 | } 21 | 22 | @test "($PLUGIN_COMMAND_PREFIX:export) success with SSH_TTY" { 23 | if [[ -n "$GITHUB_WORKFLOW" ]]; then 24 | skip "No tty is available on Github Actions" 25 | fi 26 | export SSH_TTY=$(tty) 27 | run dokku "$PLUGIN_COMMAND_PREFIX:export" l 28 | echo "output: $output" 29 | echo "status: $status" 30 | assert_exit_status 0 31 | } 32 | 33 | @test "($PLUGIN_COMMAND_PREFIX:export) success without SSH_TTY" { 34 | unset SSH_TTY 35 | run dokku "$PLUGIN_COMMAND_PREFIX:export" l 36 | echo "output: $output" 37 | echo "status: $status" 38 | assert_exit_status 0 39 | } 40 | -------------------------------------------------------------------------------- /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 62 | echo "output: $output" 63 | echo "status: $status" 64 | assert_success 65 | assert_contains "${lines[*]}" "exposed on port(s) [container->host]: 5432->4242" 66 | } 67 | -------------------------------------------------------------------------------- /tests/service_import.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | load test_helper 3 | 4 | setup() { 5 | dokku "$PLUGIN_COMMAND_PREFIX:create" l 6 | echo "data" | tee "/tmp/fake.dump" 7 | } 8 | 9 | teardown() { 10 | dokku --force "$PLUGIN_COMMAND_PREFIX:destroy" l 11 | rm -f "/tmp/fake.dump" 12 | } 13 | 14 | @test "($PLUGIN_COMMAND_PREFIX:import) error when there are no arguments" { 15 | run dokku "$PLUGIN_COMMAND_PREFIX:import" 16 | assert_contains "${lines[*]}" "Please specify a valid name for the service" 17 | assert_failure 18 | } 19 | 20 | @test "($PLUGIN_COMMAND_PREFIX:import) error when service does not exist" { 21 | run dokku "$PLUGIN_COMMAND_PREFIX:import" not_existing_service 22 | assert_contains "${lines[*]}" "service not_existing_service does not exist" 23 | assert_failure 24 | } 25 | 26 | @test "($PLUGIN_COMMAND_PREFIX:import) error when data is not provided" { 27 | if [[ -n "$GITHUB_WORKFLOW" ]]; then 28 | skip "No tty is available on Github Actions" 29 | fi 30 | run dokku "$PLUGIN_COMMAND_PREFIX:import" l 31 | assert_contains "${lines[*]}" "No data provided on stdin" 32 | assert_failure 33 | } 34 | 35 | @test "($PLUGIN_COMMAND_PREFIX:import) success" { 36 | skip "The fake dump is hard to work with in tests" 37 | run dokku "$PLUGIN_COMMAND_PREFIX:import" l <"/tmp/fake.dump" 38 | echo "output: $output" 39 | echo "status: $status" 40 | assert_success 41 | } 42 | -------------------------------------------------------------------------------- /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[*]}" "postgres://postgres:$password@dokku-postgres-l:5432/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[*]}" "postgres://postgres:$password@dokku-postgres-test-with-underscores:5432/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 "postgres://postgres:$password@dokku-postgres-l:5432/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 --status 66 | assert_success 67 | 68 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --version 69 | assert_success 70 | } 71 | 72 | @test "($PLUGIN_COMMAND_PREFIX:info) error when invalid flag" { 73 | run dokku "$PLUGIN_COMMAND_PREFIX:info" l --invalid-flag 74 | assert_failure 75 | } 76 | -------------------------------------------------------------------------------- /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 DATABASE_URL" 54 | assert_failure 55 | 56 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app 57 | } 58 | 59 | @test "($PLUGIN_COMMAND_PREFIX:link) exports DATABASE_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 DATABASE_URL) 64 | password="$(sudo cat "$PLUGIN_DATA_ROOT/ls/PASSWORD")" 65 | assert_contains "$url" "postgres://postgres:$password@dokku-postgres-ls:5432/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 DATABASE_URL already in use" { 71 | dokku config:set my-app DATABASE_URL=postgres://user:pass@host:5432/db 72 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app 73 | run dokku config my-app 74 | assert_contains "${lines[*]}" "DOKKU_POSTGRES_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_POSTGRES_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.postgres.ls:dokku-postgres-ls" 89 | assert_success 90 | dokku "$PLUGIN_COMMAND_PREFIX:unlink" ls my-app 91 | } 92 | 93 | @test "($PLUGIN_COMMAND_PREFIX:link) uses apps POSTGRES_DATABASE_SCHEME variable" { 94 | dokku config:set my-app POSTGRES_DATABASE_SCHEME=postgres2 95 | dokku "$PLUGIN_COMMAND_PREFIX:link" ls my-app 96 | url=$(dokku config:get my-app DATABASE_URL) 97 | password="$(sudo cat "$PLUGIN_DATA_ROOT/ls/PASSWORD")" 98 | assert_contains "$url" "postgres2://postgres:$password@dokku-postgres-ls:5432/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 DATABASE_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" "postgres://postgres:$password@dokku-postgres-ls:5432/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/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_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 | -------------------------------------------------------------------------------- /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_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 DATABASE_URL" 39 | } 40 | 41 | @test "($PLUGIN_COMMAND_PREFIX:promote) changes DATABASE_URL" { 42 | password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" 43 | dokku config:set my-app "DATABASE_URL=postgres://u:p@host:5432/db" "DOKKU_POSTGRES_BLUE_URL=postgres://postgres:$password@dokku-postgres-l:5432/l" 44 | dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app 45 | url=$(dokku config:get my-app DATABASE_URL) 46 | assert_equal "$url" "postgres://postgres:$password@dokku-postgres-l:5432/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 "DATABASE_URL=postgres://u:p@host:5432/db" "DOKKU_POSTGRES_BLUE_URL=postgres://postgres:$password@dokku-postgres-l:5432/l" 52 | dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app 53 | run dokku config my-app 54 | assert_contains "${lines[*]}" "DOKKU_POSTGRES_" 55 | } 56 | @test "($PLUGIN_COMMAND_PREFIX:promote) uses POSTGRES_DATABASE_SCHEME variable" { 57 | password="$(sudo cat "$PLUGIN_DATA_ROOT/l/PASSWORD")" 58 | dokku config:set my-app "POSTGRES_DATABASE_SCHEME=postgres2" "DATABASE_URL=postgres://u:p@host:5432/db" "DOKKU_POSTGRES_BLUE_URL=postgres2://postgres:$password@dokku-postgres-l:5432/l" 59 | dokku "$PLUGIN_COMMAND_PREFIX:promote" l my-app 60 | url=$(dokku config:get my-app DATABASE_URL) 61 | assert_contains "$url" "postgres2://postgres:$password@dokku-postgres-l:5432/l" 62 | } 63 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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_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_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 | -------------------------------------------------------------------------------- /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 DATABASE_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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /update: -------------------------------------------------------------------------------- 1 | install --------------------------------------------------------------------------------