Compare commits
250 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e10e62b1e9 | ||
|
|
f425e23bdf | ||
|
|
4c86c7bd26 | ||
|
|
fa605b6a83 | ||
|
|
1f08853fc7 | ||
|
|
40421b32a4 | ||
|
|
f3d6190e18 | ||
|
|
46377071ea | ||
|
|
5fbe28f672 | ||
|
|
302d82a192 | ||
|
|
061ea9bfd7 | ||
|
|
f8e3bdc56b | ||
|
|
92d7e8ce65 | ||
|
|
e7faec3e26 | ||
|
|
72a847a6f1 | ||
|
|
0e007a1196 | ||
|
|
af626a51cc | ||
|
|
4bb221d89a | ||
|
|
984388d191 | ||
|
|
f0ef1daa15 | ||
|
|
3d065bf35c | ||
|
|
f1c0432375 | ||
|
|
21645247fb | ||
|
|
1a350796e5 | ||
|
|
5522cf63f7 | ||
|
|
52d6143d97 | ||
|
|
0fe5c645d6 | ||
|
|
85d04ee11a | ||
|
|
343c5fb5ca | ||
|
|
4ae56cf01c | ||
|
|
8336247cc1 | ||
|
|
3fe0b56fb8 | ||
|
|
329e849894 | ||
|
|
70cee2df86 | ||
|
|
2a30f45177 | ||
|
|
6528c4511a | ||
|
|
fe6f339890 | ||
|
|
c46efa54b4 | ||
|
|
3ef3f0218f | ||
|
|
59414fe231 | ||
|
|
052a14f13c | ||
|
|
050fa7edf3 | ||
|
|
e9db130b38 | ||
|
|
39aefb95c2 | ||
|
|
f1baa1f6a5 | ||
|
|
cd9c2d7dbe | ||
|
|
2e0939702a | ||
|
|
fc4903c1c9 | ||
|
|
3f408f1304 | ||
|
|
e3eab48e4a | ||
|
|
39abbdc5dd | ||
|
|
5d5ede2b85 | ||
|
|
64252b282a | ||
|
|
b449227467 | ||
|
|
228eb9ed7a | ||
|
|
a999f9d4e5 | ||
|
|
9b431321fa | ||
|
|
a96c1d644a | ||
|
|
6bd6cad8fd | ||
|
|
58cc088445 | ||
|
|
1d46208ac2 | ||
|
|
465c6e9a62 | ||
|
|
7a8cc2687d | ||
|
|
96ad5e8e5d | ||
|
|
4cc215ea02 | ||
|
|
c10c58a1cd | ||
|
|
099653ca02 | ||
|
|
84a6c6017d | ||
|
|
9fcd9b0065 | ||
|
|
dc9ebf867c | ||
|
|
3684c10a78 | ||
|
|
10492587c2 | ||
|
|
bc93007c74 | ||
|
|
0e91a5bd0b | ||
|
|
75c7c2ebf0 | ||
|
|
6c57f1a08b | ||
|
|
59e5036456 | ||
|
|
158f10d321 | ||
|
|
4a3047b170 | ||
|
|
64a1c91b76 | ||
|
|
39b879058d | ||
|
|
5ae9067750 | ||
|
|
2af312ac03 | ||
|
|
172bc87f32 | ||
|
|
83ef992155 | ||
|
|
0df3f8d12d | ||
|
|
23ee740c04 | ||
|
|
54d731aeee | ||
|
|
9481e7031d | ||
|
|
70ba60e9e8 | ||
|
|
04a5e8bedf | ||
|
|
9706f7a298 | ||
|
|
cdd2b2028e | ||
|
|
3eb7a13006 | ||
|
|
71763e18f6 | ||
|
|
e9506e80cb | ||
|
|
33a540502a | ||
|
|
b8575a33f5 | ||
|
|
a3cd6f6e63 | ||
|
|
85fa7a5bb0 | ||
|
|
90ee5d58c5 | ||
|
|
ffac858566 | ||
|
|
0f10c94839 | ||
|
|
0581b38adf | ||
|
|
576ec05a9e | ||
|
|
6f4720adca | ||
|
|
ab3249c76b | ||
|
|
2f7daad200 | ||
|
|
6780d53c77 | ||
|
|
36fc689a5d | ||
|
|
98c45b55b7 | ||
|
|
1be66bd1bc | ||
|
|
91c2164e49 | ||
|
|
9876b9e588 | ||
|
|
58e36fee10 | ||
|
|
03830562c2 | ||
|
|
430cc2b4ca | ||
|
|
3f497908b5 | ||
|
|
3422866909 | ||
|
|
b84635baf7 | ||
|
|
ad8bcecb5b | ||
|
|
c896ca700c | ||
|
|
ecf67d3cdd | ||
|
|
e9b9091de5 | ||
|
|
62b27d4007 | ||
|
|
cc3ccda90a | ||
|
|
dc79152fe0 | ||
|
|
6b340c69b5 | ||
|
|
f2ec959598 | ||
|
|
b16c2876c4 | ||
|
|
3f50097619 | ||
|
|
28ca39266c | ||
|
|
6dcf695822 | ||
|
|
aeba3f2269 | ||
|
|
1fb0e737c3 | ||
|
|
462a648ac8 | ||
|
|
6523163701 | ||
|
|
a9a9d0a898 | ||
|
|
2851f2c63f | ||
|
|
5e82b37147 | ||
|
|
810ebffceb | ||
|
|
adedd3af5d | ||
|
|
722f22e7f0 | ||
|
|
ad732bd42b | ||
|
|
fdbab2c291 | ||
|
|
8654783131 | ||
|
|
b099d2c389 | ||
|
|
c9ea884e5d | ||
|
|
fbf9077075 | ||
|
|
5e32f9a89d | ||
|
|
690c32ceb8 | ||
|
|
7d73577952 | ||
|
|
edfec35177 | ||
|
|
c2ee6e99c6 | ||
|
|
419d687c50 | ||
|
|
3ca5503b74 | ||
|
|
acde3d60a7 | ||
|
|
7a4464a8ae | ||
|
|
096ba83f41 | ||
|
|
04cd5eeb91 | ||
|
|
9d287d0a5d | ||
|
|
af13d1247f | ||
|
|
81ddef04ff | ||
|
|
9ef7c385d4 | ||
|
|
dc00542b6f | ||
|
|
7fe2f8593c | ||
|
|
20dca9fd46 | ||
|
|
647efab2dd | ||
|
|
44282fd857 | ||
|
|
1372522258 | ||
|
|
27f247eabd | ||
|
|
a3abf8016b | ||
|
|
3b9f4ba63f | ||
|
|
92d6e76ea4 | ||
|
|
350efd8d53 | ||
|
|
6f008d6643 | ||
|
|
6e76831b5d | ||
|
|
31333452c8 | ||
|
|
25759bcbb4 | ||
|
|
72eb8a06f0 | ||
|
|
1e8831d9a0 | ||
|
|
c788659b63 | ||
|
|
e74346f0dc | ||
|
|
5b592575e7 | ||
|
|
c43a3edfc6 | ||
|
|
94149c8445 | ||
|
|
7fd32fb3e8 | ||
|
|
006eb452f1 | ||
|
|
2c5190bf63 | ||
|
|
0cc9e42c59 | ||
|
|
b409af602a | ||
|
|
b0afa778fb | ||
|
|
b8a4152e10 | ||
|
|
4949d1e33e | ||
|
|
06a7cb2a3d | ||
|
|
aee88d081d | ||
|
|
f71d147a8f | ||
|
|
dfad37ba23 | ||
|
|
1a2ed28e5b | ||
|
|
054a1328f7 | ||
|
|
901ec7c213 | ||
|
|
6fbd148597 | ||
|
|
d7d5d373c9 | ||
|
|
a9e0f8b7be | ||
|
|
f668bec210 | ||
|
|
1835b04809 | ||
|
|
ec9b8be5f8 | ||
|
|
8be92d9739 | ||
|
|
bbb38031f0 | ||
|
|
c25ef5dc4c | ||
|
|
093414b846 | ||
|
|
f664ad1cde | ||
|
|
5e9306ad40 | ||
|
|
c9af7e4cfa | ||
|
|
5d72f145df | ||
|
|
60e3b37d39 | ||
|
|
a8563489e7 | ||
|
|
a86c037a91 | ||
|
|
523429b47f | ||
|
|
a13722eec1 | ||
|
|
8e8b6d60f0 | ||
|
|
4808c047ee | ||
|
|
be5e81b246 | ||
|
|
a137ed64dc | ||
|
|
fc1129c728 | ||
|
|
a22594b891 | ||
|
|
4f5c747c99 | ||
|
|
e7a81a8f8b | ||
|
|
32414b343a | ||
|
|
eeb6e78fa4 | ||
|
|
08aa2b9fa4 | ||
|
|
8b90d4ebf9 | ||
|
|
133fdc1f0a | ||
|
|
e7e01ee838 | ||
|
|
12c9536a7b | ||
|
|
c20fbfccf6 | ||
|
|
fd27d90303 | ||
|
|
686428a41a | ||
|
|
73e85b7df5 | ||
|
|
dfa241d6a9 | ||
|
|
dd8e1fdf45 | ||
|
|
21b091ab14 | ||
|
|
416b499670 | ||
|
|
dc90a889d7 | ||
|
|
14757ca925 | ||
|
|
7d865ccb1f | ||
|
|
294d4b1f29 | ||
|
|
5e3184b61d | ||
|
|
e57e1408b2 | ||
|
|
ef95d2bcd4 |
@@ -9,9 +9,6 @@ jobs:
|
||||
make ci-dependencies
|
||||
- run: |
|
||||
./tests/ci/setup.sh
|
||||
- run: |
|
||||
sudo apt-get remove -qq -y git
|
||||
sudo apt-get install -qq -y git=1:1.9.1-1ubuntu0.6 git-man=1:1.9.1-1ubuntu0.6
|
||||
- run: |
|
||||
echo 'export DOKKU_SKIP_CLEANUP=true' | sudo tee /home/dokku/.dokkurc/dokku_skip_cleanup
|
||||
- run: |
|
||||
@@ -20,10 +17,12 @@ jobs:
|
||||
- run: |
|
||||
case $CIRCLE_NODE_INDEX in
|
||||
0) sudo -E make -e lint ;;
|
||||
1) sudo -E make -e go-tests ;;
|
||||
1) sudo -E make -e go-tests ci-go-coverage;;
|
||||
2) sudo -E make -e deploy-test-checks-root deploy-test-config deploy-test-multi deploy-test-go-fail-predeploy deploy-test-go-fail-postdeploy ;;
|
||||
esac
|
||||
- run:
|
||||
shell: /bin/bash
|
||||
command: sudo -E make -e test-ci
|
||||
no_output_timeout: 60m
|
||||
- store_artifacts:
|
||||
path: ./coverage.out
|
||||
|
||||
5
.codacy.yml
Normal file
5
.codacy.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
exclude_paths:
|
||||
- vendor/**/*
|
||||
- tests/**/*
|
||||
- "**_test.go"
|
||||
- contrib/*
|
||||
@@ -17,5 +17,5 @@ indent_size = 4
|
||||
|
||||
[*.go]
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,7 +2,9 @@
|
||||
*.rpm
|
||||
.DS_Store
|
||||
.ruby-version
|
||||
.idea/
|
||||
.vagrant
|
||||
data/
|
||||
stack.tgz
|
||||
tmp
|
||||
coverage.out
|
||||
|
||||
@@ -7,3 +7,4 @@ linters:
|
||||
files:
|
||||
ignore:
|
||||
- './debian/*'
|
||||
- '*/vendor/*'
|
||||
|
||||
72
HISTORY.md
72
HISTORY.md
@@ -1,5 +1,77 @@
|
||||
# History
|
||||
|
||||
## 0.11.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- #3014: @josegonzalez fix: handle case where DOKKU_DOCKERFILE_PORTS is an empty string
|
||||
- #3013: @alexquick Fix some issues with config/network/repo help output
|
||||
- #3012: @alexquick Fail when setting/unsetting invalid keys
|
||||
- #3011: @alexquick Forward output from plugn triggers to user
|
||||
- #3004: @josegonzalez Return/Exit 1 when an image being deployed is invalid
|
||||
|
||||
### Documentation
|
||||
|
||||
- #3015: @elia Tiny fixes to triggers documentation
|
||||
|
||||
## 0.11.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- #3010: @josegonzalez fix: route config_all to the `config` command to fix datastore plugin usage
|
||||
- #3009: @josegonzalez fix: correct the guard around the config_export call in config_sub
|
||||
- #3006: @josegonzalez fix: do not allow shadowing of the CACHE_DIR variable
|
||||
- #3005: @josegonzalez fix: persist users in the dokku group through installations
|
||||
- #3003: @josegonzalez Fix issues in apps:clone calls
|
||||
- #3001: @josegonzalez fix: allow applications to begin with numeric values
|
||||
|
||||
### New Features
|
||||
|
||||
- #3002: @josegonzalez fix: omit redirection of docker build output
|
||||
- #3000: @josegonzalez fix: remove golang files and triggers directory for packaging
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- #2998: @josegonzalez Fix issues in release process
|
||||
- #2993: @josegonzalez Add config_all alias for plugin usage
|
||||
- #2972: @buckle2000 Correct typo in docker-options:remove error output
|
||||
- #2964: @znz Remove unused variable
|
||||
- #2967: @znz Fix indentation in test file
|
||||
- #2963: @znz Correct typos in config plugin and remove potential infinite recursion issue
|
||||
- #2951: @josegonzalez Handle case where the app directory is a symlink
|
||||
- #2939: @znz Remove unnecessary lines
|
||||
- #2945: @znz Fix network plugin version
|
||||
- #2937: @michaelshobbs Strip restart flag from app_user_pre_deploy_trigger
|
||||
- #2931: @josegonzalez Upgrade git package for CI
|
||||
- #2928: @silverfix Do not overwrite the VHOST file during installation if it exists
|
||||
- #2926: @vtavernier Remove leading forward slash from app name in git-upload-pack
|
||||
|
||||
### New Features
|
||||
|
||||
- #2985: @bitmand Build a custom dhparam file once for nginx and include it as default
|
||||
- #2974: @josegonzalez Upgrade to herokuish 0.3.33
|
||||
- #2973: @josegonzalez Allow usage of git 2.13.0+ by unsetting GIT_QUARANTINE_PATH during git worktree usage
|
||||
- #2971: @miraculixx Add support for older virtualbox versions in official Dokku Vagrantfile
|
||||
- #2966: @znz Simplify internal config functions to reduce duplication
|
||||
- #2751: @alexquick Move config plugin to golang
|
||||
- #2938: @michaelshobbs Upgrade to golang 1.9.1
|
||||
- #2736: @josegonzalez Implement Network Plugin
|
||||
- #2929: @michaelshobbs Add codacy config and coverage targets
|
||||
|
||||
### Documentation
|
||||
|
||||
- #2935: @jcrben Document how to make herokuish optional during the bootstrap installation
|
||||
- #2982: @agorf Correct typo in user management docs
|
||||
- #2981: @agorf Correct typos in process management docs
|
||||
- #2969: @znz Correct comments on network triggers
|
||||
- #2965: @znz Remove spaces from config subcommand help output to mirror help output of other subcommands
|
||||
- #2954: @mrname Add vernemq community datastore plugin to docs
|
||||
- #2944: @axilleas Fix syntax typo in debian installation docs
|
||||
- #2932: @znz Update code comment to match documentation
|
||||
- #2933: @znz Fix version number for network binding documentation
|
||||
|
||||
## 0.10.5
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
DOKKU_VERSION ?= master
|
||||
|
||||
SSHCOMMAND_URL ?= https://raw.githubusercontent.com/dokku/sshcommand/v0.6.0/sshcommand
|
||||
SSHCOMMAND_URL ?= https://raw.githubusercontent.com/dokku/sshcommand/v0.7.0/sshcommand
|
||||
PLUGN_URL ?= https://github.com/dokku/plugn/releases/download/v0.3.0/plugn_0.3.0_linux_x86_64.tgz
|
||||
SIGIL_URL ?= https://github.com/gliderlabs/sigil/releases/download/v0.4.0/sigil_0.4.0_Linux_x86_64.tgz
|
||||
STACK_URL ?= https://github.com/gliderlabs/herokuish.git
|
||||
|
||||
@@ -99,8 +99,8 @@ A fresh VM running any of the following operating systems:
|
||||
To install the latest stable release, run the following commands as a user who has access to `sudo`:
|
||||
|
||||
```shell
|
||||
wget https://raw.githubusercontent.com/dokku/dokku/v0.10.5/bootstrap.sh
|
||||
sudo DOKKU_TAG=v0.10.5 bash bootstrap.sh
|
||||
wget https://raw.githubusercontent.com/dokku/dokku/v0.11.2/bootstrap.sh
|
||||
sudo DOKKU_TAG=v0.11.2 bash bootstrap.sh
|
||||
```
|
||||
|
||||
You can then proceed to the ip address or domain name associated with your server to complete the web-based installation.
|
||||
|
||||
2
Vagrantfile
vendored
2
Vagrantfile
vendored
@@ -45,6 +45,8 @@ Vagrant::configure("2") do |config|
|
||||
vm.vm.provider :virtualbox do |vb|
|
||||
vb.customize ["modifyvm", :id, "--natdnshostresolver1", "off"]
|
||||
vb.customize ["modifyvm", :id, "--natdnsproxy1", "off"]
|
||||
# enable NAT adapter cable https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=838999
|
||||
vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
|
||||
end
|
||||
|
||||
vm.vm.provision :shell, :inline => "export DEBIAN_FRONTEND=noninteractive && apt-get update > /dev/null && apt-get -qq -y install git > /dev/null && cd /root/dokku && #{make_cmd}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
GO_REPO_ROOT := /go/src/github.com/dokku/dokku
|
||||
BUILD_IMAGE := golang:1.7.5
|
||||
BUILD_IMAGE := golang:1.9.1
|
||||
|
||||
.PHONY: build-in-docker build clean src-clean
|
||||
|
||||
@@ -2,14 +2,14 @@ FROM ubuntu:14.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install gcc git build-essential wget ruby-dev ruby1.9.1 lintian rpm help2man man-db
|
||||
RUN apt-get update && apt-get -y install gcc git build-essential wget ruby-dev ruby1.9.1 lintian rpm help2man man-db
|
||||
RUN command -v fpm > /dev/null || sudo gem install fpm --no-ri --no-rdoc
|
||||
|
||||
ARG GOLANG_VERSION
|
||||
|
||||
RUN wget -qO /tmp/go${GOLANG_VERSION}.linux-amd64.tar.gz https://storage.googleapis.com/golang/go${GOLANG_VERSION}.linux-amd64.tar.gz \
|
||||
&& tar -C /usr/local -xzf /tmp/go${GOLANG_VERSION}.linux-amd64.tar.gz
|
||||
&& tar -C /usr/local -xzf /tmp/go${GOLANG_VERSION}.linux-amd64.tar.gz \
|
||||
&& cp /usr/local/go/bin/* /usr/local/bin
|
||||
|
||||
ARG WORKDIR=/go/src/github.com/dokku/dokku
|
||||
|
||||
@@ -27,8 +27,9 @@ ARG DOKKU_VERSION=master
|
||||
ARG DOKKU_GIT_REV
|
||||
ARG IS_RELEASE=false
|
||||
|
||||
RUN PATH=$PATH:/usr/local/go/bin GOPATH=/go \
|
||||
PLUGIN_MAKE_TARGET=${PLUGIN_MAKE_TARGET} \
|
||||
ENV GOPATH=/go
|
||||
|
||||
RUN PLUGIN_MAKE_TARGET=${PLUGIN_MAKE_TARGET} \
|
||||
DOKKU_VERSION=${DOKKU_VERSION} \
|
||||
DOKKU_GIT_REV=${DOKKU_GIT_REV} \
|
||||
IS_RELEASE=${IS_RELEASE} \
|
||||
|
||||
@@ -10,7 +10,7 @@ import subprocess
|
||||
import sys
|
||||
import threading
|
||||
|
||||
VERSION = 'v0.10.5'
|
||||
VERSION = 'v0.11.2'
|
||||
|
||||
hostname = ''
|
||||
try:
|
||||
|
||||
4
deb.mk
4
deb.mk
@@ -1,6 +1,6 @@
|
||||
HEROKUISH_DESCRIPTION = 'Herokuish uses Docker and Buildpacks to build applications like Heroku'
|
||||
HEROKUISH_REPO_NAME ?= gliderlabs/herokuish
|
||||
HEROKUISH_VERSION ?= 0.3.31
|
||||
HEROKUISH_VERSION ?= 0.3.33
|
||||
HEROKUISH_ARCHITECTURE = amd64
|
||||
HEROKUISH_PACKAGE_NAME = herokuish_$(HEROKUISH_VERSION)_$(HEROKUISH_ARCHITECTURE).deb
|
||||
|
||||
@@ -90,7 +90,7 @@ deb-herokuish:
|
||||
@echo 'if [[ ! -z $${http_proxy+x} ]]; then BUILDARGS="--build-arg http_proxy=$$http_proxy"; fi' >> /tmp/tmp/post-install
|
||||
@echo 'if [[ ! -z $${https_proxy+x} ]]; then BUILDARGS="$$BUILDARGS --build-arg https_proxy=$$https_proxy"; fi' >> /tmp/tmp/post-install
|
||||
@echo 'if [[ ! -z $${BUILDARGS+x} ]]; then echo Adding proxy settings to docker build: $$BUILDARGS; fi' >> /tmp/tmp/post-install
|
||||
@echo 'sudo docker build --pull $$BUILDARGS -t gliderlabs/herokuish /var/lib/herokuish 1> /dev/null' >> /tmp/tmp/post-install
|
||||
@echo 'sudo docker build --pull $$BUILDARGS -t gliderlabs/herokuish /var/lib/herokuish' >> /tmp/tmp/post-install
|
||||
|
||||
@echo "-> Cloning repository"
|
||||
git clone -q "https://github.com/$(HEROKUISH_REPO_NAME).git" --branch "v$(HEROKUISH_VERSION)" /tmp/tmp/herokuish > /dev/null
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@@ -1,5 +1,5 @@
|
||||
Package: dokku
|
||||
Version: 0.10.5
|
||||
Version: 0.11.2
|
||||
Section: web
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
|
||||
7
debian/lintian-overrides
vendored
7
debian/lintian-overrides
vendored
@@ -3,3 +3,10 @@ dokku: maintainer-script-calls-systemctl postinst:87
|
||||
dokku: changelog-file-missing-in-native-package
|
||||
dokku: statically-linked-binary
|
||||
dokku: unstripped-binary-or-object
|
||||
|
||||
# The Go compiler is currently unable to produce read-only relocations
|
||||
# (it produces static binaries).
|
||||
dokku: hardening-no-relro
|
||||
|
||||
# Built golang binaries link to libc
|
||||
dokku: missing-dependency-on-libc
|
||||
|
||||
13
debian/postinst
vendored
13
debian/postinst
vendored
@@ -100,12 +100,15 @@ case "$1" in
|
||||
exit 0
|
||||
fi
|
||||
|
||||
db_get "dokku/vhost_enable"
|
||||
if [ "$RET" = "true" ]; then
|
||||
db_get "dokku/hostname"
|
||||
echo "$RET" > "${DOKKU_ROOT}/VHOST"
|
||||
if [ -f "${DOKKU_ROOT}/VHOST" ]; then
|
||||
echo "VHOST file detected, skipping modification"
|
||||
else
|
||||
rm -f "${DOKKU_ROOT}/VHOST"
|
||||
db_get "dokku/vhost_enable"
|
||||
if [ "$RET" = "true" ]; then
|
||||
db_get "dokku/hostname"
|
||||
echo "Setting VHOST contents to $RET"
|
||||
echo "$RET" > "${DOKKU_ROOT}/VHOST"
|
||||
fi
|
||||
fi
|
||||
|
||||
db_get "dokku/hostname"
|
||||
|
||||
@@ -31,30 +31,30 @@ dokku plugin
|
||||
|
||||
```
|
||||
plugn: dev
|
||||
00_dokku-standard 0.10.5 enabled dokku core standard plugin
|
||||
20_events 0.10.5 enabled dokku core events logging plugin
|
||||
apps 0.10.5 enabled dokku core apps plugin
|
||||
build-env 0.10.5 enabled dokku core build-env plugin
|
||||
certs 0.10.5 enabled dokku core certificate management plugin
|
||||
checks 0.10.5 enabled dokku core checks plugin
|
||||
common 0.10.5 enabled dokku core common plugin
|
||||
config 0.10.5 enabled dokku core config plugin
|
||||
docker-options 0.10.5 enabled dokku core docker-options plugin
|
||||
domains 0.10.5 enabled dokku core domains plugin
|
||||
enter 0.10.5 enabled dokku core enter plugin
|
||||
git 0.10.5 enabled dokku core git plugin
|
||||
logs 0.10.5 enabled dokku core logs plugin
|
||||
named-containers 0.10.5 enabled dokku core named containers plugin
|
||||
nginx-vhosts 0.10.5 enabled dokku core nginx-vhosts plugin
|
||||
plugin 0.10.5 enabled dokku core plugin plugin
|
||||
proxy 0.10.5 enabled dokku core proxy plugin
|
||||
ps 0.10.5 enabled dokku core ps plugin
|
||||
repo 0.10.5 enabled dokku core repo plugin
|
||||
shell 0.10.5 enabled dokku core shell plugin
|
||||
ssh-keys 0.10.5 enabled dokku core ssh-keys plugin
|
||||
storage 0.10.5 enabled dokku core storage plugin
|
||||
tags 0.10.5 enabled dokku core tags plugin
|
||||
tar 0.10.5 enabled dokku core tar plugin
|
||||
00_dokku-standard 0.11.2 enabled dokku core standard plugin
|
||||
20_events 0.11.2 enabled dokku core events logging plugin
|
||||
apps 0.11.2 enabled dokku core apps plugin
|
||||
build-env 0.11.2 enabled dokku core build-env plugin
|
||||
certs 0.11.2 enabled dokku core certificate management plugin
|
||||
checks 0.11.2 enabled dokku core checks plugin
|
||||
common 0.11.2 enabled dokku core common plugin
|
||||
config 0.11.2 enabled dokku core config plugin
|
||||
docker-options 0.11.2 enabled dokku core docker-options plugin
|
||||
domains 0.11.2 enabled dokku core domains plugin
|
||||
enter 0.11.2 enabled dokku core enter plugin
|
||||
git 0.11.2 enabled dokku core git plugin
|
||||
logs 0.11.2 enabled dokku core logs plugin
|
||||
named-containers 0.11.2 enabled dokku core named containers plugin
|
||||
nginx-vhosts 0.11.2 enabled dokku core nginx-vhosts plugin
|
||||
plugin 0.11.2 enabled dokku core plugin plugin
|
||||
proxy 0.11.2 enabled dokku core proxy plugin
|
||||
ps 0.11.2 enabled dokku core ps plugin
|
||||
repo 0.11.2 enabled dokku core repo plugin
|
||||
shell 0.11.2 enabled dokku core shell plugin
|
||||
ssh-keys 0.11.2 enabled dokku core ssh-keys plugin
|
||||
storage 0.11.2 enabled dokku core storage plugin
|
||||
tags 0.11.2 enabled dokku core tags plugin
|
||||
tar 0.11.2 enabled dokku core tar plugin
|
||||
```
|
||||
|
||||
Installing a plugin is easy as well using the `plugin:install` command. This command will also trigger the `install` pluginhook on all existing plugins.
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/mstile-70x70.png"/>
|
||||
<square150x150logo src="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/mstile-150x150.png"/>
|
||||
<square310x310logo src="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/mstile-310x310.png"/>
|
||||
<wide310x150logo src="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/mstile-310x150.png"/>
|
||||
<square70x70logo src="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/mstile-70x70.png"/>
|
||||
<square150x150logo src="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/mstile-150x150.png"/>
|
||||
<square310x310logo src="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/mstile-310x310.png"/>
|
||||
<wide310x150logo src="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/mstile-310x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
|
||||
@@ -2,37 +2,37 @@
|
||||
"name": "Dokku",
|
||||
"icons": [
|
||||
{
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.10.5\/docs\/assets\/favicons\/android-chrome-36x36.png",
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.11.2\/docs\/assets\/favicons\/android-chrome-36x36.png",
|
||||
"sizes": "36x36",
|
||||
"type": "image\/png",
|
||||
"density": "0.75"
|
||||
},
|
||||
{
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.10.5\/docs\/assets\/favicons\/android-chrome-48x48.png",
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.11.2\/docs\/assets\/favicons\/android-chrome-48x48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image\/png",
|
||||
"density": "1.0"
|
||||
},
|
||||
{
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.10.5\/docs\/assets\/favicons\/android-chrome-72x72.png",
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.11.2\/docs\/assets\/favicons\/android-chrome-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image\/png",
|
||||
"density": "1.5"
|
||||
},
|
||||
{
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.10.5\/docs\/assets\/favicons\/android-chrome-96x96.png",
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.11.2\/docs\/assets\/favicons\/android-chrome-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image\/png",
|
||||
"density": "2.0"
|
||||
},
|
||||
{
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.10.5\/docs\/assets\/favicons\/android-chrome-144x144.png",
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.11.2\/docs\/assets\/favicons\/android-chrome-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image\/png",
|
||||
"density": "3.0"
|
||||
},
|
||||
{
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.10.5\/docs\/assets\/favicons\/android-chrome-192x192.png",
|
||||
"src": "https:\/\/cdn.rawgit.com\/progrium\/dokku\/v0.11.2\/docs\/assets\/favicons\/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image\/png",
|
||||
"density": "4.0"
|
||||
|
||||
@@ -35,13 +35,13 @@ h1 {
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.header .navbar-brand a {
|
||||
background-image: url(https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/dokku.png);
|
||||
background-image: url(https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/dokku.png);
|
||||
text-indent: 40px;
|
||||
}
|
||||
.blurb {
|
||||
color: #424242;
|
||||
background-color: #ededed;
|
||||
background-image: url(https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/gplaypattern.png);
|
||||
background-image: url(https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/gplaypattern.png);
|
||||
padding: 45px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"0.7.2",
|
||||
"0.8.2",
|
||||
"0.9.4",
|
||||
"0.10.5"
|
||||
"0.10.5",
|
||||
"0.11.2"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ Note: The following plugins have been supplied by our community and may not have
|
||||
[mixxorz]: https://github.com/mixxorz
|
||||
[mlebkowski]: https://github.com/mlebkowski
|
||||
[motin]: https://github.com/motin
|
||||
[mrname]: https://github.com/mrname
|
||||
[musicglue]: https://github.com/musicglue
|
||||
[neam]: https://github.com/neam
|
||||
[nickcharlton]: https://github.com/nickcharlton
|
||||
@@ -152,6 +153,7 @@ Note: The following plugins have been supplied by our community and may not have
|
||||
| [RabbitMQ](https://github.com/jlachowski/dokku-rabbitmq-plugin) | [jlachowski][] | 0.3.x |
|
||||
| [RabbitMQ (single container)](https://github.com/jlachowski/dokku-rabbitmq-single-plugin) | [jlachowski][] | 0.3.x |
|
||||
| [ElasticMQ (SQS compatible)](https://github.com/cu12/dokku-elasticmq) | [cu12][] | 0.5.0+ |
|
||||
| [VerneMQ (MQTT Broker)](https://github.com/SpinifexGroup/dokku-vernemq) | [mrname][] | 0.4.0+ |
|
||||
|
||||
#### Other
|
||||
|
||||
|
||||
@@ -5,10 +5,11 @@ Typically an application will require some configuration to run properly. Dokku
|
||||
The `config` plugin provides the following commands to manage your variables:
|
||||
|
||||
```
|
||||
config (<app>|--global) Display all global or app-specific config vars
|
||||
config:get (<app>|--global) KEY Display a global or app-specific config value
|
||||
config:set (<app>|--global) KEY1=VALUE1 [KEY2=VALUE2 ...] Set one or more config vars
|
||||
config:unset (<app>|--global) KEY1 [KEY2 ...] Unset one or more config vars
|
||||
config (<app>|--global) Display all global or app-specific config vars
|
||||
config:get (<app>|--global) KEY Display a global or app-specific config value
|
||||
config:set (<app>|--global) KEY1=VALUE1 [KEY2=VALUE2 ...] Set one or more config vars
|
||||
config:unset (<app>|--global) KEY1 [KEY2 ...] Unset one or more config vars
|
||||
config:export [--format=FORMAT] [--merged] (<app>|--global) Export all global or app-specific configuration
|
||||
```
|
||||
|
||||
The variables are available both at run time and during the application build/compilation step for buildpack-based deploys. For security reasons - and as per [docker recommendations](https://github.com/docker/docker/issues/13490) - Dockerfile-based deploys have variables available *only* during runtime, as noted in [this issue](https://github.com/dokku/dokku/issues/1860).
|
||||
@@ -23,10 +24,15 @@ You can set multiple environment variables at once:
|
||||
dokku config:set node-js-app ENV=prod COMPILE_ASSETS=1
|
||||
```
|
||||
|
||||
When setting variables with whitespaces, you need to escape them:
|
||||
> Note: Whitespace and special characters get tricky. If you are using dokku locally you don't need to do any special escaping. If you are using dokku over ssh you will need to backslash-escape spaces:
|
||||
```shell
|
||||
dokku config:set node-js-app KEY="VAL\ WITH\ SPACES"
|
||||
```
|
||||
|
||||
Dokku can also read base64 encoded values. That's the easiest way to set a value with newlines or spaces. To set a value with newlines you need to base64 encode it first and pass the `--encoded` flag:
|
||||
|
||||
```shell
|
||||
dokku config:set node-js-app KEY=\"VAL\ WITH\ SPACES\"
|
||||
dokku config:set --encoded node-js-app KEY="$(base64 ~/.ssh/id_rsa)"
|
||||
```
|
||||
|
||||
When setting or unsetting environment variables, you may wish to avoid an application restart. This is useful when developing plugins or when setting multiple environment variables in a scripted manner. To do so, use the `--no-restart` flag:
|
||||
@@ -35,23 +41,24 @@ When setting or unsetting environment variables, you may wish to avoid an applic
|
||||
dokku config:set --no-restart node-js-app ENV=prod
|
||||
```
|
||||
|
||||
If you wish to have the variables output in an `eval`-compatible form, you can use the `--export` flag:
|
||||
If you wish to have the variables output in an `eval`-compatible form, you can use the `config:export` command
|
||||
|
||||
```shell
|
||||
dokku config node-js-app --export
|
||||
dokku config:export node-js-app
|
||||
# outputs variables in the form:
|
||||
#
|
||||
# export ENV='prod'
|
||||
# export COMPILE_ASSETS='1'
|
||||
|
||||
# source in all the node-js-app app environment variables
|
||||
eval $(dokku config node-js-app --export)
|
||||
eval $(dokku config:export node-js-app)
|
||||
```
|
||||
|
||||
You can also output the variables in a single-line for usage in command-line utilities with the `--shell` flag:
|
||||
You can control the format of the exported variables with the `--format` flag.
|
||||
`--format=shell` will output the variables in a single-line for usage in command-line utilities:
|
||||
|
||||
```shell
|
||||
dokku config node-js-app --shell
|
||||
dokku config:export --format shell node-js-app
|
||||
|
||||
# outputs variables in the form:
|
||||
#
|
||||
|
||||
@@ -93,7 +93,7 @@ dokku ps:scale node-js-app
|
||||
|
||||
### Stopping applications
|
||||
|
||||
Deployed applications can be stopped using the `ps:stop` command. This turns all running containers for an application, and will result in a `502 Bad Gateway` response for the default nginx proxy implementation.
|
||||
Deployed applications can be stopped using the `ps:stop` command. This turns off all running containers for an application, and will result in a `502 Bad Gateway` response for the default nginx proxy implementation.
|
||||
|
||||
```shell
|
||||
dokku ps:stop node-js-app
|
||||
@@ -115,7 +115,7 @@ By default, Dokku will automatically restart containers that exit with a non-zer
|
||||
|
||||
### Showing the current restart policy
|
||||
|
||||
THe `ps:restart-policy` command will show the currently configured restart policy for an application. The default policy is `on-failure:10`
|
||||
The `ps:restart-policy` command will show the currently configured restart policy for an application. The default policy is `on-failure:10`
|
||||
|
||||
```shell
|
||||
dokku ps:restart-policy node-js-app
|
||||
|
||||
@@ -46,7 +46,7 @@ dokku ssh-keys:add KEY_NAME path/to/id_rsa.pub
|
||||
b7:76:27:4f:30:90:21:ae:d4:1e:70:20:35:3f:06:d6
|
||||
```
|
||||
|
||||
`KEY_NAME` is the username prefer to use to refer to this particular key. Including the word `admin` in the name will grant the user privileges to add additional keys remotely.
|
||||
`KEY_NAME` is the name you want to use to refer to this particular key. Including the word `admin` in the name will grant the user privileges to add additional keys remotely.
|
||||
|
||||
> `KEY_NAME` is a unique name which is used to identify public keys. Attempting to re-use a key name will result in an error. The ssh (git) user is *always* `dokku`, as this is the system user that the `dokku` binary uses to perform all it's actions.
|
||||
|
||||
|
||||
@@ -344,6 +344,141 @@ if [[ ! -f "$DOKKU_ROOT/HOSTNAME" ]]; then
|
||||
fi
|
||||
```
|
||||
|
||||
### `network-build-config`
|
||||
|
||||
- Description: Rebuilds network configuration
|
||||
- Invoked by: `internally triggered by proxy-build-config within proxy implementations`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-compute-ports`
|
||||
|
||||
- Description: Computes the ports for a given app container
|
||||
- Invoked by: `internally triggered by proxy-build-config within proxy implementations`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-config-exists`
|
||||
|
||||
- Description: Returns whether the network configuration for a given app exists
|
||||
- Invoked by: `internally triggered by core-post-deploy within proxy implementations`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-get-ipaddr`
|
||||
|
||||
- Description: Return the ipaddr for a given app container
|
||||
- Invoked by: `internally triggered by a deploy`
|
||||
- Arguments: `$APP $PROC_TYPE $CONTAINER_ID`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-get-listeners`
|
||||
|
||||
- Description: Return the listeners (host:port combinations) for a given app container
|
||||
- Invoked by: `internally triggered by a deploy`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-get-property`
|
||||
|
||||
- Description: Return the network value for an application's property
|
||||
- Invoked by: `internally triggered by a deploy`
|
||||
- Arguments: `$APP $KEY`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-get-port`
|
||||
|
||||
- Description: Return the port for a given app container
|
||||
- Invoked by: `internally triggered by a deploy`
|
||||
- Arguments: `$APP $PROC_TYPE $CONTAINER_ID $IS_HEROKUISH_CONTAINER`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-write-ipaddr`
|
||||
|
||||
- Description: Write the ipaddr for a given app index
|
||||
- Invoked by: `internally triggered by a deploy`
|
||||
- Arguments: `$APP $PROC_TYPE $CONTAINER_INDEX $IP_ADDRESS`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `network-write-port`
|
||||
|
||||
- Description: Write the port for a given app index
|
||||
- Invoked by: `internally triggered by a deploy`
|
||||
- Arguments: `$APP $PROC_TYPE $CONTAINER_INDEX $PORT`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `nginx-hostname`
|
||||
|
||||
- Description: Allows you to customize the hostname for a given application.
|
||||
@@ -410,6 +545,40 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `post-certs-remove`
|
||||
|
||||
- Description: Allows you to run commands after a cert is removed
|
||||
- Invoked by: `dokku certs:remove`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
APP="$1"; verify_app_name "$APP"
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `post-certs-update`
|
||||
|
||||
- Description: Allows you to run commands after a cert is added/updated
|
||||
- Invoked by: `dokku certs:add`, `dokku certs:update`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
APP="$1"; verify_app_name "$APP"
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `post-create`
|
||||
|
||||
- Description: Can be used to run commands after an application is created.
|
||||
@@ -763,10 +932,10 @@ APP="$1"; verify_app_name "$APP"
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `post-certs-update`
|
||||
### `proxy-build-config`
|
||||
|
||||
- Description: Allows you to run commands after a cert is added/updated
|
||||
- Invoked by: `dokku certs:add`, `dokku certs:update`
|
||||
- Description: Builds the proxy implementation configuration for a given app
|
||||
- Invoked by: `internally triggered by ps:restore`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
@@ -774,16 +943,29 @@ APP="$1"; verify_app_name "$APP"
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
APP="$1"; verify_app_name "$APP"
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `post-certs-remove`
|
||||
### `proxy-enable`
|
||||
|
||||
- Description: Allows you to run commands after a cert is removed
|
||||
- Invoked by: `dokku certs:remove`
|
||||
- Description: Enables the configured proxy implementation for an app
|
||||
- Invoked by: `internally triggered by ps:restore`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
# TODO
|
||||
```
|
||||
|
||||
### `proxy-disable`
|
||||
|
||||
- Description: Disables the configured proxy implementation for an app
|
||||
- Invoked by: `internally triggered by ps:restore`
|
||||
- Arguments: `$APP`
|
||||
- Example:
|
||||
|
||||
@@ -791,8 +973,6 @@ APP="$1"; verify_app_name "$APP"
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
APP="$1"; verify_app_name "$APP"
|
||||
|
||||
# TODO
|
||||
```
|
||||
@@ -833,7 +1013,7 @@ newrev=$2
|
||||
APP=${refname/*\//}.$reference_app
|
||||
|
||||
if [[ ! -d "$DOKKU_ROOT/$APP" ]]; then
|
||||
REFERENCE_REPO="$DOKKU_ROOT/$reference_app
|
||||
REFERENCE_REPO="$DOKKU_ROOT/$reference_app"
|
||||
git clone --bare --shared --reference "$REFERENCE_REPO" "$REFERENCE_REPO" "$DOKKU_ROOT/$APP" > /dev/null
|
||||
fi
|
||||
plugn trigger receive-app $APP $newrev
|
||||
@@ -889,7 +1069,7 @@ docker push $DOCKER_HUB_USER/$APP:$IMAGE_TAG
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
APP="$1"; IMAGE_TAG="$2"
|
||||
|
||||
some code to remove a docker hub tag because it's not implemented in the CLI....
|
||||
# some code to remove a docker hub tag because it's not implemented in the CLI...
|
||||
```
|
||||
|
||||
### `uninstall`
|
||||
@@ -899,16 +1079,16 @@ some code to remove a docker hub tag because it's not implemented in the CLI....
|
||||
- Arguments: `$PLUGIN`
|
||||
- Example:
|
||||
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
# Cleanup up extra containers created
|
||||
```shell
|
||||
#!/usr/bin/env bash
|
||||
# Cleanup up extra containers created
|
||||
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
PLUGIN="$1"
|
||||
PLUGIN="$1"
|
||||
|
||||
[[ "$PLUGIN" = "my-plugin" ]] && docker rmi -f "${PLUGIN_IMAGE_DEPENDENCY}"
|
||||
```
|
||||
[[ "$PLUGIN" = "my-plugin" ]] && docker rmi -f "${PLUGIN_IMAGE_DEPENDENCY}"
|
||||
```
|
||||
|
||||
> To avoid uninstalling other plugins make sure to check the plugin name like shown in the example.
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ The workflow looks like this:
|
||||
```shell
|
||||
# having dokku-arch in ../dokku-arch
|
||||
vagrant up build-arch
|
||||
# wait for "==> build-arch: ==> Finished making: dokku 0.10.5-2 (Mon Feb 22 23:20:37 CET 2016)"
|
||||
# wait for "==> build-arch: ==> Finished making: dokku 0.11.2-2 (Mon Feb 22 23:20:37 CET 2016)"
|
||||
cd ../dokku-arch
|
||||
git add PKGBUILD .SRCINFO
|
||||
git commit -m 'Update to dokku 0.9.9'
|
||||
|
||||
@@ -44,6 +44,10 @@ cd dokku
|
||||
sudo BUILD_STACK=true STACK_URL=https://github.com/gliderlabs/herokuish.git make install
|
||||
```
|
||||
|
||||
## Skipping herokuish installation
|
||||
|
||||
The `herokuish` package is recommended but not required if not using Heroku Buildpacks for deployment. Debian-based OS users can run the bootstrap installer via `sudo DOKKU_NO_INSTALL_RECOMMENDS=true bash bootstrap.sh` to skip the dependency. Please note that this will _also_ skip installation of other recommended dependencies.
|
||||
|
||||
## Configuring
|
||||
|
||||
Once Dokku is installed, if you are not using the web-installer, you'll want to configure a the virtualhost setup as well as the push user. If you do not, your installation will be considered incomplete and you will not be able to deploy applications.
|
||||
|
||||
@@ -35,7 +35,7 @@ After setting the desired options, proceed with the installation as described ab
|
||||
| Name | Type | Default | Description |
|
||||
| ------------------ | ------- | --------------------- | ------------------------------------------------------------------------ |
|
||||
| dokku/web_config | boolean | true | Use web-based config for below options |
|
||||
| dokku/vhost_enable | boolean | false | Use vhost-based deployments (e.g. <app>.dokku.me) |
|
||||
| dokku/vhost_enable | boolean | false | Use vhost-based deployments (e.g., <app>.dokku.me) |
|
||||
| dokku/hostname | string | dokku.me | Hostname, used as vhost domain and for showing app URL after deploy |
|
||||
| dokku/skip_key_file| boolean | false | Don't check for the existence of the dokku/key_file. Warning: This setting this to true, will require you to manually add an SSH key later on. |
|
||||
| dokku/skip_key_file| boolean | false | Don't check for the existence of the dokku/key_file. Warning: Setting this to true, will require you to manually add an SSH key later on. |
|
||||
| dokku/key_file | string | /root/.ssh/id_rsa.pub | Path on disk to an SSH key to add to the Dokku user (Will be ignored on `dpkg-reconfigure`) |
|
||||
|
||||
@@ -21,8 +21,8 @@ To install the latest stable version of dokku, you can run the following shell c
|
||||
|
||||
```shell
|
||||
# for debian systems, installs Dokku via apt-get
|
||||
wget https://raw.githubusercontent.com/dokku/dokku/v0.10.5/bootstrap.sh;
|
||||
sudo DOKKU_TAG=v0.10.5 bash bootstrap.sh
|
||||
wget https://raw.githubusercontent.com/dokku/dokku/v0.11.2/bootstrap.sh;
|
||||
sudo DOKKU_TAG=v0.11.2 bash bootstrap.sh
|
||||
```
|
||||
|
||||
The installation process takes about 5-10 minutes, depending upon internet connection speed.
|
||||
|
||||
@@ -10,30 +10,30 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css">
|
||||
<title>Dokku - The smallest PaaS implementation you've ever seen</title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/android-chrome-192x192.png" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/manifest.json">
|
||||
<link rel="shortcut icon" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/android-chrome-192x192.png" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/manifest.json">
|
||||
<link rel="shortcut icon" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon.ico">
|
||||
<meta name="apple-mobile-web-app-title" content="Dokku">
|
||||
<meta name="application-name" content="Dokku">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="msapplication-TileImage" content="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/mstile-144x144.png">
|
||||
<meta name="msapplication-config" content="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/browserconfig.xml">
|
||||
<meta name="msapplication-TileImage" content="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/mstile-144x144.png">
|
||||
<meta name="msapplication-config" content="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/style.css" rel="stylesheet">
|
||||
<link href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/style.css" rel="stylesheet">
|
||||
<!-- <link href="/dokku/docs/assets/style.css" rel="stylesheet"> -->
|
||||
<style>
|
||||
</style>
|
||||
@@ -98,12 +98,12 @@
|
||||
<p class="line">
|
||||
<span class="path"></span>
|
||||
<span class="prompt">$</span>
|
||||
<span class="command">wget https://raw.githubusercontent.com/dokku/dokku/v0.10.5/bootstrap.sh</span>
|
||||
<span class="command">wget https://raw.githubusercontent.com/dokku/dokku/v0.11.2/bootstrap.sh</span>
|
||||
</p>
|
||||
<p class="line">
|
||||
<span class="path"></span>
|
||||
<span class="prompt">$</span>
|
||||
<span class="command">sudo DOKKU_TAG=v0.10.5 bash bootstrap.sh</span>
|
||||
<span class="command">sudo DOKKU_TAG=v0.11.2 bash bootstrap.sh</span>
|
||||
</p>
|
||||
<p class="line">
|
||||
<span class="output"> # go to your server's IP and follow the web installer</span>
|
||||
|
||||
124
docs/networking/network.md
Normal file
124
docs/networking/network.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Network Management
|
||||
|
||||
> New as of 0.11.0
|
||||
|
||||
```
|
||||
network:report [<app>] [<flag>] # Displays a network report for one or more apps
|
||||
network:rebuild <app> # Rebuilds network settings for an app
|
||||
network:rebuildall # Rebuild network settings for all apps
|
||||
network:set <app> <key> (<value>) # Set or clear a network property for an app
|
||||
```
|
||||
|
||||
The Network plugin allows developers to abstract the concept of container network management, allowing developers to both change what networks a given container is attached to as well as rebuild the configuration on the fly.
|
||||
|
||||
## Usage
|
||||
|
||||
### Rebuilding network settings
|
||||
|
||||
There are cases where you may need to rebuild the network configuration for an app, such as on app boot or container restart. In these cases, you can use the `network:rebuild` command:
|
||||
|
||||
```shell
|
||||
dokku network:rebuild node-js-app
|
||||
```
|
||||
|
||||
> This command will exit a non-zero number that depends on the number of containers for which configuration could not be built
|
||||
|
||||
### Rebuilding all network settings
|
||||
|
||||
In some cases, a docker upgrade may reset container IPs or Ports. In both cases, you can quickly rewrite those files by using the `network:rebuildall` command:
|
||||
|
||||
```shell
|
||||
dokku network:rebuildall
|
||||
```
|
||||
|
||||
> This command will exit a non-zero number that depends on the number of containers for which configuration could not be built
|
||||
|
||||
### Container network interface binding
|
||||
|
||||
> This functionality does not control the `--network` docker flag. Please use the [docker-options plugin](docs/advanced-usage/docker-options.md) to manage this flag.
|
||||
|
||||
By default, an application will only bind to the internal interface. This behavior can be modified per app by changing the `bind-all-interfaces` network property.
|
||||
|
||||
```shell
|
||||
# bind to the default docker interface (`docker0`) with a random internal ip
|
||||
# this is the default behavior
|
||||
dokku network:set node-js-app bind-all-interfaces false
|
||||
|
||||
# bind to all interfaces (`0.0.0.0`) on a random port for each upstream port
|
||||
# this will make the app container directly accessible by other hosts on your network
|
||||
# ports are randomized for every deploy, e.g. `0.0.0.0:32771->5000/tcp`.
|
||||
dokku network:set node-js-app bind-all-interfaces true
|
||||
```
|
||||
|
||||
By way of example, in the default case, each container is bound to the docker interface:
|
||||
|
||||
```shell
|
||||
docker ps
|
||||
```
|
||||
|
||||
```
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
1b88d8aec3d1 dokku/node-js-app:latest "/bin/bash -c '/star About a minute ago Up About a minute node-js-app.web.1
|
||||
```
|
||||
|
||||
As such, the container's IP address will be an internal IP, and thus it is only accessible on the host itself:
|
||||
|
||||
```
|
||||
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' node-js-app.web.1
|
||||
```
|
||||
|
||||
```
|
||||
172.17.0.6
|
||||
```
|
||||
|
||||
However, you can disable the internal proxying via the `network:set` command so that it will listen on the host's IP address:
|
||||
|
||||
```shell
|
||||
dokku network:set node-js-app bind-all-interfaces true
|
||||
|
||||
# container bound to all interfaces
|
||||
docker ps
|
||||
```
|
||||
|
||||
```
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
d6499edb0edb dokku/node-js-app:latest "/bin/bash -c '/star About a minute ago Up About a minute 0.0.0.0:49153->5000/tcp node-js-app.web.1
|
||||
```
|
||||
|
||||
### Displaying network reports about an app
|
||||
|
||||
You can get a report about the app's network status using the `network:report` command:
|
||||
|
||||
```shell
|
||||
dokku network:report
|
||||
```
|
||||
|
||||
```
|
||||
=====> node-js-app network information
|
||||
Network bind all interfaces: false
|
||||
Network listeners: 172.17.0.1:5000
|
||||
=====> python-sample network information
|
||||
Network bind all interfaces: false
|
||||
Network listeners: 172.17.0.2:5000
|
||||
=====> ruby-sample network information
|
||||
Network bind all interfaces: true
|
||||
Network listeners:
|
||||
```
|
||||
|
||||
You can run the command for a specific app also.
|
||||
|
||||
```shell
|
||||
dokku network:report node-js-app
|
||||
```
|
||||
|
||||
```
|
||||
=====> node-js-app network information
|
||||
Network bind all interfaces: false
|
||||
Network listeners: 172.17.0.1:5000
|
||||
```
|
||||
|
||||
You can pass flags which will output only the value of the specific information you want. For example:
|
||||
|
||||
```shell
|
||||
dokku network:report node-js-app --network-bind-all-interfaces
|
||||
```
|
||||
@@ -19,46 +19,9 @@ In Dokku 0.5.0, port proxying was decoupled from the `nginx-vhosts` plugin into
|
||||
|
||||
### Container network interface binding
|
||||
|
||||
> New as of 0.5.0
|
||||
> Changed as of 0.11.0
|
||||
|
||||
By default, the deployed docker container running your app's web process will bind to the internal docker network interface (i.e. `docker inspect --format '{{ .NetworkSettings.IPAddress }}' $CONTAINER_ID`). This behavior can be modified per app by disabling the proxy (i.e. `dokku proxy:disable <app>`). In this case, the container will bind to an external interface (i.e. `0.0.0.0`) and your app container will be directly accessible by other hosts on your network.
|
||||
|
||||
> If a proxy is disabled, Dokku will bind your container's port to a random port on the host for every deploy, e.g. `0.0.0.0:32771->5000/tcp`.
|
||||
|
||||
By way of example, in the default case, each container is bound to the docker interface:
|
||||
|
||||
```shell
|
||||
docker ps
|
||||
```
|
||||
|
||||
```
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
1b88d8aec3d1 dokku/node-js-app:latest "/bin/bash -c '/star About a minute ago Up About a minute node-js-app.web.1
|
||||
```
|
||||
|
||||
As such, the container's IP address will be an internal IP, and thus it is only accessible on the host itself:
|
||||
|
||||
```
|
||||
docker inspect --format '{{ .NetworkSettings.IPAddress }}' node-js-app.web.1
|
||||
```
|
||||
|
||||
```
|
||||
172.17.0.6
|
||||
```
|
||||
|
||||
However, you can disable the internal proxying via the `proxy:disable` command so that it will listen on the host's IP address:
|
||||
|
||||
```shell
|
||||
dokku proxy:disable node-js-app
|
||||
|
||||
# container bound to all interfaces
|
||||
docker ps
|
||||
```
|
||||
|
||||
```
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
d6499edb0edb dokku/node-js-app:latest "/bin/bash -c '/star About a minute ago Up About a minute 0.0.0.0:49153->5000/tcp node-js-app.web.1
|
||||
```
|
||||
From Dokku versions `0.5.0` until `0.11.0`, enabling or disabling an application's proxy would **also** control whether or not the application was bound to all interfaces - e.g. `0.0.0.0`. As of `0.11.0`, this is now controlled by the network plugin. Please see the [network documentation](/docs/networking/network.md#container-network-interface-binding) for more information.
|
||||
|
||||
### Displaying proxy reports about an app
|
||||
|
||||
@@ -9,26 +9,26 @@
|
||||
<meta name="author" content="">
|
||||
<title>Dokku - The smallest PaaS implementation you've ever seen</title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/apple-touch-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/android-chrome-192x192.png" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/manifest.json">
|
||||
<link rel="shortcut icon" href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/apple-touch-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/android-chrome-192x192.png" sizes="192x192">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="manifest" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/manifest.json">
|
||||
<link rel="shortcut icon" href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/favicon.ico">
|
||||
<meta name="apple-mobile-web-app-title" content="Dokku">
|
||||
<meta name="application-name" content="Dokku">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="msapplication-TileImage" content="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/mstile-144x144.png">
|
||||
<meta name="msapplication-config" content="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/favicons/browserconfig.xml">
|
||||
<meta name="msapplication-TileImage" content="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/mstile-144x144.png">
|
||||
<meta name="msapplication-config" content="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/favicons/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<script>
|
||||
@@ -42,7 +42,7 @@
|
||||
</script>
|
||||
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.rawgit.com/dokku/dokku/v0.10.5/docs/assets/style.css" rel="stylesheet">
|
||||
<link href="https://cdn.rawgit.com/dokku/dokku/v0.11.2/docs/assets/style.css" rel="stylesheet">
|
||||
<!-- <link href="/dokku/docs/assets/style.css" rel="stylesheet"> -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<style>
|
||||
@@ -136,11 +136,16 @@
|
||||
<a href="#" class="list-group-item disabled">Configuration</a>
|
||||
|
||||
<a href="/{{NAME}}/configuration/environment-variables/" class="list-group-item">Environment Variables</a>
|
||||
<a href="/{{NAME}}/configuration/dns/" class="list-group-item">DNS Configuration</a>
|
||||
<a href="/{{NAME}}/configuration/domains/" class="list-group-item">Domain Configuration</a>
|
||||
<a href="/{{NAME}}/configuration/nginx/" class="list-group-item">Nginx Configuration</a>
|
||||
<a href="/{{NAME}}/configuration/ssl/" class="list-group-item">SSL Configuration</a>
|
||||
|
||||
<a href="#" class="list-group-item disabled">Network Management</a>
|
||||
|
||||
<a href="/{{NAME}}/networking/dns/" class="list-group-item">DNS Configuration</a>
|
||||
<a href="/{{NAME}}/networking/network/" class="list-group-item">Network Management</a>
|
||||
<a href="/{{NAME}}/networking/proxy-management/" class="list-group-item">Proxy and Port Management</a>
|
||||
|
||||
<a href="#" class="list-group-item disabled">Advanced Usage</a>
|
||||
|
||||
<a href="/{{NAME}}/advanced-usage/backup-recovery/" class="list-group-item">Backup and Recovery</a>
|
||||
@@ -149,7 +154,6 @@
|
||||
<a href="/{{NAME}}/advanced-usage/event-logs/" class="list-group-item">Event Logs</a>
|
||||
<a href="/{{NAME}}/advanced-usage/persistent-storage/" class="list-group-item">Persistent Storage</a>
|
||||
<a href="/{{NAME}}/advanced-usage/plugin-management/" class="list-group-item">Plugin Management</a>
|
||||
<a href="/{{NAME}}/advanced-usage/proxy-management/" class="list-group-item">Proxy and Port Management</a>
|
||||
<a href="/{{NAME}}/advanced-usage/repository-management/" class="list-group-item">Repository Management</a>
|
||||
|
||||
<a href="#" class="list-group-item disabled">Community Contributions</a>
|
||||
|
||||
@@ -15,16 +15,19 @@
|
||||
"deployment/images": "deployment/methods/images/",
|
||||
"configuration-management": "configuration/environment-variables/",
|
||||
"deployment/ssl-configuration": "configuration/ssl/",
|
||||
"dns": "configuration/dns/",
|
||||
"nginx": "configuration/nginx/",
|
||||
|
||||
"dns": "networking/dns/",
|
||||
"configuration/dns": "networking/dns/",
|
||||
"proxy": "networking/proxy-management/",
|
||||
"advanced-usage/proxy-management": "networking/proxy-management/",
|
||||
|
||||
"backup-recovery": "advanced-usage/backup-recovery/",
|
||||
"deployment-tasks": "advanced-usage/deployment-tasks/",
|
||||
"deployment/deployment-tasks": "advanced-usage/deployment-tasks/",
|
||||
"docker-options": "advanced-usage/docker-options/",
|
||||
"dokku-events-logs": "advanced-usage/event-logs/",
|
||||
"dokku-storage": "advanced-usage/persistent-storage/",
|
||||
"proxy": "advanced-usage/proxy-management/",
|
||||
|
||||
"plugins": "community/plugins/"
|
||||
}
|
||||
|
||||
@@ -23,8 +23,10 @@ get_phase_script() {
|
||||
|
||||
execute_script() {
|
||||
declare desc="executes appropriate phase script key from app.json"
|
||||
local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
||||
local PHASE_SCRIPT_KEY="$3"
|
||||
local APP="$1"; local IMAGE_TAG="$2"; local PHASE_SCRIPT_KEY="$3"
|
||||
local IMAGE id
|
||||
|
||||
IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
||||
local SCRIPT_CMD=$(get_phase_script "$IMAGE" "$PHASE_SCRIPT_KEY" 2>/dev/null)
|
||||
if [[ -n "$SCRIPT_CMD" ]];then
|
||||
dokku_log_info1 "Running '$SCRIPT_CMD' in app container"
|
||||
@@ -55,8 +57,11 @@ execute_script() {
|
||||
# strip --restart args from DOCKER_ARGS
|
||||
local DOCKER_ARGS=$(sed -e "s/--restart=[[:graph:]]\+[[:blank:]]\?//g" <<< "$DOCKER_ARGS")
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
local id=$(docker run "$DOKKU_GLOBAL_RUN_ARGS" -e DOKKU_TRACE="$DOKKU_TRACE" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_DIR:/cache" $DOCKER_ARGS "$IMAGE" /bin/bash -c "$COMMAND")
|
||||
# eval args as array to respect escapes
|
||||
declare -a ARG_ARRAY
|
||||
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
||||
|
||||
id=$(docker run "$DOKKU_GLOBAL_RUN_ARGS" -e DOKKU_TRACE="$DOKKU_TRACE" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_DIR:/cache" "${ARG_ARRAY[@]}" "$IMAGE" /bin/bash -c "$COMMAND")
|
||||
if test "$(docker wait "$id")" -eq 0; then
|
||||
dokku_container_log_verbose_quiet "$id"
|
||||
if [[ "$PHASE_SCRIPT_KEY" != "postdeploy" ]];then
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core standard plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
@@ -17,6 +17,7 @@ app_user_pre_deploy_trigger() {
|
||||
local desc="app user pre-deploy trigger"
|
||||
local APP="$1"; local IMAGE_TAG="$2"; local IMAGE; local DOCKER_ARGS
|
||||
local DOKKU_APP_TYPE DOKKU_APP_USER APP_PATHS CONTAINER_PATHS
|
||||
declare -a ARG_ARRAY
|
||||
|
||||
IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
|
||||
|
||||
@@ -27,12 +28,15 @@ app_user_pre_deploy_trigger() {
|
||||
|
||||
if [[ -n "$APP_PATHS" ]]; then
|
||||
CONTAINER_PATHS=$(echo "$APP_PATHS" | awk -F ':' '{ print $2 }' | xargs)
|
||||
DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG" | xargs)
|
||||
DOCKER_ARGS=$(: | plugn trigger docker-args-deploy "$APP" "$IMAGE_TAG")
|
||||
# strip --restart args from DOCKER_ARGS
|
||||
DOCKER_ARGS=$(sed -e "s/--restart=[[:graph:]]\+[[:blank:]]\?//g" <<< "$DOCKER_ARGS")
|
||||
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
||||
fi
|
||||
|
||||
if [[ "$DOKKU_APP_TYPE" == "herokuish" ]] && [[ -n "$CONTAINER_PATHS" ]]; then
|
||||
# shellcheck disable=SC2086
|
||||
docker run $DOKKU_GLOBAL_RUN_ARGS $DOCKER_ARGS $IMAGE /bin/bash -c "find $CONTAINER_PATHS -not -user $DOKKU_APP_USER -print0 | xargs -0 -r chown -R $DOKKU_APP_USER" || true
|
||||
docker run $DOKKU_GLOBAL_RUN_ARGS "${ARG_ARRAY[@]}" $IMAGE /bin/bash -c "find $CONTAINER_PATHS -not -user $DOKKU_APP_USER -print0 | xargs -0 -r chown -R $DOKKU_APP_USER" || true
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ dokku_run_cmd() {
|
||||
local DOCKER_ARGS=$(: | plugn trigger docker-args-run "$APP" "$IMAGE_TAG")
|
||||
[[ "$DOKKU_TRACE" ]] && local DOCKER_ARGS+=" -e TRACE=true "
|
||||
|
||||
declare -a ARG_ARRAY
|
||||
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
||||
|
||||
local DOKKU_RUN_OPTS=" -e DYNO=run.$RANDOM"
|
||||
if [[ "$DOKKU_RM_CONTAINER" ]]; then
|
||||
DOKKU_RUN_OPTS+=" --rm"
|
||||
@@ -44,7 +47,7 @@ dokku_run_cmd() {
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
docker run $DOKKU_GLOBAL_RUN_ARGS $DOKKU_RUN_OPTS $DOCKER_ARGS $IMAGE $EXEC_CMD "$@"
|
||||
docker run $DOKKU_GLOBAL_RUN_ARGS $DOKKU_RUN_OPTS "${ARG_ARRAY[@]}" $IMAGE $EXEC_CMD "$@"
|
||||
}
|
||||
|
||||
dokku_run_cmd "$@"
|
||||
|
||||
1
plugins/20_events/network-build-config
Symbolic link
1
plugins/20_events/network-build-config
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-compute-ports
Symbolic link
1
plugins/20_events/network-compute-ports
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-config-exists
Symbolic link
1
plugins/20_events/network-config-exists
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-get-ipaddr
Symbolic link
1
plugins/20_events/network-get-ipaddr
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-get-listeners
Symbolic link
1
plugins/20_events/network-get-listeners
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-get-port
Symbolic link
1
plugins/20_events/network-get-port
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-get-property
Symbolic link
1
plugins/20_events/network-get-property
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-write-ipaddr
Symbolic link
1
plugins/20_events/network-write-ipaddr
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/network-write-port
Symbolic link
1
plugins/20_events/network-write-port
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core events logging plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
1
plugins/20_events/proxy-build-config
Symbolic link
1
plugins/20_events/proxy-build-config
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/proxy-disable
Symbolic link
1
plugins/20_events/proxy-disable
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
1
plugins/20_events/proxy-enable
Symbolic link
1
plugins/20_events/proxy-enable
Symbolic link
@@ -0,0 +1 @@
|
||||
hook
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core apps plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
@@ -6,7 +6,12 @@ app_post_delete() {
|
||||
declare desc="apps post-delete plugin trigger"
|
||||
local trigger="app_post_delete"
|
||||
local APP="$1"; local IMAGE_REPO=$(get_app_image_repo "$APP")
|
||||
[[ -n $APP ]] && rm -rf "${DOKKU_ROOT:?}/$APP" > /dev/null
|
||||
if [[ -n $APP ]]; then
|
||||
# remove contents for apps that are symlinks to other folders
|
||||
rm -rf "${DOKKU_ROOT:?}/$APP/" > /dev/null
|
||||
# then remove the folder and/or the symlink
|
||||
rm -rf "${DOKKU_ROOT:?}/$APP" > /dev/null
|
||||
fi
|
||||
|
||||
# remove all application containers & images
|
||||
# shellcheck disable=SC2046
|
||||
|
||||
@@ -22,8 +22,8 @@ apps_clone_cmd() {
|
||||
|
||||
apps_create "$NEW_APP"
|
||||
pushd "$DOKKU_ROOT/$OLD_APP/." > /dev/null
|
||||
find ./* -not \( -name .cache \) | cpio -pvdmu "$DOKKU_ROOT/$NEW_APP"
|
||||
popd > /dev/null
|
||||
find ./* -not \( -name .cache \) | grep -v "./cache" | cpio -pdmu --quiet "$DOKKU_ROOT/$NEW_APP"
|
||||
popd > /dev/null 2>&1 || pushd "/tmp" > /dev/null
|
||||
|
||||
if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then
|
||||
docker run "$DOKKU_GLOBAL_RUN_ARGS" --rm -v "$NEW_CACHE_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core build-env plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
@@ -6,36 +6,26 @@ source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
build_env_pre_build_buildpack() {
|
||||
declare desc="build-env pre-build-buildpack plugin trigger"
|
||||
local trigger="build_env_pre_build_buildpack"
|
||||
local APP="$1"; local IMAGE=$(get_app_image_name "$APP"); local BUILD_ENV=""
|
||||
local APP="$1"
|
||||
local IMAGE id
|
||||
|
||||
verify_app_name "$APP"
|
||||
IMAGE=$(get_app_image_name "$APP");
|
||||
|
||||
[[ -z $(config_get --global CURL_CONNECT_TIMEOUT) ]] && config_set --global CURL_CONNECT_TIMEOUT=90
|
||||
[[ -z $(config_get --global CURL_TIMEOUT) ]] && config_set --global CURL_TIMEOUT=60
|
||||
|
||||
if [[ -n $(config_export global) ]]; then
|
||||
local BUILD_ENV+=$'\n'
|
||||
local BUILD_ENV+=$(config_export global)
|
||||
local BUILD_ENV+=$'\n'
|
||||
fi
|
||||
if [[ -n $(config_export app "$APP") ]]; then
|
||||
local BUILD_ENV+=$'\n'
|
||||
local BUILD_ENV+=$(config_export app "$APP")
|
||||
local BUILD_ENV+=$'\n'
|
||||
fi
|
||||
dokku_log_info1 "Adding BUILD_ENV to build environment..."
|
||||
# create build env files for use in buildpacks like this:
|
||||
# https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34
|
||||
id=$(config_bundle --merged "$APP" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; cat | tar -x -C /tmp/env")
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
|
||||
if [[ ! -z "$BUILD_ENV" ]]; then
|
||||
dokku_log_info1 "Adding BUILD_ENV to build environment..."
|
||||
# create build env files for use in buildpacks like this:
|
||||
# https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34
|
||||
local id=$(echo $BUILD_ENV | sed -e 's@export @@g' -e 's@\\n@ @g' | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; for ENV_VAR in $(cat); do echo \$ENV_VAR | cut -d'=' -f2- > /tmp/env/\$(echo \$ENV_VAR | cut -d'=' -f1); done " )
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
|
||||
# create build env for 'old style' buildpacks and dokku plugins
|
||||
local id=$(echo -e "$BUILD_ENV" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env")
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
fi
|
||||
# create build env for 'old style' buildpacks and dokku plugins
|
||||
id=$(config_export app "$APP" --format envfile --merged | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env")
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
}
|
||||
|
||||
build_env_pre_build_buildpack "$@"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core certificate management plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core checks plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
@@ -45,18 +45,21 @@ check_process_type() {
|
||||
|
||||
check_process() {
|
||||
local APP="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3"
|
||||
local DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
local DOKKU_IP_FILE="$DOKKU_ROOT/$APP/IP.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
local DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
local CONTAINER_ID DOKKU_CONTAINER_ID_FILE IMAGE IP IS_HEROKUISH_CONTAINER PORT
|
||||
DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
|
||||
if [[ ! -f "$DOKKU_CONTAINER_ID_FILE" ]]; then
|
||||
dokku_log_fail "Invalid container index specified ($APP.$PROC_TYPE.$CONTAINER_INDEX)"
|
||||
fi
|
||||
|
||||
IS_HEROKUISH_CONTAINER=false
|
||||
IMAGE=$(get_app_image_name "$APP")
|
||||
is_image_herokuish_based "$IMAGE" && IS_HEROKUISH_CONTAINER=true
|
||||
|
||||
dokku_log_info1 "Running checks for app ($APP.$PROC_TYPE.$CONTAINER_INDEX)"
|
||||
local CONTAINER_ID=$(< "$DOKKU_CONTAINER_ID_FILE")
|
||||
local IP=$(< "$DOKKU_IP_FILE")
|
||||
local PORT=$(< "$DOKKU_PORT_FILE")
|
||||
CONTAINER_ID=$(< "$DOKKU_CONTAINER_ID_FILE")
|
||||
IP="$(plugn trigger network-get-ipaddr "$APP" "$PROC_TYPE" "$CONTAINER_ID")"
|
||||
PORT="$(plugn trigger network-get-port "$APP" "$PROC_TYPE" "$IS_HEROKUISH_CONTAINER" "$CONTAINER_ID")"
|
||||
plugn trigger check-deploy "$APP" "$CONTAINER_ID" "$PROC_TYPE" "$PORT" "$IP"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
sh "github.com/codeskyblue/go-sh"
|
||||
)
|
||||
@@ -43,42 +46,24 @@ func (sc *ShellCmd) Execute() bool {
|
||||
sc.Command.Stdout = os.Stdout
|
||||
sc.Command.Stderr = os.Stderr
|
||||
}
|
||||
err := sc.Command.Run()
|
||||
if err != nil {
|
||||
if err := sc.Command.Run(); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// VerifyAppName verifies app name format and app existence"
|
||||
func VerifyAppName(appName string) (err error) {
|
||||
dokkuRoot := MustGetEnv("DOKKU_ROOT")
|
||||
appRoot := strings.Join([]string{dokkuRoot, appName}, "/")
|
||||
_, err = os.Stat(appRoot)
|
||||
if os.IsNotExist(err) {
|
||||
return fmt.Errorf("App %s does not exist: %v\n", appName, err)
|
||||
// Output is a lightweight wrapper around exec.Command.Output()
|
||||
func (sc *ShellCmd) Output() ([]byte, error) {
|
||||
env := os.Environ()
|
||||
for k, v := range sc.Env {
|
||||
env = append(env, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
r, _ := regexp.Compile("^[a-z].*")
|
||||
if !r.MatchString(appName) {
|
||||
return fmt.Errorf("App name (%s) must begin with lowercase alphanumeric character\n", appName)
|
||||
sc.Command.Env = env
|
||||
if sc.ShowOutput {
|
||||
sc.Command.Stdout = os.Stdout
|
||||
sc.Command.Stderr = os.Stderr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MustGetEnv returns env variable or fails if it's not set
|
||||
func MustGetEnv(key string) string {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
LogFail(fmt.Sprintf("%s not set!", key))
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// LogFail is the failure log formatter
|
||||
// prints text to stderr and exits with status 1
|
||||
func LogFail(text string) {
|
||||
fmt.Fprintln(os.Stderr, fmt.Sprintf("FAILED: %s", text))
|
||||
os.Exit(1)
|
||||
return sc.Command.Output()
|
||||
}
|
||||
|
||||
// GetDeployingAppImageName returns deploying image identifier for a given app, tag tuple. validate if tag is presented
|
||||
@@ -130,12 +115,242 @@ func GetAppImageRepo(appName string) string {
|
||||
return strings.Join([]string{"dokku", appName}, "/")
|
||||
}
|
||||
|
||||
// ContainerIsRunning checks to see if a container is running
|
||||
func ContainerIsRunning(containerID string) bool {
|
||||
b, err := DockerInspect(containerID, "'{{.State.Running}}'")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.TrimSpace(string(b[:])) == "true"
|
||||
}
|
||||
|
||||
// DirectoryExists returns if a path exists and is a directory
|
||||
func DirectoryExists(filePath string) bool {
|
||||
fi, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return fi.IsDir()
|
||||
}
|
||||
|
||||
// DockerInspect runs an inspect command with a given format against a container id
|
||||
func DockerInspect(containerID, format string) (output string, err error) {
|
||||
b, err := sh.Command("docker", "inspect", "--format", format, containerID).Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
output = strings.TrimSpace(string(b[:]))
|
||||
if strings.HasPrefix(output, "'") && strings.HasSuffix(output, "'") {
|
||||
output = strings.TrimSuffix(strings.TrimPrefix(output, "'"), "'")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DokkuApps returns a list of all local apps
|
||||
func DokkuApps() (apps []string, err error) {
|
||||
dokkuRoot := MustGetEnv("DOKKU_ROOT")
|
||||
files, err := ioutil.ReadDir(dokkuRoot)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("You haven't deployed any applications yet")
|
||||
return
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
appRoot := strings.Join([]string{dokkuRoot, f.Name()}, "/")
|
||||
if !DirectoryExists(appRoot) {
|
||||
continue
|
||||
}
|
||||
if f.Name() == "tls" || strings.HasPrefix(f.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
apps = append(apps, f.Name())
|
||||
}
|
||||
|
||||
if len(apps) == 0 {
|
||||
err = fmt.Errorf("You haven't deployed any applications yet")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FileToSlice reads in all the lines from a file into a string slice
|
||||
func FileToSlice(filePath string) (lines []string, err error) {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if text == "" {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, text)
|
||||
}
|
||||
err = scanner.Err()
|
||||
return
|
||||
}
|
||||
|
||||
// FileExists returns if a path exists and is a file
|
||||
func FileExists(filePath string) bool {
|
||||
fi, err := os.Stat(filePath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return fi.Mode().IsRegular()
|
||||
}
|
||||
|
||||
// GetAppImageName returns image identifier for a given app, tag tuple. validate if tag is presented
|
||||
func GetAppImageName(appName, imageTag, imageRepo string) (imageName string) {
|
||||
err := VerifyAppName(appName)
|
||||
if err != nil {
|
||||
LogFail(err.Error())
|
||||
}
|
||||
|
||||
if imageRepo == "" {
|
||||
imageRepo = GetAppImageRepo(appName)
|
||||
}
|
||||
|
||||
if imageTag == "" {
|
||||
imageName = fmt.Sprintf("%v:latest", imageRepo)
|
||||
} else {
|
||||
imageName = fmt.Sprintf("%v:%v", imageRepo, imageTag)
|
||||
if !VerifyImage(imageName) {
|
||||
LogFail(fmt.Sprintf("app image (%s) not found", imageName))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// IsDeployed returns true if given app has a running container
|
||||
func IsDeployed(appName string) bool {
|
||||
dokkuRoot := MustGetEnv("DOKKU_ROOT")
|
||||
appRoot := strings.Join([]string{dokkuRoot, appName}, "/")
|
||||
files, err := ioutil.ReadDir(appRoot)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if f.Name() == "CONTAINER" || strings.HasPrefix(f.Name(), "CONTAINER.") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsImageHerokuishBased returns true if app image is based on herokuish
|
||||
func IsImageHerokuishBased(image string) bool {
|
||||
// circleci can't support --rm as they run lxc in lxc
|
||||
dockerArgs := ""
|
||||
if !FileExists("/home/ubuntu/.circlerc") {
|
||||
dockerArgs = "--rm"
|
||||
}
|
||||
|
||||
dockerGlobalArgs := os.Getenv("DOKKU_GLOBAL_RUN_ARGS")
|
||||
parts := []string{"docker", "run", dockerGlobalArgs, "--entrypoint=\"/bin/sh\"", dockerArgs, image, "-c", "\"test -f /exec\""}
|
||||
|
||||
var dockerCmdParts []string
|
||||
for _, str := range parts {
|
||||
if str != "" {
|
||||
dockerCmdParts = append(dockerCmdParts, str)
|
||||
}
|
||||
}
|
||||
|
||||
dockerCmd := NewShellCmd(strings.Join(dockerCmdParts, " "))
|
||||
dockerCmd.ShowOutput = false
|
||||
return dockerCmd.Execute()
|
||||
}
|
||||
|
||||
// MustGetEnv returns env variable or fails if it's not set
|
||||
func MustGetEnv(key string) (val string) {
|
||||
val = os.Getenv(key)
|
||||
if val == "" {
|
||||
LogFail(fmt.Sprintf("%s not set!", key))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReadFirstLine gets the first line of a file that has contents and returns it
|
||||
// if there are no contents, an empty string is returned
|
||||
// will also return an empty string if the file does not exist
|
||||
func ReadFirstLine(filename string) (text string) {
|
||||
if !FileExists(filename) {
|
||||
return
|
||||
}
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
if text = strings.TrimSpace(scanner.Text()); text == "" {
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// StripInlineComments removes bash-style comment from input line
|
||||
func StripInlineComments(text string) string {
|
||||
bytes := []byte(text)
|
||||
re := regexp.MustCompile("(?s)#.*")
|
||||
bytes = re.ReplaceAll(bytes, nil)
|
||||
return strings.TrimSpace(string(bytes))
|
||||
}
|
||||
|
||||
// ToBool returns a bool value for a given string
|
||||
func ToBool(s string) bool {
|
||||
return s == "true"
|
||||
}
|
||||
|
||||
// UcFirst uppercases the first character in a string
|
||||
func UcFirst(str string) string {
|
||||
for i, v := range str {
|
||||
return string(unicode.ToUpper(v)) + str[i+1:]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// VerifyAppName verifies app name format and app existence"
|
||||
func VerifyAppName(appName string) (err error) {
|
||||
if appName == "" {
|
||||
return fmt.Errorf("App name must not be null")
|
||||
}
|
||||
dokkuRoot := MustGetEnv("DOKKU_ROOT")
|
||||
appRoot := strings.Join([]string{dokkuRoot, appName}, "/")
|
||||
if !DirectoryExists(appRoot) {
|
||||
return fmt.Errorf("app %s does not exist: %v", appName, err)
|
||||
}
|
||||
r, _ := regexp.Compile("^[a-z0-9].*")
|
||||
if !r.MatchString(appName) {
|
||||
return fmt.Errorf("app name (%s) must begin with lowercase alphanumeric character", appName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// VerifyImage returns true if docker image exists in local repo
|
||||
func VerifyImage(image string) bool {
|
||||
imageCmd := NewShellCmd(strings.Join([]string{"docker inspect", image}, " "))
|
||||
imageCmd.ShowOutput = false
|
||||
if imageCmd.Execute() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return imageCmd.Execute()
|
||||
}
|
||||
|
||||
//PlugnTrigger fire the given plugn trigger with the given args
|
||||
func PlugnTrigger(triggerName string, args ...string) error {
|
||||
shellArgs := make([]interface{}, len(args)+2)
|
||||
shellArgs[0] = "trigger"
|
||||
shellArgs[1] = triggerName
|
||||
for i, arg := range args {
|
||||
shellArgs[i+2] = arg
|
||||
}
|
||||
return sh.Command("plugn", shellArgs...).Run()
|
||||
}
|
||||
|
||||
@@ -1,38 +1,128 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestGetEnv(t *testing.T) {
|
||||
var (
|
||||
testAppName = "test-app-1"
|
||||
testAppDir = strings.Join([]string{"/home/dokku/", testAppName}, "")
|
||||
testEnvFile = strings.Join([]string{testAppDir, "/ENV"}, "")
|
||||
testEnvLine = "export testKey=TESTING"
|
||||
testAppName2 = "01-test-app-1"
|
||||
testAppDir2 = strings.Join([]string{"/home/dokku/", testAppName2}, "")
|
||||
testEnvFile2 = strings.Join([]string{testAppDir2, "/ENV"}, "")
|
||||
testEnvLine2 = "export testKey=TESTING"
|
||||
)
|
||||
|
||||
func setupTestApp() (err error) {
|
||||
Expect(os.MkdirAll(testAppDir, 0644)).To(Succeed())
|
||||
b := []byte(testEnvLine + "\n")
|
||||
if err = ioutil.WriteFile(testEnvFile, b, 0644); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupTestApp2() (err error) {
|
||||
Expect(os.MkdirAll(testAppDir2, 0644)).To(Succeed())
|
||||
b := []byte(testEnvLine2 + "\n")
|
||||
if err = ioutil.WriteFile(testEnvFile2, b, 0644); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func teardownTestApp() {
|
||||
os.RemoveAll(testAppDir)
|
||||
}
|
||||
|
||||
func teardownTestApp2() {
|
||||
os.RemoveAll(testAppDir2)
|
||||
}
|
||||
|
||||
func TestCommonGetEnv(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(MustGetEnv("DOKKU_ROOT")).To(Equal("/home/dokku"))
|
||||
}
|
||||
|
||||
func TestGetAppImageRepo(t *testing.T) {
|
||||
func TestCommonGetAppImageRepo(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(GetAppImageRepo("testapp")).To(Equal("dokku/testapp"))
|
||||
}
|
||||
|
||||
func TestVerifyImageInvalid(t *testing.T) {
|
||||
func TestCommonVerifyImageInvalid(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(VerifyImage("testapp")).To(Equal(false))
|
||||
}
|
||||
|
||||
func TestVerifyAppNameInvalid(t *testing.T) {
|
||||
func TestCommonVerifyAppNameInvalid(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
err := VerifyAppName("1994testApp")
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
func TestVerifyAppName(t *testing.T) {
|
||||
func TestCommonVerifyAppName(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
dir := "/home/dokku/testApp"
|
||||
os.MkdirAll(dir, 0644)
|
||||
err := VerifyAppName("testApp")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
os.RemoveAll(dir)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
Expect(VerifyAppName(testAppName)).To(Succeed())
|
||||
teardownTestApp()
|
||||
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp2()).To(Succeed())
|
||||
Expect(VerifyAppName(testAppName2)).To(Succeed())
|
||||
teardownTestApp2()
|
||||
}
|
||||
|
||||
func TestCommonDokkuAppsError(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
_, err := DokkuApps()
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
func TestCommonDokkuApps(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
apps, err := DokkuApps()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(apps).To(HaveLen(1))
|
||||
Expect(apps[0]).To(Equal(testAppName))
|
||||
teardownTestApp()
|
||||
}
|
||||
|
||||
func TestCommonFileToSlice(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
lines, err := FileToSlice(testEnvFile)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(lines).To(Equal([]string{testEnvLine}))
|
||||
teardownTestApp()
|
||||
}
|
||||
|
||||
func TestCommonFileExists(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
Expect(FileExists(testEnvFile)).To(BeTrue())
|
||||
teardownTestApp()
|
||||
}
|
||||
|
||||
func TestCommonReadFirstLine(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
line := ReadFirstLine(testEnvFile)
|
||||
Expect(line).To(Equal(""))
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
line = ReadFirstLine(testEnvFile)
|
||||
Expect(line).To(Equal(testEnvLine))
|
||||
teardownTestApp()
|
||||
}
|
||||
|
||||
func TestCommonStripInlineComments(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
text := StripInlineComments(strings.Join([]string{testEnvLine, "# testing comment"}, " "))
|
||||
Expect(text).To(Equal(testEnvLine))
|
||||
}
|
||||
|
||||
@@ -440,9 +440,10 @@ dokku_build() {
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
local APP="$1"; local IMAGE_SOURCE_TYPE="$2"; local TMP_WORK_DIR="$3"; local IMAGE=$(get_app_image_name "$APP")
|
||||
local cid
|
||||
verify_app_name "$APP"
|
||||
|
||||
local CACHE_DIR="$DOKKU_ROOT/$APP/cache"
|
||||
local DOKKU_APP_CACHE_DIR="$DOKKU_ROOT/$APP/cache"
|
||||
|
||||
eval "$(config_export app "$APP")"
|
||||
pushd "$TMP_WORK_DIR" &> /dev/null
|
||||
@@ -450,19 +451,21 @@ dokku_build() {
|
||||
case "$IMAGE_SOURCE_TYPE" in
|
||||
herokuish)
|
||||
DOKKU_IMAGE="$(config_get "$APP" DOKKU_IMAGE || echo "$DOKKU_IMAGE")"
|
||||
local id=$(tar -c . | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app")
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
[[ -d $CACHE_DIR ]] || mkdir -p "$CACHE_DIR"
|
||||
cid=$(tar -c . | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app")
|
||||
test "$(docker wait "$cid")" -eq 0
|
||||
docker commit "$cid" "$IMAGE" > /dev/null
|
||||
[[ -d $DOKKU_APP_CACHE_DIR ]] || mkdir -p "$DOKKU_APP_CACHE_DIR"
|
||||
plugn trigger pre-build-buildpack "$APP"
|
||||
|
||||
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$IMAGE_SOURCE_TYPE")
|
||||
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true "
|
||||
declare -a ARG_ARRAY
|
||||
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
||||
# shellcheck disable=SC2086
|
||||
local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -v $CACHE_DIR:/cache -e CACHE_PATH=/cache $DOCKER_ARGS $IMAGE /build)
|
||||
docker attach "$id"
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
cid=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -v $DOKKU_APP_CACHE_DIR:/cache -e CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build)
|
||||
docker attach "$cid"
|
||||
test "$(docker wait "$cid")" -eq 0
|
||||
docker commit "$cid" "$IMAGE" > /dev/null
|
||||
|
||||
plugn trigger post-build-buildpack "$APP"
|
||||
;;
|
||||
@@ -483,9 +486,11 @@ dokku_build() {
|
||||
local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$IMAGE_SOURCE_TYPE")
|
||||
# strip --volume and -v args from DOCKER_ARGS
|
||||
local DOCKER_ARGS=$(sed -e "s/--volume=[[:graph:]]\+[[:blank:]]\?//g" -e "s/-v[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" <<< "$DOCKER_ARGS")
|
||||
declare -a ARG_ARRAY
|
||||
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
docker build $DOCKER_ARGS $DOKKU_DOCKER_BUILD_OPTS -t $IMAGE .
|
||||
docker build "${ARG_ARRAY[@]}" $DOKKU_DOCKER_BUILD_OPTS -t $IMAGE .
|
||||
|
||||
plugn trigger post-build-dockerfile "$APP"
|
||||
;;
|
||||
@@ -501,20 +506,21 @@ dokku_release() {
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
local APP="$1"; local IMAGE_SOURCE_TYPE="$2"; local IMAGE_TAG="$3"; local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
|
||||
local cid
|
||||
verify_app_name "$APP"
|
||||
|
||||
case "$IMAGE_SOURCE_TYPE" in
|
||||
herokuish)
|
||||
plugn trigger pre-release-buildpack "$APP" "$IMAGE_TAG"
|
||||
if [[ -n $(config_export global) ]]; then
|
||||
local id=$(config_export global | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh")
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
cid=$(config_export global | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh")
|
||||
test "$(docker wait "$cid")" -eq 0
|
||||
docker commit "$cid" "$IMAGE" > /dev/null
|
||||
fi
|
||||
if [[ -n $(config_export app "$APP") ]]; then
|
||||
local id=$(config_export app "$APP" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh")
|
||||
test "$(docker wait "$id")" -eq 0
|
||||
docker commit "$id" "$IMAGE" > /dev/null
|
||||
cid=$(config_export app "$APP" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh")
|
||||
test "$(docker wait "$cid")" -eq 0
|
||||
docker commit "$cid" "$IMAGE" > /dev/null
|
||||
fi
|
||||
plugn trigger post-release-buildpack "$APP" "$IMAGE_TAG"
|
||||
;;
|
||||
@@ -536,19 +542,21 @@ dokku_deploy_cmd() {
|
||||
local cmd="deploy"
|
||||
source "$PLUGIN_AVAILABLE_PATH/checks/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
source "$PLUGIN_AVAILABLE_PATH/proxy/functions"
|
||||
|
||||
[[ -z $1 ]] && dokku_log_fail "Please specify an app to run the command on"
|
||||
local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
||||
local APP="$1" IMAGE_TAG="$2"
|
||||
local DOKKU_DOCKER_STOP_TIMEOUT DOKKU_HEROKUISH DOKKU_NETWORK_BIND_ALL IMAGE
|
||||
DOKKU_HEROKUISH=false
|
||||
IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
||||
verify_app_name "$APP"
|
||||
plugn trigger pre-deploy "$APP" "$IMAGE_TAG"
|
||||
|
||||
is_image_herokuish_based "$IMAGE" && local DOKKU_HEROKUISH=true
|
||||
is_image_herokuish_based "$IMAGE" && DOKKU_HEROKUISH=true
|
||||
local DOKKU_SCALE_FILE="$DOKKU_ROOT/$APP/DOKKU_SCALE"
|
||||
local oldids=$(get_app_container_ids "$APP")
|
||||
|
||||
local DOKKU_IS_APP_PROXY_ENABLED="$(is_app_proxy_enabled "$APP")"
|
||||
local DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)"
|
||||
DOKKU_NETWORK_BIND_ALL="$(plugn trigger network-get-property "$APP" bind-all-interfaces)"
|
||||
DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)"
|
||||
[[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}"
|
||||
|
||||
local line; local PROC_TYPE; local PROC_COUNT; local CONTAINER_INDEX
|
||||
@@ -572,10 +580,8 @@ dokku_deploy_cmd() {
|
||||
fi
|
||||
|
||||
while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do
|
||||
local id=""; local port=""; local ipaddr=""
|
||||
local cid=""; local port=""; local ipaddr=""
|
||||
local DOKKU_CONTAINER_ID_FILE="$DOKKU_ROOT/$APP/CONTAINER.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
local DOKKU_IP_FILE="$DOKKU_ROOT/$APP/IP.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
local DOKKU_PORT_FILE="$DOKKU_ROOT/$APP/PORT.$PROC_TYPE.$CONTAINER_INDEX"
|
||||
|
||||
# start the app
|
||||
local DOCKER_ARGS
|
||||
@@ -583,69 +589,63 @@ dokku_deploy_cmd() {
|
||||
DOCKER_ARGS+=" -e DYNO=$PROC_TYPE.$CONTAINER_INDEX "
|
||||
[[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true "
|
||||
|
||||
[[ -n "$DOKKU_HEROKUISH" ]] && local START_CMD="/start $PROC_TYPE"
|
||||
declare -a ARG_ARRAY
|
||||
eval "ARG_ARRAY=($DOCKER_ARGS)"
|
||||
|
||||
if [[ -z "$DOKKU_HEROKUISH" ]]; then
|
||||
local DOKKU_DOCKERFILE_PORTS=($(config_get "$APP" DOKKU_DOCKERFILE_PORTS || true))
|
||||
[[ "$DOKKU_HEROKUISH" == "true" ]] && local START_CMD="/start $PROC_TYPE"
|
||||
|
||||
if [[ "$DOKKU_HEROKUISH" == "false" ]]; then
|
||||
local DOKKU_DOCKERFILE_START_CMD=$(config_get "$APP" DOKKU_DOCKERFILE_START_CMD || true)
|
||||
local DOKKU_PROCFILE_START_CMD=$(get_cmd_from_procfile "$APP" "$PROC_TYPE")
|
||||
local START_CMD=${DOKKU_DOCKERFILE_START_CMD:-$DOKKU_PROCFILE_START_CMD}
|
||||
fi
|
||||
|
||||
if [[ "$PROC_TYPE" == "web" ]]; then
|
||||
if [[ -z "${DOKKU_DOCKERFILE_PORTS[*]}" ]]; then
|
||||
local port=5000
|
||||
local DOKKU_DOCKER_PORT_ARGS+="-p $port"
|
||||
else
|
||||
local p
|
||||
for p in ${DOKKU_DOCKERFILE_PORTS[*]};do
|
||||
if [[ ! "$p" =~ .*udp.* ]]; then
|
||||
# set port to first non-udp port
|
||||
local p=${p//\/tcp}
|
||||
local port=${port:="$p"}
|
||||
fi
|
||||
local DOKKU_DOCKER_PORT_ARGS+=" -p $p "
|
||||
done
|
||||
fi
|
||||
if [[ "$DOKKU_IS_APP_PROXY_ENABLED" == "true" ]]; then
|
||||
# shellcheck disable=SC2086
|
||||
local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD)
|
||||
local ipaddr=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$id")
|
||||
# Docker < 1.9 compatibility
|
||||
if [[ -z $ipaddr ]]; then
|
||||
local ipaddr=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' "$id")
|
||||
ports=($(plugn trigger network-compute-ports "$APP" "$PROC_TYPE" "$DOKKU_HEROKUISH"))
|
||||
local DOKKU_DOCKER_PORT_ARGS=""
|
||||
local DOKKU_PORT=""
|
||||
for p in "${ports[@]}"; do
|
||||
if [[ ! "$p" =~ .*udp.* ]]; then
|
||||
DOKKU_PORT=${DOKKU_PORT:="$p"}
|
||||
fi
|
||||
DOKKU_DOCKER_PORT_ARGS+=" -p $p "
|
||||
done
|
||||
|
||||
if [[ "$DOKKU_NETWORK_BIND_ALL" == "false" ]]; then
|
||||
# shellcheck disable=SC2086
|
||||
cid=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d -e PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD)
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOKKU_DOCKER_PORT_ARGS -e PORT=$port $DOCKER_ARGS $IMAGE $START_CMD)
|
||||
local port=$(docker port "$id" "$port" | sed 's/[0-9.]*://')
|
||||
local ipaddr=127.0.0.1
|
||||
cid=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOKKU_DOCKER_PORT_ARGS -e PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD)
|
||||
fi
|
||||
else
|
||||
# shellcheck disable=SC2086
|
||||
local id=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d $DOCKER_ARGS $IMAGE $START_CMD)
|
||||
cid=$(docker run $DOKKU_GLOBAL_RUN_ARGS -d "${ARG_ARRAY[@]}" $IMAGE $START_CMD)
|
||||
fi
|
||||
|
||||
ipaddr=$(plugn trigger network-get-ipaddr "$APP" "$PROC_TYPE" "$cid")
|
||||
port=$(plugn trigger network-get-port "$APP" "$PROC_TYPE" "$DOKKU_HEROKUISH" "$cid")
|
||||
|
||||
kill_new() {
|
||||
declare desc="wrapper function to kill newly started app container"
|
||||
local id="$1"
|
||||
docker inspect "$id" &> /dev/null && docker stop "$id" > /dev/null && docker kill "$id" &> /dev/null
|
||||
local cid="$1"
|
||||
docker inspect "$cid" &> /dev/null && docker stop "$cid" > /dev/null && docker kill "$cid" &> /dev/null
|
||||
trap - INT TERM EXIT
|
||||
kill -9 $$
|
||||
}
|
||||
|
||||
# run checks first, then post-deploy hooks, which switches proxy traffic
|
||||
trap 'kill_new $id' INT TERM EXIT
|
||||
trap 'kill_new $cid' INT TERM EXIT
|
||||
if [[ "$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")" == "false" ]]; then
|
||||
dokku_log_info1 "Attempting pre-flight checks"
|
||||
plugn trigger check-deploy "$APP" "$id" "$PROC_TYPE" "$port" "$ipaddr"
|
||||
plugn trigger check-deploy "$APP" "$cid" "$PROC_TYPE" "$port" "$ipaddr"
|
||||
fi
|
||||
trap - INT TERM EXIT
|
||||
|
||||
# now using the new container
|
||||
[[ -n "$id" ]] && echo "$id" > "$DOKKU_CONTAINER_ID_FILE"
|
||||
[[ -n "$ipaddr" ]] && echo "$ipaddr" > "$DOKKU_IP_FILE"
|
||||
[[ -n "$port" ]] && echo "$port" > "$DOKKU_PORT_FILE"
|
||||
[[ -n "$cid" ]] && echo "$cid" > "$DOKKU_CONTAINER_ID_FILE"
|
||||
[[ -n "$ipaddr" ]] && plugn trigger network-write-ipaddr "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" "$ipaddr"
|
||||
[[ -n "$port" ]] && plugn trigger network-write-port "$APP" "$PROC_TYPE" "$CONTAINER_INDEX" "$port"
|
||||
|
||||
# cleanup pre-migration files
|
||||
rm -f "$DOKKU_ROOT/$APP/CONTAINER" "$DOKKU_ROOT/$APP/IP" "$DOKKU_ROOT/$APP/PORT"
|
||||
@@ -1046,9 +1046,11 @@ get_app_urls() {
|
||||
echo "$(< "$DOKKU_ROOT/HOSTNAME"):$app_port (container)"
|
||||
done
|
||||
else
|
||||
shopt -s nullglob
|
||||
for PORT_FILE in $DOKKU_ROOT/$APP/PORT.*; do
|
||||
echo "$SCHEME://$(< "$DOKKU_ROOT/HOSTNAME"):$(< "$PORT_FILE") (container)"
|
||||
local DOKKU_APP_LISTENERS PORT
|
||||
DOKKU_APP_LISTENERS="$(plugn trigger network-get-listeners "$APP" | xargs)"
|
||||
for DOKKU_APP_LISTENER in $DOKKU_APP_LISTENERS; do
|
||||
PORT="$(echo "$DOKKU_APP_LISTENER" | cut -d ':' -f2)"
|
||||
echo "$SCHEME://$(< "$DOKKU_ROOT/HOSTNAME"):$PORT (container)"
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
56
plugins/common/log.go
Normal file
56
plugins/common/log.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// LogFail is the failure log formatter
|
||||
// prints text to stderr and exits with status 1
|
||||
func LogFail(text string) {
|
||||
fmt.Fprintln(os.Stderr, fmt.Sprintf("FAILED: %s", text))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// LogInfo1 is the info1 header formatter
|
||||
func LogInfo1(text string) {
|
||||
fmt.Fprintln(os.Stdout, fmt.Sprintf("-----> %s", text))
|
||||
}
|
||||
|
||||
// LogInfo1Quiet is the info1 header formatter (with quiet option)
|
||||
func LogInfo1Quiet(text string) {
|
||||
if os.Getenv("DOKKU_QUIET_OUTPUT") != "" {
|
||||
LogInfo1(text)
|
||||
}
|
||||
}
|
||||
|
||||
// LogInfo2 is the info2 header formatter
|
||||
func LogInfo2(text string) {
|
||||
fmt.Fprintln(os.Stdout, fmt.Sprintf("=====> %s", text))
|
||||
}
|
||||
|
||||
// LogInfo2Quiet is the info2 header formatter (with quiet option)
|
||||
func LogInfo2Quiet(text string) {
|
||||
if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
|
||||
LogInfo2(text)
|
||||
}
|
||||
}
|
||||
|
||||
// LogVerbose is the verbose log formatter
|
||||
// prints indented text to stdout
|
||||
func LogVerbose(text string) {
|
||||
fmt.Fprintln(os.Stdout, fmt.Sprintf(" %s", text))
|
||||
}
|
||||
|
||||
// LogVerboseQuiet is the verbose log formatter
|
||||
// prints indented text to stdout (with quiet option)
|
||||
func LogVerboseQuiet(text string) {
|
||||
if os.Getenv("DOKKU_QUIET_OUTPUT") != "" {
|
||||
LogVerbose(text)
|
||||
}
|
||||
}
|
||||
|
||||
// LogWarn is the warning log formatter
|
||||
func LogWarn(text string) {
|
||||
fmt.Fprintln(os.Stderr, fmt.Sprintf(" ! %s", text))
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core common plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
164
plugins/common/properties.go
Normal file
164
plugins/common/properties.go
Normal file
@@ -0,0 +1,164 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CommandPropertySet is a generic function that will set a property for a given plugin/app combination
|
||||
func CommandPropertySet(pluginName, appName, property, value string, properties map[string]string) {
|
||||
if err := VerifyAppName(appName); err != nil {
|
||||
LogFail(err.Error())
|
||||
}
|
||||
if property == "" {
|
||||
LogFail("No property specified")
|
||||
}
|
||||
|
||||
if _, ok := properties[property]; !ok {
|
||||
properties := reflect.ValueOf(properties).MapKeys()
|
||||
validPropertyList := make([]string, len(properties))
|
||||
for i := 0; i < len(properties); i++ {
|
||||
validPropertyList[i] = properties[i].String()
|
||||
}
|
||||
|
||||
LogFail(fmt.Sprintf("Invalid property specified, valid properties include: %s", strings.Join(validPropertyList, ", ")))
|
||||
}
|
||||
|
||||
if value != "" {
|
||||
LogInfo2Quiet(fmt.Sprintf("Setting %s to %s", property, value))
|
||||
PropertyWrite(pluginName, appName, property, value)
|
||||
} else {
|
||||
LogInfo2Quiet(fmt.Sprintf("Unsetting %s", property))
|
||||
PropertyDelete(pluginName, appName, property)
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyDelete deletes a property from the plugin properties for an app
|
||||
func PropertyDelete(pluginName string, appName string, property string) {
|
||||
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
|
||||
propertyPath := strings.Join([]string{pluginAppConfigRoot, property}, "/")
|
||||
if err := os.Remove(propertyPath); err != nil {
|
||||
LogFail(fmt.Sprintf("Unable to remove %s property %s.%s", pluginName, appName, property))
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyDestroy destroys the plugin properties for an app
|
||||
func PropertyDestroy(pluginName string, appName string) {
|
||||
if appName == "_all_" {
|
||||
pluginConfigPath := getPluginConfigPath(pluginName)
|
||||
os.RemoveAll(pluginConfigPath)
|
||||
} else {
|
||||
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
|
||||
os.RemoveAll(pluginAppConfigRoot)
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyExists returns whether a property exists or not
|
||||
func PropertyExists(pluginName string, appName string, property string) bool {
|
||||
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
|
||||
propertyPath := strings.Join([]string{pluginAppConfigRoot, property}, "/")
|
||||
_, err := os.Stat(propertyPath)
|
||||
return !os.IsNotExist(err)
|
||||
}
|
||||
|
||||
// PropertyGet returns the value for a given property
|
||||
func PropertyGet(pluginName string, appName string, property string) string {
|
||||
return PropertyGetDefault(pluginName, appName, property, "")
|
||||
}
|
||||
|
||||
// PropertyGetDefault returns the value for a given property with a specified default value
|
||||
func PropertyGetDefault(pluginName, appName, property, defaultValue string) (val string) {
|
||||
if !PropertyExists(pluginName, appName, property) {
|
||||
return
|
||||
}
|
||||
|
||||
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
|
||||
propertyPath := strings.Join([]string{pluginAppConfigRoot, property}, "/")
|
||||
|
||||
b, err := ioutil.ReadFile(propertyPath)
|
||||
if err != nil {
|
||||
LogWarn(fmt.Sprintf("Unable to read %s property %s.%s", pluginName, appName, property))
|
||||
return
|
||||
}
|
||||
val = string(b)
|
||||
return
|
||||
}
|
||||
|
||||
// PropertyWrite writes a value for a given application property
|
||||
func PropertyWrite(pluginName string, appName string, property string, value string) {
|
||||
if err := makePropertyPath(pluginName, appName); err != nil {
|
||||
LogFail(fmt.Sprintf("Unable to create %s config directory for %s: %s", pluginName, appName, err.Error()))
|
||||
}
|
||||
|
||||
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
|
||||
propertyPath := strings.Join([]string{pluginAppConfigRoot, property}, "/")
|
||||
file, err := os.Create(propertyPath)
|
||||
if err != nil {
|
||||
LogFail(fmt.Sprintf("Unable to write %s config value %s.%s: %s", pluginName, appName, property, err.Error()))
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fmt.Fprintf(file, value)
|
||||
file.Chmod(0600)
|
||||
setPermissions(propertyPath, 0600)
|
||||
}
|
||||
|
||||
// PropertySetup creates the plugin config root
|
||||
func PropertySetup(pluginName string) (err error) {
|
||||
pluginConfigRoot := getPluginConfigPath(pluginName)
|
||||
if err = os.MkdirAll(pluginConfigRoot, 0755); err != nil {
|
||||
return
|
||||
}
|
||||
return setPermissions(pluginConfigRoot, 0755)
|
||||
}
|
||||
|
||||
// getPluginAppPropertyPath returns the plugin property path for a given plugin/app combination
|
||||
func getPluginAppPropertyPath(pluginName string, appName string) string {
|
||||
return strings.Join([]string{getPluginConfigPath(pluginName), appName}, "/")
|
||||
}
|
||||
|
||||
// getPluginConfigPath returns the plugin property path for a given plugin
|
||||
func getPluginConfigPath(pluginName string) string {
|
||||
return strings.Join([]string{MustGetEnv("DOKKU_LIB_ROOT"), "config", pluginName}, "/")
|
||||
}
|
||||
|
||||
// makePropertyPath ensures that a property path exists
|
||||
func makePropertyPath(pluginName string, appName string) (err error) {
|
||||
pluginAppConfigRoot := getPluginAppPropertyPath(pluginName, appName)
|
||||
if err = os.MkdirAll(pluginAppConfigRoot, 0755); err != nil {
|
||||
return
|
||||
}
|
||||
return setPermissions(pluginAppConfigRoot, 0755)
|
||||
}
|
||||
|
||||
// setPermissions sets the proper owner and filemode for a given file
|
||||
func setPermissions(path string, fileMode os.FileMode) (err error) {
|
||||
if err = os.Chmod(path, fileMode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
group, err := user.LookupGroup("dokku")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
user, err := user.Lookup("dokku")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
uid, err := strconv.Atoi(user.Uid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
gid, err := strconv.Atoi(group.Gid)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return os.Chown(path, uid, gid)
|
||||
}
|
||||
2
plugins/config/.gitignore
vendored
Normal file
2
plugins/config/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/commands
|
||||
/subcommands/*
|
||||
28
plugins/config/Makefile
Normal file
28
plugins/config/Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
include ../../common.mk
|
||||
|
||||
GO_ARGS ?= -a
|
||||
|
||||
SUBCOMMANDS = subcommands/export subcommands/get subcommands/set subcommands/unset subcommands/keys subcommands/bundle
|
||||
|
||||
build-in-docker: clean
|
||||
docker run --rm \
|
||||
-v $$PWD/../..:$(GO_REPO_ROOT) \
|
||||
-w $(GO_REPO_ROOT)/plugins/config \
|
||||
$(BUILD_IMAGE) \
|
||||
bash -c "GO_ARGS='$(GO_ARGS)' make build" || exit $$?
|
||||
|
||||
build: commands subcommands
|
||||
|
||||
commands: **/**/commands.go
|
||||
go build $(GO_ARGS) -o commands src/commands/commands.go
|
||||
|
||||
subcommands: $(SUBCOMMANDS)
|
||||
|
||||
subcommands/%: src/subcommands/*/%.go
|
||||
go build $(GO_ARGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf commands subcommands
|
||||
|
||||
src-clean:
|
||||
rm -rf .gitignore src triggers vendor Makefile *.go
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
[[ " help config:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
|
||||
case "$1" in
|
||||
help | config:help)
|
||||
help_content_func () {
|
||||
declare desc="return config plugin help content"
|
||||
cat<<help_content
|
||||
config (<app>|--global), Display all global or app-specific config vars
|
||||
config:get (<app>|--global) KEY, Display a global or app-specific config value
|
||||
config:set (<app>|--global) KEY1=VALUE1 [KEY2=VALUE2 ...], Set one or more config vars
|
||||
config:unset (<app>|--global) KEY1 [KEY2 ...], Unset one or more config vars
|
||||
help_content
|
||||
}
|
||||
|
||||
if [[ $1 = "config:help" ]] ; then
|
||||
echo -e 'Usage: dokku config[:COMMAND] (<app>|--global)'
|
||||
echo ''
|
||||
echo 'Manage global or app-specific config vars.'
|
||||
echo ''
|
||||
echo 'Additional commands:'
|
||||
help_content_func | sort | column -c2 -t -s,
|
||||
else
|
||||
help_content_func
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
|
||||
;;
|
||||
|
||||
esac
|
||||
119
plugins/config/config.go
Normal file
119
plugins/config/config.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
//Get retreives a value from a config. If appName is empty the global config is used.
|
||||
func Get(appName string, key string) (value string, ok bool) {
|
||||
env, err := loadAppOrGlobalEnv(appName)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if err = validateKey(key); err != nil {
|
||||
return "", false
|
||||
}
|
||||
return env.Get(key)
|
||||
}
|
||||
|
||||
//GetWithDefault gets a value from a config. If appName is empty the global config is used. If the appName or key do not exist defaultValue is returned.
|
||||
func GetWithDefault(appName string, key string, defaultValue string) (value string) {
|
||||
value, ok := Get(appName, key)
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
//SetMany variables in the environment. If appName is empty the global config is used. If restart is true the app is restarted.
|
||||
func SetMany(appName string, entries map[string]string, restart bool) (err error) {
|
||||
global := appName == ""
|
||||
env, err := loadAppOrGlobalEnv(appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
keys := make([]string, 0, len(entries))
|
||||
for k := range entries {
|
||||
if err = validateKey(k); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
for k, v := range entries {
|
||||
env.Set(k, v)
|
||||
keys = append(keys, k)
|
||||
}
|
||||
if len(entries) != 0 {
|
||||
common.LogInfo1("Setting config vars")
|
||||
fmt.Println(prettyPrintEnvEntries(" ", entries))
|
||||
env.Write()
|
||||
triggerUpdate(appName, "set", keys)
|
||||
}
|
||||
if !global && restart && env.GetBoolDefault("DOKKU_APP_RESTORE", true) {
|
||||
triggerRestart(appName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//UnsetMany a value in a config. If appName is empty the global config is used. If restart is true the app is restarted.
|
||||
func UnsetMany(appName string, keys []string, restart bool) (err error) {
|
||||
global := appName == ""
|
||||
env, err := loadAppOrGlobalEnv(appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var changed = false
|
||||
for _, k := range keys {
|
||||
if err = validateKey(k); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, k := range keys {
|
||||
if _, hasKey := env.Map()[k]; hasKey {
|
||||
common.LogInfo1(fmt.Sprintf("Unsetting %s", k))
|
||||
env.Unset(k)
|
||||
changed = true
|
||||
} else {
|
||||
common.LogInfo1(fmt.Sprintf("Skipping %s, it is not set in the environment", k))
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
env.Write()
|
||||
triggerUpdate(appName, "unset", keys)
|
||||
}
|
||||
if !global && restart && env.GetBoolDefault("DOKKU_APP_RESTORE", true) {
|
||||
triggerRestart(appName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func triggerRestart(appName string) {
|
||||
common.LogInfo1(fmt.Sprintf("Restarting app %s", appName))
|
||||
if err := common.PlugnTrigger("app-restart", appName); err != nil {
|
||||
common.LogWarn(fmt.Sprintf("Failure while restarting app: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
func triggerUpdate(appName string, operation string, args []string) {
|
||||
args = append([]string{appName, operation}, args...)
|
||||
if err := common.PlugnTrigger("post-config-update", args...); err != nil {
|
||||
common.LogWarn(fmt.Sprintf("Failure while triggering post-config-update: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
func loadAppOrGlobalEnv(appName string) (env *Env, err error) {
|
||||
if appName == "" || appName == "--global" {
|
||||
return LoadGlobalEnv()
|
||||
}
|
||||
return LoadAppEnv(appName)
|
||||
}
|
||||
|
||||
func validateKey(key string) error {
|
||||
r, _ := regexp.Compile("^[a-zA-Z_][a-zA-Z0-9_]*$")
|
||||
if !r.MatchString(key) {
|
||||
return fmt.Errorf("Invalid key name: '%s'", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
152
plugins/config/config_test.go
Normal file
152
plugins/config/config_test.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var (
|
||||
testAppName = "test-app-1"
|
||||
dokkuRoot = common.MustGetEnv("DOKKU_ROOT")
|
||||
testAppDir = strings.Join([]string{dokkuRoot, testAppName}, "/")
|
||||
globalConfigFile = strings.Join([]string{dokkuRoot, "ENV"}, "/")
|
||||
)
|
||||
|
||||
func setupTestApp() (err error) {
|
||||
Expect(os.MkdirAll(testAppDir, 0766)).To(Succeed())
|
||||
b := []byte("export testKey=TESTING\n")
|
||||
if err = ioutil.WriteFile(strings.Join([]string{testAppDir, "/ENV"}, ""), b, 0644); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b = []byte("export testKey=GLOBAL_TESTING\nexport globalKey=GLOBAL_VALUE")
|
||||
if err = ioutil.WriteFile(globalConfigFile, b, 0644); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func teardownTestApp() {
|
||||
os.RemoveAll(testAppDir)
|
||||
}
|
||||
|
||||
func TestConfigGetWithDefault(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
Expect(GetWithDefault(testAppName, "unknownKey", "UNKNOWN")).To(Equal("UNKNOWN"))
|
||||
Expect(GetWithDefault(testAppName, "testKey", "testKey")).To(Equal("TESTING"))
|
||||
Expect(GetWithDefault(testAppName+"-nonexistent", "testKey", "default")).To(Equal("default"))
|
||||
teardownTestApp()
|
||||
}
|
||||
|
||||
func TestConfigGet(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
expectValue(testAppName, "testKey", "TESTING")
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
|
||||
expectNoValue(testAppName, "testKey2")
|
||||
expectNoValue("", "testKey2")
|
||||
}
|
||||
|
||||
func TestConfigSetMany(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
expectValue(testAppName, "testKey", "TESTING")
|
||||
|
||||
vals := map[string]string{"testKey": "updated", "testKey2": "new"}
|
||||
Expect(SetMany(testAppName, vals, false)).To(Succeed())
|
||||
expectValue(testAppName, "testKey", "updated")
|
||||
expectValue(testAppName, "testKey2", "new")
|
||||
|
||||
vals = map[string]string{"testKey": "updated_global", "testKey2": "new_global"}
|
||||
Expect(SetMany("", vals, false)).To(Succeed())
|
||||
expectValue("", "testKey", "updated_global")
|
||||
expectValue("", "testKey2", "new_global")
|
||||
expectValue("", "globalKey", "GLOBAL_VALUE")
|
||||
expectValue(testAppName, "testKey", "updated")
|
||||
expectValue(testAppName, "testKey2", "new")
|
||||
|
||||
Expect(SetMany(testAppName+"does_not_exist", vals, false)).ToNot(Succeed())
|
||||
}
|
||||
|
||||
func TestConfigUnsetMany(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
expectValue(testAppName, "testKey", "TESTING")
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
|
||||
keys := []string{"testKey", "noKey"}
|
||||
Expect(UnsetMany(testAppName, keys, false)).To(Succeed())
|
||||
expectNoValue(testAppName, "testKey")
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
|
||||
Expect(UnsetMany(testAppName, keys, false)).To(Succeed())
|
||||
expectNoValue(testAppName, "testKey")
|
||||
expectNoValue(testAppName, "globalKey")
|
||||
|
||||
Expect(UnsetMany(testAppName+"does-not-exist", keys, false)).ToNot(Succeed())
|
||||
}
|
||||
|
||||
func TestEnvironmentLoading(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
env, err := LoadMergedAppEnv(testAppName)
|
||||
Expect(err).To(Succeed())
|
||||
v, _ := env.Get("testKey")
|
||||
Expect(v).To(Equal("TESTING"))
|
||||
v, _ = env.Get("globalKey")
|
||||
Expect(v).To(Equal("GLOBAL_VALUE"))
|
||||
Expect(env.Write()).ToNot(Succeed())
|
||||
|
||||
env, err = LoadAppEnv(testAppName)
|
||||
env.Set("testKey", "TESTING-updated")
|
||||
env.Set("testKey2", "TESTING-'\n'-updated")
|
||||
env.Write()
|
||||
|
||||
expectValue(testAppName, "testKey", "TESTING-updated")
|
||||
expectValue(testAppName, "testKey2", "TESTING-'\n'-updated")
|
||||
expectValue("", "testKey", "GLOBAL_TESTING")
|
||||
Expect(err).To(Succeed())
|
||||
}
|
||||
|
||||
func TestInvalidKeys(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
Expect(setupTestApp()).To(Succeed())
|
||||
defer teardownTestApp()
|
||||
|
||||
invalidKeys := []string{"0invalidKey", "invalid:key", "invalid=Key", "!invalidKey"}
|
||||
for _, key := range invalidKeys {
|
||||
Expect(SetMany(testAppName, map[string]string{key: "value"}, false)).NotTo(Succeed())
|
||||
Expect(UnsetMany(testAppName, []string{key}, false)).NotTo(Succeed())
|
||||
value, ok := Get(testAppName, key)
|
||||
Expect(ok).To(Equal(false))
|
||||
value = GetWithDefault(testAppName, key, "default")
|
||||
Expect(value).To(Equal("default"))
|
||||
}
|
||||
}
|
||||
|
||||
func expectValue(appName string, key string, expected string) {
|
||||
v, ok := Get(appName, key)
|
||||
Expect(ok).To(Equal(true))
|
||||
Expect(v).To(Equal(expected))
|
||||
}
|
||||
|
||||
func expectNoValue(appName string, key string) {
|
||||
_, ok := Get(appName, key)
|
||||
Expect(ok).To(Equal(false))
|
||||
}
|
||||
@@ -5,17 +5,17 @@ source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
config_docker_args() {
|
||||
declare desc="config docker-args plugin trigger"
|
||||
local trigger="$0 config_docker_args"
|
||||
local STDIN=$(cat); local APP="$1"; local IMAGE_TAG="$2"; local IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
||||
local DOCKERFILE_ENV_FILE="$DOKKU_ROOT/$APP/DOCKERFILE_ENV_FILE"
|
||||
declare APP="$1" IMAGE_TAG="$2"
|
||||
local ENV_ARGS IMAGE STDIN trigger
|
||||
|
||||
IMAGE=$(get_deploying_app_image_name "$APP" "$IMAGE_TAG")
|
||||
STDIN=$(cat);
|
||||
trigger="$0 config_docker_args"
|
||||
verify_app_name "$APP"
|
||||
|
||||
if ! is_image_herokuish_based "$IMAGE"; then
|
||||
> "$DOCKERFILE_ENV_FILE"
|
||||
config_export global | sed -e "s:^export ::g" -e "s:=':=:g" -e "s:'$::g" > "$DOCKERFILE_ENV_FILE"
|
||||
config_export app "$APP" | sed -e "s:^export ::g" -e "s:=':=:g" -e "s:'$::g" >> "$DOCKERFILE_ENV_FILE"
|
||||
|
||||
echo -n "$STDIN --env-file=$DOCKERFILE_ENV_FILE"
|
||||
ENV_ARGS="$(config_export app "$APP" --format docker-args --merged)"
|
||||
echo -n "$STDIN $ENV_ARGS"
|
||||
else
|
||||
echo -n "$STDIN"
|
||||
fi
|
||||
|
||||
274
plugins/config/environment.go
Normal file
274
plugins/config/environment.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"archive/tar"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
//ExportFormat types of possible exports
|
||||
type ExportFormat int
|
||||
|
||||
const (
|
||||
//ExportFormatExports format: Sourceable exports
|
||||
ExportFormatExports ExportFormat = iota
|
||||
//ExportFormatEnvfile format: dotenv file
|
||||
ExportFormatEnvfile
|
||||
//ExportFormatDockerArgs format: --env args for docker
|
||||
ExportFormatDockerArgs
|
||||
//ExportFormatShell format: env arguments for shell
|
||||
ExportFormatShell
|
||||
//ExportFormatPretty format: pretty-printed in columns
|
||||
ExportFormatPretty
|
||||
)
|
||||
|
||||
//Env is a representation for global or app environment
|
||||
type Env struct {
|
||||
name string
|
||||
filename string
|
||||
env map[string]string
|
||||
}
|
||||
|
||||
//newEnvFromString creates an env from the given ENVFILE contents representation
|
||||
func newEnvFromString(rep string) (env *Env, err error) {
|
||||
envMap, err := godotenv.Unmarshal(rep)
|
||||
env = &Env{
|
||||
name: "<unknown>",
|
||||
filename: "",
|
||||
env: envMap,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//LoadAppEnv loads an environment for the given app
|
||||
func LoadAppEnv(appName string) (env *Env, err error) {
|
||||
appfile, err := getAppFile(appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return loadFromFile(appName, appfile)
|
||||
}
|
||||
|
||||
//LoadMergedAppEnv loads an app environment merged with the global environment
|
||||
func LoadMergedAppEnv(appName string) (env *Env, err error) {
|
||||
env, err = LoadAppEnv(appName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
global, err := LoadGlobalEnv()
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
global.Merge(env)
|
||||
global.filename = ""
|
||||
global.name = env.name
|
||||
return global, err
|
||||
}
|
||||
|
||||
//LoadGlobalEnv loads the global environment
|
||||
func LoadGlobalEnv() (*Env, error) {
|
||||
return loadFromFile("<global>", getGlobalFile())
|
||||
}
|
||||
|
||||
//Get an environment variable
|
||||
func (e *Env) Get(key string) (value string, ok bool) {
|
||||
value, ok = e.env[key]
|
||||
return
|
||||
}
|
||||
|
||||
//GetDefault an environment variable or a default if it doesn't exist
|
||||
func (e *Env) GetDefault(key string, defaultValue string) string {
|
||||
v, ok := e.env[key]
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
//GetBoolDefault gets the bool value of the given key with the given default
|
||||
//right now that is evaluated as `value != "0"`
|
||||
func (e *Env) GetBoolDefault(key string, defaultValue bool) bool {
|
||||
v, ok := e.Get(key)
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
return v != "0"
|
||||
}
|
||||
|
||||
//Set an environment variable
|
||||
func (e *Env) Set(key string, value string) {
|
||||
e.env[key] = value
|
||||
}
|
||||
|
||||
//Unset an environment variable
|
||||
func (e *Env) Unset(key string) {
|
||||
delete(e.env, key)
|
||||
}
|
||||
|
||||
//Keys gets the keys in this environment
|
||||
func (e *Env) Keys() (keys []string) {
|
||||
keys = make([]string, 0, len(e.env))
|
||||
for k := range e.env {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return
|
||||
}
|
||||
|
||||
//Len returns the number of items in this environment
|
||||
func (e *Env) Len() int {
|
||||
return len(e.env)
|
||||
}
|
||||
|
||||
//Map returns the Env as a map
|
||||
func (e *Env) Map() map[string]string {
|
||||
return e.env
|
||||
}
|
||||
|
||||
func (e *Env) String() string {
|
||||
return e.EnvfileString()
|
||||
}
|
||||
|
||||
//Merge merges the given environment on top of the receiver
|
||||
func (e *Env) Merge(other *Env) {
|
||||
for _, k := range other.Keys() {
|
||||
e.Set(k, other.GetDefault(k, ""))
|
||||
}
|
||||
}
|
||||
|
||||
//Write an Env back to the file it was read from as an exportfile
|
||||
func (e *Env) Write() error {
|
||||
if e.filename == "" {
|
||||
return errors.New("this Env was created unbound to a file")
|
||||
}
|
||||
return godotenv.Write(e.Map(), e.filename)
|
||||
}
|
||||
|
||||
//Export the Env in the given format
|
||||
func (e *Env) Export(format ExportFormat) string {
|
||||
switch format {
|
||||
case ExportFormatExports:
|
||||
return e.ExportfileString()
|
||||
case ExportFormatEnvfile:
|
||||
return e.EnvfileString()
|
||||
case ExportFormatDockerArgs:
|
||||
return e.DockerArgsString()
|
||||
case ExportFormatShell:
|
||||
return e.ShellString()
|
||||
case ExportFormatPretty:
|
||||
return prettyPrintEnvEntries("", e.Map())
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Unknown export format: %v", format))
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
//EnvfileString returns the contents of this Env in dotenv format
|
||||
func (e *Env) EnvfileString() string {
|
||||
rep, _ := godotenv.Marshal(e.Map())
|
||||
return rep
|
||||
}
|
||||
|
||||
//ExportfileString returns the contents of this Env as bash exports
|
||||
func (e *Env) ExportfileString() string {
|
||||
return e.stringWithPrefixAndSeparator("export ", "\n")
|
||||
}
|
||||
|
||||
//DockerArgsString gets the contents of this Env in the form -env=KEY=VALUE --env...
|
||||
func (e *Env) DockerArgsString() string {
|
||||
return e.stringWithPrefixAndSeparator("--env=", " ")
|
||||
}
|
||||
|
||||
//ShellString gets the contents of this Env in the form "KEY='value' KEY2='value'"
|
||||
// for passing the environment in the shell
|
||||
func (e *Env) ShellString() string {
|
||||
return e.stringWithPrefixAndSeparator("", " ")
|
||||
}
|
||||
|
||||
//ExportBundle writes a tarfile of the environment to the given io.Writer.
|
||||
// for every environment variable there is a file with the variable's key
|
||||
// with its content set to the variable's value
|
||||
func (e *Env) ExportBundle(dest io.Writer) error {
|
||||
tarfile := tar.NewWriter(dest)
|
||||
defer tarfile.Close()
|
||||
|
||||
for _, k := range e.Keys() {
|
||||
val, _ := e.Get(k)
|
||||
valbin := []byte(val)
|
||||
|
||||
header := &tar.Header{
|
||||
Name: k,
|
||||
Mode: 0600,
|
||||
Size: int64(len(valbin)),
|
||||
}
|
||||
tarfile.WriteHeader(header)
|
||||
tarfile.Write(valbin)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//stringWithPrefixAndSeparator makes a string of the environment
|
||||
// with the given prefix and separator for each entry
|
||||
func (e *Env) stringWithPrefixAndSeparator(prefix string, separator string) string {
|
||||
keys := e.Keys()
|
||||
entries := make([]string, len(keys))
|
||||
for i, k := range keys {
|
||||
v := singleQuoteEscape(e.env[k])
|
||||
entries[i] = fmt.Sprintf("%s%s='%s'", prefix, k, v)
|
||||
}
|
||||
return strings.Join(entries, separator)
|
||||
}
|
||||
|
||||
//singleQuoteEscape escapes the value as if it were shell-quoted in single quotes
|
||||
func singleQuoteEscape(value string) string { // so that 'esc'aped' -> 'esc'\''aped'
|
||||
return strings.Replace(value, "'", "'\\''", -1)
|
||||
}
|
||||
|
||||
//prettyPrintEnvEntries in columns
|
||||
func prettyPrintEnvEntries(prefix string, entries map[string]string) string {
|
||||
colConfig := columnize.DefaultConfig()
|
||||
colConfig.Prefix = prefix
|
||||
colConfig.Delim = "\x00"
|
||||
lines := make([]string, 0, len(entries))
|
||||
for k, v := range entries {
|
||||
lines = append(lines, fmt.Sprintf("%s:\x00%s", k, v))
|
||||
}
|
||||
return columnize.Format(lines, colConfig)
|
||||
}
|
||||
|
||||
func loadFromFile(name string, filename string) (env *Env, err error) {
|
||||
envMap := make(map[string]string)
|
||||
if _, err := os.Stat(filename); err == nil {
|
||||
envMap, err = godotenv.Read(filename)
|
||||
}
|
||||
|
||||
env = &Env{
|
||||
name: name,
|
||||
filename: filename,
|
||||
env: envMap,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getAppFile(appName string) (string, error) {
|
||||
err := common.VerifyAppName(appName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil
|
||||
}
|
||||
|
||||
func getGlobalFile() string {
|
||||
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), "ENV")
|
||||
}
|
||||
102
plugins/config/environment_test.go
Normal file
102
plugins/config/environment_test.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestExportfileRoundtrip(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
env, err := newEnvFromString("HI='ho'\nFoo='Bar'\n\nBaz='BOFF'")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(env.Map()).To(Equal(pairs("Baz", "BOFF", "Foo", "Bar", "HI", "ho")))
|
||||
Expect(env.String()).To(Equal("Baz=\"BOFF\"\nFoo=\"Bar\"\nHI=\"ho\""))
|
||||
|
||||
env, err = newEnvFromString(`export HI="h\no"`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(env.Map()).To(Equal(pairs("HI", "h\no")))
|
||||
Expect(env.String()).To(Equal(`HI="h\no"`))
|
||||
|
||||
env, err = newEnvFromString("HI='ho'\nFOO=\"'\\nBAR=''\"")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(env.Map()).To(Equal(pairs("HI", "ho", "FOO", "'\nBAR=''")))
|
||||
Expect(env.String()).To(Equal("FOO=\"'\\nBAR=''\"\nHI=\"ho\""))
|
||||
|
||||
env, err = newEnvFromString("FOO='bar' ")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(env.Map()).To(Equal(pairs("FOO", "bar")))
|
||||
Expect(env.String()).To(Equal(`FOO="bar"`))
|
||||
|
||||
}
|
||||
|
||||
func TestExportfileErrors(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
|
||||
_, err := newEnvFromString("F\nOO='bar'") //keys cannot have embedded newlines
|
||||
Expect(err).To(HaveOccurred())
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
e, _ := newEnvFromString("FOO='bar'")
|
||||
e2, _ := newEnvFromString("BAR='baz'")
|
||||
e.Merge(e2)
|
||||
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "bar")))
|
||||
|
||||
e3, _ := newEnvFromString("FOO='ba \\nz'")
|
||||
e.Merge(e3)
|
||||
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "ba \nz")))
|
||||
}
|
||||
|
||||
func TestExport(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
e, _ := newEnvFromString("BAR='BAZ'\nFOO='b'ar '\nBAZ='a\\nb'")
|
||||
Expect(e.Export(ExportFormatEnvfile)).To(Equal("BAR=\"BAZ\"\nBAZ=\"a\\nb\"\nFOO=\"b'ar \""))
|
||||
Expect(e.Export(ExportFormatDockerArgs)).To(Equal("--env=BAR='BAZ' --env=BAZ='a\nb' --env=FOO='b'\\''ar '"))
|
||||
Expect(e.Export(ExportFormatShell)).To(Equal("BAR='BAZ' BAZ='a\nb' FOO='b'\\''ar '"))
|
||||
Expect(e.Export(ExportFormatExports)).To(Equal("export BAR='BAZ'\nexport BAZ='a\nb'\nexport FOO='b'\\''ar '"))
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
RegisterTestingT(t)
|
||||
e, err := newEnvFromString("BAR='BAZ'\nFOO='ba\\nr '\nGO='1'\nNOGO='0'")
|
||||
Expect(err).To(Succeed())
|
||||
|
||||
v, ok := e.Get("GO")
|
||||
Expect(ok).To(Equal(true))
|
||||
Expect(v).To(Equal("1"))
|
||||
|
||||
v = e.GetDefault("GO", "default")
|
||||
Expect(v).To(Equal("1"))
|
||||
|
||||
v = e.GetDefault("dne", "default")
|
||||
Expect(v).To(Equal("default"))
|
||||
|
||||
b := e.GetBoolDefault("dne", true)
|
||||
Expect(b).To(Equal(true))
|
||||
|
||||
b = e.GetBoolDefault("dne", false)
|
||||
Expect(b).To(Equal(false))
|
||||
|
||||
b = e.GetBoolDefault("GO", false)
|
||||
Expect(b).To(Equal(true))
|
||||
|
||||
b = e.GetBoolDefault("NOGO", true)
|
||||
Expect(b).To(Equal(false))
|
||||
|
||||
b = e.GetBoolDefault("BAR", false)
|
||||
Expect(b).To(Equal(true)) //anything but "0" is true
|
||||
}
|
||||
|
||||
func pairs(vars ...string) map[string]string {
|
||||
res := map[string]string{}
|
||||
var i = 0
|
||||
for i < len(vars)-1 {
|
||||
key := vars[i]
|
||||
value := vars[i+1]
|
||||
res[key] = value
|
||||
i += 2
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -2,255 +2,61 @@
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
config_sub() {
|
||||
declare desc="executes a config subcommand"
|
||||
local name="$1"
|
||||
shift
|
||||
"$PLUGIN_AVAILABLE_PATH/config/subcommands/$name" "config:$name" "$@"
|
||||
}
|
||||
|
||||
config_export() {
|
||||
declare desc="returns export command for config variable of specified type (app/global)"
|
||||
local CONFIG_TYPE="$1"
|
||||
local APP="$2"
|
||||
local ENV_FILE="$DOKKU_ROOT/$APP/ENV"
|
||||
|
||||
[[ $CONFIG_TYPE == "global" ]] && local ENV_FILE="$DOKKU_ROOT/ENV"
|
||||
[[ ! -f $ENV_FILE ]] && return 0
|
||||
[[ ! -s $ENV_FILE ]] && return 0
|
||||
|
||||
local VARS=$(grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" "$ENV_FILE" | cut -d" " -f2-)
|
||||
echo "$VARS" | awk '{print "export " $0}'
|
||||
shift
|
||||
local APP="$1"
|
||||
if [[ $CONFIG_TYPE == "global" ]]; then
|
||||
APP="--global"
|
||||
else
|
||||
shift
|
||||
fi
|
||||
config_sub export "$@" "$APP"
|
||||
return 0
|
||||
}
|
||||
|
||||
get_sanitized_config_args() {
|
||||
local desc="return sanitized arguments for config plugin"
|
||||
local SANITIZED_ARGS=("$@")
|
||||
|
||||
SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--global/}")
|
||||
SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--no-restart/}")
|
||||
SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--export/}")
|
||||
SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--shell/}")
|
||||
|
||||
echo "${SANITIZED_ARGS[@]}"
|
||||
}
|
||||
|
||||
config_parse_args() {
|
||||
declare desc="parse config plugin args"
|
||||
unset APP ENV_FILE DOKKU_CONFIG_TYPE DOKKU_CONFIG_RESTART DOKKU_CONFIG_EXPORT
|
||||
|
||||
for var; do
|
||||
if [[ "$var" == "--global" ]]; then
|
||||
ENV_FILE="$DOKKU_ROOT/ENV"
|
||||
DOKKU_CONFIG_TYPE="global"
|
||||
DOKKU_CONFIG_RESTART=false
|
||||
fi
|
||||
if [[ "$var" == "--no-restart" ]]; then
|
||||
DOKKU_CONFIG_RESTART=false
|
||||
fi
|
||||
if [[ "$var" == "--export" ]]; then
|
||||
DOKKU_CONFIG_EXPORT=true
|
||||
fi
|
||||
if [[ "$var" == "--shell" ]]; then
|
||||
DOKKU_CONFIG_SHELL=true
|
||||
fi
|
||||
done
|
||||
|
||||
local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
|
||||
set -- "${SANITIZED_ARGS[@]}"
|
||||
|
||||
DOKKU_CONFIG_TYPE=${DOKKU_CONFIG_TYPE:="app"}
|
||||
DOKKU_CONFIG_RESTART=${DOKKU_CONFIG_RESTART:=true}
|
||||
|
||||
if [[ "$DOKKU_CONFIG_TYPE" == "app" ]]; then
|
||||
if [[ -z $2 ]]; then
|
||||
dokku_log_fail "Please specify an app to run the command on"
|
||||
else
|
||||
verify_app_name "$2"
|
||||
APP=${APP:="$2"}
|
||||
ENV_FILE=${ENV_FILE:="$DOKKU_ROOT/$APP/ENV"}
|
||||
fi
|
||||
fi
|
||||
export APP ENV_FILE DOKKU_CONFIG_TYPE DOKKU_CONFIG_RESTART DOKKU_CONFIG_EXPORT
|
||||
}
|
||||
|
||||
config_create () {
|
||||
declare desc="create config env file"
|
||||
local ENV_FILE=$1
|
||||
[[ -f $ENV_FILE ]] || touch "$ENV_FILE"
|
||||
}
|
||||
|
||||
config_styled_hash () {
|
||||
declare desc="internal config hash"
|
||||
local vars="$1"
|
||||
local prefix="$2"
|
||||
local longest=""
|
||||
|
||||
while read -r word; do
|
||||
local KEY=$(echo "$word" | cut -d"=" -f1)
|
||||
if [[ ${#KEY} -gt ${#longest} ]]; then
|
||||
local longest=$KEY
|
||||
fi
|
||||
done <<< "$vars"
|
||||
|
||||
while read -r word; do
|
||||
local KEY=$(echo "$word" | cut -d"=" -f1)
|
||||
local VALUE=$(echo "$word" | cut -d"=" -f2- | sed -e "s/^'//" -e "s/'$//" -e "s/\$$//g")
|
||||
|
||||
local num_zeros=$((${#longest} - ${#KEY}))
|
||||
local zeros=" "
|
||||
while [[ $num_zeros -gt 0 ]]; do
|
||||
local zeros="$zeros "
|
||||
local num_zeros=$((num_zeros - 1))
|
||||
done
|
||||
echo "$prefix$KEY:$zeros$VALUE"
|
||||
done <<< "$vars"
|
||||
}
|
||||
|
||||
config_write() {
|
||||
declare desc="writes config vars out to appropriate file path"
|
||||
local ENV_TEMP="$1"
|
||||
local ENV_FILE_TEMP="${ENV_FILE}.tmp"
|
||||
|
||||
echo "$ENV_TEMP" | sed '/^$/d' | sort > "$ENV_FILE_TEMP"
|
||||
if ! cmp -s "$ENV_FILE" "$ENV_FILE_TEMP"; then
|
||||
cp -f "$ENV_FILE_TEMP" "$ENV_FILE"
|
||||
chmod 600 "$ENV_FILE"
|
||||
fi
|
||||
rm -f "$ENV_FILE_TEMP"
|
||||
}
|
||||
|
||||
config_all() {
|
||||
declare desc="print or export config vars"
|
||||
declare desc="Backwards compatible function for plugin use"
|
||||
[[ "$1" == "config" ]] || set -- "config" "$@"
|
||||
config_parse_args "$@"
|
||||
local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
|
||||
set -- "${SANITIZED_ARGS[@]}"
|
||||
if [[ -n "$DOKKU_CONFIG_EXPORT" ]]; then
|
||||
config_export app "$@"
|
||||
return 0
|
||||
fi
|
||||
|
||||
config_create "$ENV_FILE"
|
||||
[[ $DOKKU_CONFIG_EXPORT ]] && config_export "$DOKKU_CONFIG_TYPE" "$APP" && return 0
|
||||
"$PLUGIN_AVAILABLE_PATH/config/commands" "$@"
|
||||
}
|
||||
|
||||
[[ $APP ]] && local DOKKU_CONFIG_TYPE=$APP
|
||||
[[ ! -s $ENV_FILE ]] && dokku_log_fail "no config vars for $DOKKU_CONFIG_TYPE"
|
||||
|
||||
local VARS=$(grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" "$ENV_FILE" | cut -d" " -f2-)
|
||||
|
||||
[[ $DOKKU_CONFIG_SHELL ]] && echo "$VARS" && return 0
|
||||
|
||||
dokku_log_info2_quiet "$DOKKU_CONFIG_TYPE config vars"
|
||||
config_styled_hash "$VARS"
|
||||
config_keys() {
|
||||
declare desc="returns keys for app or global"
|
||||
config_sub keys "$@"
|
||||
return 0
|
||||
}
|
||||
|
||||
config_get() {
|
||||
declare desc="get value of given config var"
|
||||
[[ "$1" == "config:get" ]] || set -- "config:get" "$@"
|
||||
config_parse_args "$@"
|
||||
local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
|
||||
set -- "${SANITIZED_ARGS[@]}"
|
||||
|
||||
if [[ -z $2 ]]; then
|
||||
echo "Usage: dokku config:get APP KEY"
|
||||
echo "Must specify KEY."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
config_create "$ENV_FILE"
|
||||
if [[ ! -s $ENV_FILE ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
local KEY="${*: -1}"
|
||||
|
||||
grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" "$ENV_FILE" | grep "^export $KEY=" | cut -d"=" -f2- | sed -e "s/^'//" -e "s/'$//"
|
||||
config_sub get "$@"
|
||||
}
|
||||
|
||||
config_set() {
|
||||
declare desc="set value of given config var"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
[[ "$1" == "config:set" ]] || set -- "config:set" "$@"
|
||||
config_parse_args "$@"
|
||||
|
||||
if [[ -z "${*:3}" ]]; then
|
||||
echo "Usage: dokku config:set APP KEY1=VALUE1 [KEY2=VALUE2 ...]"
|
||||
echo "Whitespaces need to be escaped, i.e. KEY=\"VAL\ WITH\ SPACES\""
|
||||
echo "Must specify KEY and VALUE to set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
config_create "$ENV_FILE"
|
||||
local ENV_ADD=""
|
||||
local ENV_TEMP=$(cat "${ENV_FILE}")
|
||||
local RESTART_APP=false
|
||||
shift 2
|
||||
|
||||
for var; do
|
||||
if [[ $var == "--global" ]] || [[ $var == "--no-restart" ]] || ([[ $APP ]] && [[ $var == "$APP" ]]); then
|
||||
shift 1
|
||||
elif [[ $var != *"="* ]]; then
|
||||
echo "Usage: dokku config:set APP KEY1=VALUE1 [KEY2=VALUE2 ...]"
|
||||
echo "Whitespaces need to be escaped, i.e. KEY=\"VAL\ WITH\ SPACES\""
|
||||
echo "Must specify KEY and VALUE to set."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for var; do
|
||||
local KEY=$(echo ${var} | cut -d"=" -f1)
|
||||
local VALUE=$(echo ${var} | cut -d"=" -f2-)
|
||||
|
||||
if [[ $KEY =~ [a-zA-Z_][a-zA-Z0-9_]* ]]; then
|
||||
local RESTART_APP=true
|
||||
local ENV_TEMP=$(echo "${ENV_TEMP}" | sed "/^export $KEY=/ d")
|
||||
local ENV_TEMP="${ENV_TEMP}
|
||||
export $KEY='$VALUE'"
|
||||
local ENV_ADD=$(echo -e "${ENV_ADD}" | sed "/^$KEY=/ d")
|
||||
local ENV_ADD="${ENV_ADD}$
|
||||
${var}"
|
||||
fi
|
||||
done
|
||||
local ENV_ADD=$(echo "$ENV_ADD" | tail -n +2) #remove first empty line
|
||||
|
||||
if [[ $RESTART_APP ]]; then
|
||||
dokku_log_info1 "Setting config vars"
|
||||
config_styled_hash "$ENV_ADD" " "
|
||||
|
||||
config_write "$ENV_TEMP"
|
||||
plugn trigger post-config-update "$APP" "set" "$@"
|
||||
fi
|
||||
|
||||
[[ $APP ]] && local DOKKU_APP_RESTORE=$(config_get "$APP" DOKKU_APP_RESTORE || true)
|
||||
if [[ "$DOKKU_CONFIG_RESTART" == "true" ]] && [[ "$DOKKU_APP_RESTORE" != 0 ]]; then
|
||||
dokku_log_info1 "Restarting app $APP"
|
||||
ps_restart "$APP"
|
||||
fi
|
||||
config_sub set "$@"
|
||||
}
|
||||
|
||||
config_unset() {
|
||||
declare desc="unset given config var"
|
||||
source "$PLUGIN_AVAILABLE_PATH/ps/functions"
|
||||
|
||||
[[ "$1" == "config:unset" ]] || set -- "config:unset" "$@"
|
||||
config_parse_args "$@"
|
||||
local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
|
||||
set -- "${SANITIZED_ARGS[@]}"
|
||||
|
||||
if [[ -z $2 ]]; then
|
||||
echo "Usage: dokku config:unset APP KEY1 [KEY2 ...]"
|
||||
echo "Must specify KEY to unset."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
config_create "$ENV_FILE"
|
||||
local ENV_TEMP=$(cat "${ENV_FILE}")
|
||||
local VARS="${*:2}"
|
||||
|
||||
for var in $VARS; do
|
||||
dokku_log_info1 "Unsetting $var"
|
||||
local ENV_TEMP=$(echo "${ENV_TEMP}" | sed "/^export $var=/ d")
|
||||
|
||||
config_write "$ENV_TEMP"
|
||||
done
|
||||
|
||||
plugn trigger post-config-update "$APP" "unset" "$@"
|
||||
|
||||
[[ $APP ]] && local DOKKU_APP_RESTORE=$(config_get "$APP" DOKKU_APP_RESTORE || true)
|
||||
if [[ "$DOKKU_CONFIG_RESTART" == "true" ]] && [[ "$DOKKU_APP_RESTORE" != 0 ]]; then
|
||||
dokku_log_info1 "Restarting app $APP"
|
||||
ps_restart "$APP"
|
||||
fi
|
||||
declare desc="unset value of given config var"
|
||||
config_sub unset "$@"
|
||||
}
|
||||
|
||||
config_bundle() {
|
||||
declare desc="export tar bundle of config"
|
||||
config_sub bundle "$@"
|
||||
}
|
||||
|
||||
8
plugins/config/glide.lock
generated
Normal file
8
plugins/config/glide.lock
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
hash: dd48defef474bdf5c6e47281a256ca941d71fe1e637d11443fb49acf3e4b5326
|
||||
updated: 2017-09-23T16:25:15.559883959-04:00
|
||||
imports:
|
||||
- name: github.com/joho/godotenv
|
||||
version: a79fa1e548e2c689c241d10173efd51e5d689d5b
|
||||
- name: github.com/ryanuber/columnize
|
||||
version: abc90934186a77966e2beeac62ed966aac0561d5
|
||||
testImports: []
|
||||
8
plugins/config/glide.yaml
Normal file
8
plugins/config/glide.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
package: github.com/dokku/dokku/plugins/config
|
||||
ignore:
|
||||
- github.com/dokku/dokku/plugins/common
|
||||
- github.com/onsi/gomega
|
||||
import:
|
||||
- package: github.com/ryanuber/columnize
|
||||
- package: github.com/joho/godotenv
|
||||
version: ^1.2.0
|
||||
@@ -1,4 +1,4 @@
|
||||
[plugin]
|
||||
description = "dokku core config plugin"
|
||||
version = "0.10.5"
|
||||
version = "0.11.2"
|
||||
[plugin.config]
|
||||
|
||||
68
plugins/config/src/commands/commands.go
Normal file
68
plugins/config/src/commands/commands.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
columnize "github.com/ryanuber/columnize"
|
||||
)
|
||||
|
||||
const (
|
||||
helpHeader = `Usage: dokku config [<app>|--global]
|
||||
|
||||
Display all global or app-specific config vars
|
||||
|
||||
Additional commands:`
|
||||
|
||||
helpContent = `
|
||||
config (<app>|--global), Pretty-print an app or global environment
|
||||
config:get (<app>|--global) KEY, Display a global or app-specific config value
|
||||
config:set (<app>|--global) [--encoded] [--no-restart] KEY1=VALUE1 [KEY2=VALUE2 ...], Set one or more config vars
|
||||
config:unset (<app>|--global) KEY1 [KEY2 ...], Unset one or more config vars
|
||||
config:export (<app>|--global) [--envfile], Export a global or app environment
|
||||
config:keys (<app>|--global) [--merged], Show keys set in environment
|
||||
config:bundle (<app>|--global) [--merged], Bundle environment into tarfile
|
||||
`
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
|
||||
cmd := flag.Arg(0)
|
||||
switch cmd {
|
||||
case "config", "config:show":
|
||||
args := flag.NewFlagSet("config:show", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
shell := args.Bool("shell", false, "--shell: in a single-line for usage in command-line utilities [deprecated]")
|
||||
export := args.Bool("export", false, "--export: print the env as eval-compatible exports [deprecated]")
|
||||
merged := args.Bool("merged", false, "--merged: display the app's envionment merged with the global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandShow(args.Args(), *global, *shell, *export, *merged)
|
||||
case "help":
|
||||
fmt.Print(helpContent)
|
||||
case "config:help":
|
||||
usage()
|
||||
default:
|
||||
dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT"))
|
||||
if err != nil {
|
||||
fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable")
|
||||
dokkuNotImplementExitCode = 10
|
||||
}
|
||||
os.Exit(dokkuNotImplementExitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func usage() {
|
||||
config := columnize.DefaultConfig()
|
||||
config.Delim = ","
|
||||
config.Prefix = " "
|
||||
config.Empty = ""
|
||||
content := strings.Split(helpContent, "\n")[1:]
|
||||
fmt.Println(helpHeader)
|
||||
fmt.Println(columnize.Format(content, config))
|
||||
}
|
||||
16
plugins/config/src/subcommands/bundle/bundle.go
Normal file
16
plugins/config/src/subcommands/bundle/bundle.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
args := flag.NewFlagSet("config:bundle", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandBundle(args.Args(), *global, *merged)
|
||||
}
|
||||
20
plugins/config/src/subcommands/export/export.go
Normal file
20
plugins/config/src/subcommands/export/export.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
// print the environment to stdout
|
||||
func main() {
|
||||
const defaultPrefix = "export "
|
||||
const defaultSeparator = "\n"
|
||||
args := flag.NewFlagSet("config:export", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
|
||||
format := args.String("format", "exports", "--format: [ exports | envfile | docker-args | shell ] which format to export as)")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandExport(args.Args(), *global, *merged, *format)
|
||||
}
|
||||
17
plugins/config/src/subcommands/get/get.go
Normal file
17
plugins/config/src/subcommands/get/get.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
// get the given entries from the specified environment
|
||||
func main() {
|
||||
args := flag.NewFlagSet("config:get", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
quoted := args.Bool("quoted", false, "--quoted: get the value quoted")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandGet(args.Args(), *global, *quoted)
|
||||
}
|
||||
16
plugins/config/src/subcommands/keys/keys.go
Normal file
16
plugins/config/src/subcommands/keys/keys.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
args := flag.NewFlagSet("config:keys", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandKeys(args.Args(), *global, *merged)
|
||||
}
|
||||
18
plugins/config/src/subcommands/set/set.go
Normal file
18
plugins/config/src/subcommands/set/set.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
// set the given entries to the specified environment
|
||||
func main() {
|
||||
args := flag.NewFlagSet("config:set", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
encoded := args.Bool("encoded", false, "--encoded: interpret VALUEs as base64")
|
||||
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandSet(args.Args(), *global, *noRestart, *encoded)
|
||||
}
|
||||
17
plugins/config/src/subcommands/unset/unset.go
Normal file
17
plugins/config/src/subcommands/unset/unset.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/dokku/dokku/plugins/config"
|
||||
)
|
||||
|
||||
//unset the given entries from the given environment
|
||||
func main() {
|
||||
args := flag.NewFlagSet("config:unset", flag.ExitOnError)
|
||||
global := args.Bool("global", false, "--global: use the global environment")
|
||||
noRestart := args.Bool("no-restart", false, "--no-restart: no restart")
|
||||
args.Parse(os.Args[2:])
|
||||
config.CommandUnset(args.Args(), *global, *noRestart)
|
||||
}
|
||||
165
plugins/config/subcommands.go
Normal file
165
plugins/config/subcommands.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dokku/dokku/plugins/common"
|
||||
)
|
||||
|
||||
//CommandShow implements config:show
|
||||
func CommandShow(args []string, global bool, shell bool, export bool, merged bool) {
|
||||
appName, _ := getCommonArgs(global, args)
|
||||
env := getEnvironment(appName, merged)
|
||||
if shell && export {
|
||||
common.LogFail("Only one of --shell and --export can be given")
|
||||
}
|
||||
if shell {
|
||||
fmt.Print(env.Export(ExportFormatShell))
|
||||
} else if export {
|
||||
fmt.Println(env.Export(ExportFormatExports))
|
||||
} else {
|
||||
contextName := "global"
|
||||
if appName != "" {
|
||||
contextName = appName
|
||||
}
|
||||
common.LogInfo2(contextName + " env vars")
|
||||
fmt.Println(env.Export(ExportFormatPretty))
|
||||
}
|
||||
}
|
||||
|
||||
//CommandGet implements config:get
|
||||
func CommandGet(args []string, global bool, quoted bool) {
|
||||
appName, keys := getCommonArgs(global, args)
|
||||
if len(keys) > 1 {
|
||||
common.LogFail(fmt.Sprintf("Unexpected argument(s): %v", keys[1:]))
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
common.LogFail("Expected: key")
|
||||
}
|
||||
if value, ok := Get(appName, keys[0]); !ok {
|
||||
os.Exit(1)
|
||||
} else {
|
||||
if quoted {
|
||||
fmt.Printf("'%s'", singleQuoteEscape(value))
|
||||
} else {
|
||||
fmt.Printf("%s", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//CommandUnset implements config:unset
|
||||
func CommandUnset(args []string, global bool, noRestart bool) {
|
||||
appName, keys := getCommonArgs(global, args)
|
||||
err := UnsetMany(appName, keys, !noRestart)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//CommandSet implements config:set
|
||||
func CommandSet(args []string, global bool, noRestart bool, encoded bool) {
|
||||
appName, pairs := getCommonArgs(global, args)
|
||||
updated := make(map[string]string)
|
||||
for _, e := range pairs {
|
||||
parts := strings.SplitN(e, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
common.LogFail("Invalid env pair: " + e)
|
||||
}
|
||||
key, value := parts[0], parts[1]
|
||||
if encoded {
|
||||
decoded, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
common.LogFail(fmt.Sprintf("%s for key '%s'", err.Error(), key))
|
||||
}
|
||||
value = string(decoded)
|
||||
}
|
||||
updated[key] = value
|
||||
}
|
||||
err := SetMany(appName, updated, !noRestart)
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
//CommandKeys implements config:keys
|
||||
func CommandKeys(args []string, global bool, merged bool) {
|
||||
appName, trailingArgs := getCommonArgs(global, args)
|
||||
if len(trailingArgs) > 0 {
|
||||
common.LogFail(fmt.Sprintf("Trailing argument(s): %v", trailingArgs))
|
||||
}
|
||||
env := getEnvironment(appName, merged)
|
||||
for _, k := range env.Keys() {
|
||||
fmt.Println(k)
|
||||
}
|
||||
}
|
||||
|
||||
//CommandExport implements config:export
|
||||
func CommandExport(args []string, global bool, merged bool, format string) {
|
||||
appName, trailingArgs := getCommonArgs(global, args)
|
||||
if len(trailingArgs) > 0 {
|
||||
common.LogFail(fmt.Sprintf("Trailing argument(s): %v", trailingArgs))
|
||||
}
|
||||
env := getEnvironment(appName, merged)
|
||||
exportType := ExportFormatExports
|
||||
suffix := "\n"
|
||||
switch format {
|
||||
case "exports":
|
||||
exportType = ExportFormatExports
|
||||
case "envfile":
|
||||
exportType = ExportFormatEnvfile
|
||||
case "docker-args":
|
||||
exportType = ExportFormatDockerArgs
|
||||
case "shell":
|
||||
exportType = ExportFormatShell
|
||||
suffix = " "
|
||||
case "pretty":
|
||||
exportType = ExportFormatPretty
|
||||
default:
|
||||
common.LogFail(fmt.Sprintf("Unknown export format: %v", format))
|
||||
}
|
||||
exported := env.Export(exportType)
|
||||
fmt.Print(exported + suffix)
|
||||
}
|
||||
|
||||
//CommandBundle implements config:bundle
|
||||
func CommandBundle(args []string, global bool, merged bool) {
|
||||
appName, trailingArgs := getCommonArgs(global, args)
|
||||
if len(trailingArgs) > 0 {
|
||||
common.LogFail(fmt.Sprintf("Trailing argument(s): %v", trailingArgs))
|
||||
}
|
||||
env := getEnvironment(appName, merged)
|
||||
env.ExportBundle(os.Stdout)
|
||||
}
|
||||
|
||||
//getEnvironment for the given app (global config if appName is empty). Merge with global environment if merged is true.
|
||||
func getEnvironment(appName string, merged bool) (env *Env) {
|
||||
var err error
|
||||
if appName != "" && merged {
|
||||
env, err = LoadMergedAppEnv(appName)
|
||||
} else {
|
||||
env, err = loadAppOrGlobalEnv(appName)
|
||||
}
|
||||
if err != nil {
|
||||
common.LogFail(err.Error())
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
//getCommonArgs extracts common positional args (appName and keys)
|
||||
func getCommonArgs(global bool, args []string) (appName string, keys []string) {
|
||||
keys = args
|
||||
if !global {
|
||||
if len(args) > 0 {
|
||||
appName = args[0]
|
||||
}
|
||||
if appName == "" {
|
||||
common.LogFail("Please specify an app or --global")
|
||||
} else {
|
||||
keys = args[1:]
|
||||
}
|
||||
}
|
||||
return appName, keys
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
config_main_cmd() {
|
||||
declare desc="print config vars for app via command line"
|
||||
local cmd="config"
|
||||
config_all "$@"
|
||||
}
|
||||
|
||||
config_main_cmd "$@"
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
config_get_cmd() {
|
||||
declare desc="get specified config vars from app via command line"
|
||||
local cmd="config:get"
|
||||
config_get "$@"
|
||||
}
|
||||
|
||||
config_get_cmd "$@"
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
config_set_cmd() {
|
||||
declare desc="set specified config vars for app via command line"
|
||||
local cmd="config:set"
|
||||
config_set "$@"
|
||||
}
|
||||
|
||||
config_set_cmd "$@"
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_AVAILABLE_PATH/config/functions"
|
||||
|
||||
config_unset_cmd() {
|
||||
declare desc="unset specified config vars for app via command line"
|
||||
local cmd="config:unset"
|
||||
config_unset "$@"
|
||||
}
|
||||
|
||||
config_unset_cmd "$@"
|
||||
1
plugins/config/vendor/github.com/joho/godotenv/.gitignore
generated
vendored
Normal file
1
plugins/config/vendor/github.com/joho/godotenv/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
8
plugins/config/vendor/github.com/joho/godotenv/.travis.yml
generated
vendored
Normal file
8
plugins/config/vendor/github.com/joho/godotenv/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
23
plugins/config/vendor/github.com/joho/godotenv/LICENCE
generated
vendored
Normal file
23
plugins/config/vendor/github.com/joho/godotenv/LICENCE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2013 John Barton
|
||||
|
||||
MIT License
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
||||
|
||||
163
plugins/config/vendor/github.com/joho/godotenv/README.md
generated
vendored
Normal file
163
plugins/config/vendor/github.com/joho/godotenv/README.md
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
# GoDotEnv [](https://travis-ci.org/joho/godotenv) [](https://ci.appveyor.com/project/joho/godotenv) [](https://goreportcard.com/report/github.com/joho/godotenv)
|
||||
|
||||
A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
|
||||
|
||||
From the original Library:
|
||||
|
||||
> Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
|
||||
>
|
||||
> But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a .env file into ENV when the environment is bootstrapped.
|
||||
|
||||
It can be used as a library (for loading in env for your own daemons etc) or as a bin command.
|
||||
|
||||
There is test coverage and CI for both linuxish and windows environments, but I make no guarantees about the bin version working on windows.
|
||||
|
||||
## Installation
|
||||
|
||||
As a library
|
||||
|
||||
```shell
|
||||
go get github.com/joho/godotenv
|
||||
```
|
||||
|
||||
or if you want to use it as a bin command
|
||||
```shell
|
||||
go get github.com/joho/godotenv/cmd/godotenv
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Add your application configuration to your `.env` file in the root of your project:
|
||||
|
||||
```shell
|
||||
S3_BUCKET=YOURS3BUCKET
|
||||
SECRET_KEY=YOURSECRETKEYGOESHERE
|
||||
```
|
||||
|
||||
Then in your Go app you can do something like
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/joho/godotenv"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
|
||||
s3Bucket := os.Getenv("S3_BUCKET")
|
||||
secretKey := os.Getenv("SECRET_KEY")
|
||||
|
||||
// now do something with s3 or whatever
|
||||
}
|
||||
```
|
||||
|
||||
If you're even lazier than that, you can just take advantage of the autoload package which will read in `.env` on import
|
||||
|
||||
```go
|
||||
import _ "github.com/joho/godotenv/autoload"
|
||||
```
|
||||
|
||||
While `.env` in the project root is the default, you don't have to be constrained, both examples below are 100% legit
|
||||
|
||||
```go
|
||||
_ = godotenv.Load("somerandomfile")
|
||||
_ = godotenv.Load("filenumberone.env", "filenumbertwo.env")
|
||||
```
|
||||
|
||||
If you want to be really fancy with your env file you can do comments and exports (below is a valid env file)
|
||||
|
||||
```shell
|
||||
# I am a comment and that is OK
|
||||
SOME_VAR=someval
|
||||
FOO=BAR # comments at line end are OK too
|
||||
export BAR=BAZ
|
||||
```
|
||||
|
||||
Or finally you can do YAML(ish) style
|
||||
|
||||
```yaml
|
||||
FOO: bar
|
||||
BAR: baz
|
||||
```
|
||||
|
||||
as a final aside, if you don't want godotenv munging your env you can just get a map back instead
|
||||
|
||||
```go
|
||||
var myEnv map[string]string
|
||||
myEnv, err := godotenv.Read()
|
||||
|
||||
s3Bucket := myEnv["S3_BUCKET"]
|
||||
```
|
||||
|
||||
... or from an `io.Reader` instead of a local file
|
||||
|
||||
```go
|
||||
reader := getRemoteFile()
|
||||
myEnv, err := godotenv.Parse(reader)
|
||||
```
|
||||
|
||||
... or from a `string` if you so desire
|
||||
|
||||
```go
|
||||
content := getRemoteFileContent()
|
||||
myEnv, err := godotenv.Unmarshal(content)
|
||||
```
|
||||
|
||||
### Command Mode
|
||||
|
||||
Assuming you've installed the command as above and you've got `$GOPATH/bin` in your `$PATH`
|
||||
|
||||
```
|
||||
godotenv -f /some/path/to/.env some_command with some args
|
||||
```
|
||||
|
||||
If you don't specify `-f` it will fall back on the default of loading `.env` in `PWD`
|
||||
|
||||
### Writing Env Files
|
||||
|
||||
Godotenv can also write a map representing the environment to a correctly-formatted and escaped file
|
||||
|
||||
```go
|
||||
env, err := godotenv.Unmarshal("KEY=value")
|
||||
err := godotenv.Write(env, "./.env")
|
||||
```
|
||||
|
||||
... or to a string
|
||||
|
||||
```go
|
||||
env, err := godotenv.Unmarshal("KEY=value")
|
||||
content, err := godotenv.Marshal(env)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are most welcome! The parser itself is pretty stupidly naive and I wouldn't be surprised if it breaks with edge cases.
|
||||
|
||||
*code changes without tests will not be accepted*
|
||||
|
||||
1. Fork it
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
3. Commit your changes (`git commit -am 'Added some feature'`)
|
||||
4. Push to the branch (`git push origin my-new-feature`)
|
||||
5. Create new Pull Request
|
||||
|
||||
## Releases
|
||||
|
||||
Releases should follow [Semver](http://semver.org/) though the first couple of releases are `v1` and `v1.1`.
|
||||
|
||||
Use [annotated tags for all releases](https://github.com/joho/godotenv/issues/30). Example `git tag -a v1.2.1`
|
||||
|
||||
## CI
|
||||
|
||||
Linux: [](https://travis-ci.org/joho/godotenv) Windows: [](https://ci.appveyor.com/project/joho/godotenv)
|
||||
|
||||
## Who?
|
||||
|
||||
The original library [dotenv](https://github.com/bkeepers/dotenv) was written by [Brandon Keepers](http://opensoul.org/), and this port was done by [John Barton](http://whoisjohnbarton.com) based off the tests/fixtures in the original library.
|
||||
15
plugins/config/vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
Normal file
15
plugins/config/vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package autoload
|
||||
|
||||
/*
|
||||
You can just read the .env file on import just by doing
|
||||
|
||||
import _ "github.com/joho/godotenv/autoload"
|
||||
|
||||
And bob's your mother's brother
|
||||
*/
|
||||
|
||||
import "github.com/joho/godotenv"
|
||||
|
||||
func init() {
|
||||
godotenv.Load()
|
||||
}
|
||||
54
plugins/config/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go
generated
vendored
Normal file
54
plugins/config/vendor/github.com/joho/godotenv/cmd/godotenv/cmd.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var showHelp bool
|
||||
flag.BoolVar(&showHelp, "h", false, "show help")
|
||||
var rawEnvFilenames string
|
||||
flag.StringVar(&rawEnvFilenames, "f", "", "comma separated paths to .env files")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
usage := `
|
||||
Run a process with a env setup from a .env file
|
||||
|
||||
godotenv [-f ENV_FILE_PATHS] COMMAND_ARGS
|
||||
|
||||
ENV_FILE_PATHS: comma separated paths to .env files
|
||||
COMMAND_ARGS: command and args you want to run
|
||||
|
||||
example
|
||||
godotenv -f /path/to/something/.env,/another/path/.env fortune
|
||||
`
|
||||
// if no args or -h flag
|
||||
// print usage and return
|
||||
args := flag.Args()
|
||||
if showHelp || len(args) == 0 {
|
||||
fmt.Println(usage)
|
||||
return
|
||||
}
|
||||
|
||||
// load env
|
||||
var envFilenames []string
|
||||
if rawEnvFilenames != "" {
|
||||
envFilenames = strings.Split(rawEnvFilenames, ",")
|
||||
}
|
||||
|
||||
// take rest of args and "exec" them
|
||||
cmd := args[0]
|
||||
cmdArgs := args[1:]
|
||||
|
||||
err := godotenv.Exec(envFilenames, cmd, cmdArgs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/equals.env
generated
vendored
Normal file
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/equals.env
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export OPTION_A='postgres://localhost:5432/database?sslmode=disable'
|
||||
|
||||
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/exported.env
generated
vendored
Normal file
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/exported.env
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export OPTION_A=2
|
||||
export OPTION_B='\n'
|
||||
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/invalid1.env
generated
vendored
Normal file
2
plugins/config/vendor/github.com/joho/godotenv/fixtures/invalid1.env
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
INVALID LINE
|
||||
foo=bar
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user