├── README.md
├── commands
├── functions
├── plugin.toml
├── pre-receive-app
├── require-logo.svg
└── subcommands
├── default
└── mode
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | A plugin which allow you to specify plugins and volumes
4 | required by your app.
5 |
6 | ## Requirements
7 |
8 | * dokku 0.4.0+
9 |
10 | ## Installation
11 |
12 | ```
13 | # on 0.4.x
14 | dokku plugin:install https://github.com/crisward/dokku-require.git require
15 | ```
16 |
17 | ## Usage
18 |
19 | In the root of your app, you need to add an app.json file [as specificed in this heroku spec](https://devcenter.heroku.com/articles/app-json-schema#schema-reference)
20 |
21 | With the addition of a dokku section (see below).
22 |
23 | ```json
24 | {
25 | "name": "my website",
26 | "description": "My website",
27 | "keywords": [
28 | "productivity",
29 | "HTML5"
30 | ],
31 | "website": "https://mywebsite.com/",
32 | "dokku":{
33 | "plugins":[
34 | "mariadb","redis"
35 | ],
36 | "volumes":[
37 | {"host":"/var/lib/dokku/data/storage","app":"/storage"}
38 | ]
39 | }
40 | }
41 | ```
42 |
43 | ## Plugins
44 |
45 | The `"dokku":{"plugins":[]}` array can contain a list of plugin names, which
46 | by default will be created with the app name and linked to your app.
47 | This will only work with the official plugins which have `create` and `link` methods.
48 | ie.
49 |
50 | * [CouchDB (beta)](https://github.com/dokku/dokku-couchdb)
51 | * [Elasticsearch (beta)](https://github.com/dokku/dokku-elasticsearch-plugin)
52 | * [MariaDB (beta)](https://github.com/dokku/dokku-mariadb-plugin)
53 | * [Memcached (beta)](https://github.com/dokku/dokku-memcached-plugin)
54 | * [Mongo (beta)](https://github.com/dokku/dokku-mongo-plugin)
55 | * [MySQL (beta)](https://github.com/dokku/dokku-mysql-plugin)
56 | * [Nats (beta)](https://github.com/dokku/dokku-nats)
57 | * [Postgres (beta)](https://github.com/dokku/dokku-postgres-plugin)
58 | * [RabbitMQ (beta)](https://github.com/dokku/dokku-rabbitmq-plugin)
59 | * [Redis (beta)](https://github.com/dokku/dokku-redis-plugin)
60 | * [RethinkDB (beta)](https://github.com/dokku/dokku-rethinkdb-plugin)
61 |
62 | If you need more control over the creation process or you'd like to use
63 | a non-official plugins the below syntax can be used. Each command in the
64 | array will be run in sequence.
65 |
66 | ```json
67 | "dokku":{
68 | "plugins":[
69 | {
70 | "name":"mariadb",
71 | "commands":["mariadb:create mydb","mariadb:link mydb $APP"]
72 | }
73 | ]
74 | }
75 | ```
76 |
77 | ## Volumes
78 |
79 | Volumes are shared folders between your app's container and the host machine.
80 | By default these will be created in all phased (build,run,deploy) but you can optionally declaire this in your setup
81 | ie.
82 | ```json
83 | "volumes":[
84 | {"host":"/var/lib/dokku/data/storage","app":"/storage","phases":"build,deploy"}
85 | ]
86 | ```
87 | You can also use the `$APP` name in the paths, which will be replaced with your app name
88 | ```json
89 | "volumes":[
90 | {"host":"/mystorage/$APP/images","app":"/images","phases":"deploy"}
91 | ]
92 | ```
93 |
94 |
95 |
96 | ## Alternative Settings for Development and Testing
97 |
98 | It's often neccessary to have different volumes or database configurations
99 | for production, development and testing. To enable this you can set a different 'mode'
100 | for 'dokku require' which overrides the key used within the app.json file.
101 | This allows you to setup mutiple configurations for each of your chosen environments
102 |
103 | ie. Development mode could be set with
104 | ```
105 | dokku require:mode dokku_dev
106 | ```
107 | Then in your `app.json` you would set your development settings under that key.
108 |
109 | ```json
110 | "dokku":{
111 | "plugins":["mariadb","redis"],
112 | "volumes":[{"host":"/var/lib/dokku/data/storage","app":"/storage"}]
113 | }
114 | "dokku_dev":{
115 | "plugins":["mariadb","redis"],
116 | "volumes":[
117 | {"host":"/var/lib/dokku/data/storage","app":"/storage"},
118 | {"host":"/home/vagrant/myapp/src","app":"/app/src"}
119 | ]
120 | }
121 | ```
122 |
123 | **Note:** this setting is global for all apps on your server, by default it is set to dokku.
124 |
125 |
126 | ## Apps Using this Plugin
127 |
128 | As this is very new, I've only created a single app using this.
129 |
130 | * https://github.com/crisward/dokku-ghost - create a ghost blog in dokku
131 |
132 | **If you'd like include your app here, send a pull request, it'd be nice to have a big list of easy to install apps**
133 |
134 | ## Credit
135 |
136 |
137 | Thanks to [Jose Gonzalez](https://github.com/josegonzalez) for code tidy
138 | and the [Noun Project](https://thenounproject.com/) for the logo
139 |
140 | ## License
141 |
142 | (The MIT License)
143 |
144 | Copyright (c) 2015 Cris Ward
145 |
146 | 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:
147 |
148 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
149 |
150 | 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.
151 |
--------------------------------------------------------------------------------
/commands:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
3 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
4 | source "$PLUGIN_AVAILABLE_PATH/require/functions"
5 |
6 | case "$1" in
7 | help | require:help)
8 | help_content_func() {
9 | declare desc="return help_content string"
10 | cat</dev/null 2>&1 ); then
13 | echo "$e"
14 | break
15 | fi
16 | done
17 | }
18 |
19 | require_get_python_version() {
20 | declare desc="determine the install Python version"
21 |
22 | eval "$(require_get_python_executable) -c 'from __future__ import print_function; import sys; print(sys.version_info.major)'"
23 | }
24 |
25 | require_get_app_plugins(){
26 | local JSON_NODE=$1
27 | local python_version=$(require_get_python_version)
28 | if [ "$python_version" -ge 3 ]; then
29 | cat | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(json.dumps(obj'"${JSON_NODE}"').strip("\""))';
30 | else
31 | cat | python -c 'import json,sys;obj=json.load(sys.stdin);print json.dumps(obj'"${JSON_NODE}"').strip("\"")';
32 | fi
33 | }
34 |
35 | require_get_json_len(){
36 | local JSON_NODE=$1
37 | local python=$(require_get_python_executable)
38 | local python_version=$(require_get_python_version)
39 | if [ "$python_version" -ge 3 ]; then
40 | cat | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(len(obj'"${JSON_NODE}"'))';
41 | else
42 | cat | python -c 'import json,sys;obj=json.load(sys.stdin);print len(obj'"${JSON_NODE}"')';
43 | fi
44 |
45 | }
46 |
47 | require_install_link() {
48 | declare desc="installs and links plugin passed in"
49 | declare APP="$1" PLUGIN="$2"
50 | if [[ -d "$PLUGIN_AVAILABLE_PATH/$PLUGIN/" ]]; then
51 | if ! dokku "$PLUGIN:exists" "$APP" > /dev/null 2>&1; then
52 | dokku_log_info1 "Setting up $PLUGIN"
53 | dokku "$PLUGIN:create" "$APP"
54 | fi
55 |
56 | if ! dokku "$PLUGIN:linked" "$APP" "$APP" > /dev/null 2>&1; then
57 | DOKKU_CONFIG_RESTART=false dokku "$PLUGIN:link" "$APP" "$APP"
58 | fi
59 | else
60 | dokku_log_info1 "$PLUGIN plugin is not available on your system - attempting to contine without $PLUGIN"
61 | fi
62 | }
63 |
64 | require_install_commands() {
65 | declare desc="runs commands passed in from plugin list"
66 | declare APP="$1" INDEX="$2"
67 | local COMMAND COUNT PLUGIN TOTAL
68 |
69 | COUNT=0
70 | PLUGIN=$(require_get_app_plugins "[\"$DOKKU_REQUIRE_PREFIX\"][\"plugins\"][${INDEX}][\"name\"]" < "$APP_JSON_FILE" 2>&1)
71 | if [[ -d "$PLUGIN_AVAILABLE_PATH/$PLUGIN/" ]]; then
72 | TOTAL=$(require_get_json_len "[\"$DOKKU_REQUIRE_PREFIX\"][\"plugins\"][${INDEX}][\"commands\"]" < "$APP_JSON_FILE" 2>&1)
73 | while [[ "$COUNT" -lt "$TOTAL" ]]; do
74 | COMMAND=$(require_get_app_plugins "[\"$DOKKU_REQUIRE_PREFIX\"][\"plugins\"][${INDEX}][\"commands\"][${COUNT}]" < "$APP_JSON_FILE" 2>&1)
75 | if [[ $? -ne 0 ]]; then
76 | break
77 | fi
78 |
79 | COMMAND="${COMMAND//\$APP/$APP}"
80 | # shellcheck disable=SC2086
81 | DOKKU_CONFIG_RESTART=false dokku $COMMAND || break
82 | let COUNT=COUNT+1
83 | done
84 | else
85 | dokku_log_info1 "$PLUGIN plugin is not available on your system - attempting to contine without $PLUGIN"
86 | fi
87 | }
88 |
89 | require_add_volumes() {
90 | declare desc="adds volumes from app.json file"
91 | declare APP="$1"
92 | local APPPATH COUNT HOSTPATH TOTAL
93 |
94 | COUNT=0
95 | if TOTAL=$(require_get_json_len "[\"$DOKKU_REQUIRE_PREFIX\"][\"volumes\"]" < "$APP_JSON_FILE" 2>&1); then
96 | dokku_log_info1 "Setting up $TOTAL volumes from app.json"
97 | while [[ "$COUNT" -lt "$TOTAL" ]]; do
98 | HOSTPATH=$(require_get_app_plugins "[\"$DOKKU_REQUIRE_PREFIX\"][\"volumes\"][${COUNT}][\"host\"]" < "$APP_JSON_FILE" 2>&1)
99 | APPPATH=$(require_get_app_plugins "[\"$DOKKU_REQUIRE_PREFIX\"][\"volumes\"][${COUNT}][\"app\"]" < "$APP_JSON_FILE" 2>&1)
100 |
101 | # "phases" key is optional
102 | set +eo pipefail
103 | PHASES=$(require_get_app_plugins "[\"$DOKKU_REQUIRE_PREFIX\"][\"volumes\"][${COUNT}][\"phases\"]" < "$APP_JSON_FILE" 2>&1)
104 | set -eo pipefail
105 |
106 | if [[ -z "$PHASES" ]]; then
107 | PHASES="build,deploy,run"
108 | fi
109 | if [[ $? -ne 0 ]] || [[ -z "$HOSTPATH" ]] || [[ -z "$APPPATH" ]]; then
110 | break
111 | fi
112 |
113 | # swap $APP for app name in commands
114 | HOSTPATH="${HOSTPATH//\$APP/$APP}"
115 | APPPATH="${APPPATH//\$APP/$APP}"
116 | mkdir -p "$HOSTPATH"
117 | dokku docker-options:add "$APP" "$PHASES" -v "$HOSTPATH:$APPPATH"
118 | let COUNT=COUNT+1
119 | done
120 | fi
121 | }
122 |
123 | require_mode_cmd() {
124 | declare desc="sets DOKKU_REQUIRE_PREFIX"
125 | declare MODE="$2"
126 | local cmd="mode"
127 | [[ -d $DOKKU_ROOT/.dokkurc ]] || mkdir -p "$DOKKU_ROOT/.dokkurc"
128 |
129 | echo "Setting DOKKU_REQUIRE_PREFIX to $MODE"
130 | echo "export DOKKU_REQUIRE_PREFIX=$MODE" > "$DOKKU_ROOT/.dokkurc/DOKKU_REQUIRE_PREFIX"
131 | }
132 |
--------------------------------------------------------------------------------
/plugin.toml:
--------------------------------------------------------------------------------
1 | [plugin]
2 | description = "dokku plugin to setup all the requirement for your app on push"
3 | version = "0.1.0"
4 | [plugin.config]
--------------------------------------------------------------------------------
/pre-receive-app:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
4 | DOKKU_REQUIRE_PREFIX="${DOKKU_REQUIRE_PREFIX:-dokku}"
5 | source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
6 | source "$PLUGIN_AVAILABLE_PATH/require/functions"
7 |
8 |
9 | require_pre_receive_app() {
10 | declare desc="reads app.json and builds plugins"
11 | local APP="$1" IMAGE_SOURCE_TYPE="$2" TMP_WORK_DIR="$3" REV="$4"
12 | local APP_JSON_FILE="$TMP_WORK_DIR/app.json"
13 | local TOTAL PLUGIN
14 |
15 | if [[ ! -f "$APP_JSON_FILE" ]]; then
16 | return
17 | fi
18 |
19 | # get each plugin from json, limit to 10 to prevent silly loop
20 | COUNTER=0
21 | if TOTAL=$(require_get_json_len "[\"$DOKKU_REQUIRE_PREFIX\"][\"plugins\"]" < "$APP_JSON_FILE" 2>&1); then
22 | while [[ "$COUNTER" -lt "$TOTAL" ]]; do
23 | PLUGIN=$(require_get_app_plugins "[\"$DOKKU_REQUIRE_PREFIX\"][\"plugins\"][${COUNTER}]" < "$APP_JSON_FILE" 2>&1)
24 | if [[ $? -ne 0 ]]; then
25 | break
26 | fi
27 |
28 | if [[ "$PLUGIN" == *"{"* ]]; then
29 | require_install_commands "$APP" "$COUNTER"
30 | else
31 | require_install_link "$APP" "$PLUGIN"
32 | fi
33 | let COUNTER=$((COUNTER + 1))
34 | done
35 | fi
36 | require_add_volumes "$APP"
37 | }
38 |
39 | require_pre_receive_app "$@"
40 |
--------------------------------------------------------------------------------
/require-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
17 |
--------------------------------------------------------------------------------
/subcommands/default:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
3 | source "$PLUGIN_AVAILABLE_PATH/require/functions"
4 |
5 | require_main_cmd "$@"
6 |
--------------------------------------------------------------------------------
/subcommands/mode:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
3 | source "$PLUGIN_AVAILABLE_PATH/require/functions"
4 |
5 | require_mode_cmd "$@"
--------------------------------------------------------------------------------