diff --git a/.dockerignore b/.dockerignore index 977ed7878..29683e292 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,6 +7,7 @@ build docs tests !build/dokku.deb +!tests/dhparam.pem !contrib/dokku-installer.py !contrib/dokku-update !contrib/bash-completion diff --git a/Dockerfile b/Dockerfile index 3dc52667a..c87e78ae0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,22 +10,25 @@ ARG DOKKU_SKIP_KEY_FILE=true ARG DOKKU_VHOST_ENABLE=false ARG DOKKU_WEB_CONFIG=false -COPY ./build/dokku.deb /tmp/dokku.deb - RUN addgroup --gid $DOKKU_GID dokku \ && adduser --uid $DOKKU_UID --gid $DOKKU_GID --disabled-password --gecos "" "dokku" +COPY ./tests/dhparam.pem /tmp/dhparam.pem +COPY ./build/dokku.deb /tmp/dokku.deb RUN echo "dokku dokku/hostname string $DOKKU_HOSTNAME" | debconf-set-selections \ && echo "dokku dokku/skip_key_file boolean $DOKKU_SKIP_KEY_FILE" | debconf-set-selections \ && echo "dokku dokku/vhost_enable boolean $DOKKU_VHOST_ENABLE" | debconf-set-selections \ && echo "dokku dokku/web_config boolean $DOKKU_WEB_CONFIG" | debconf-set-selections \ && curl -sSL https://packagecloud.io/dokku/dokku/gpgkey | apt-key add - \ && echo "deb https://packagecloud.io/dokku/dokku/ubuntu/ bionic main" | tee /etc/apt/sources.list.d/dokku.list \ + && mkdir -p /etc/nginx/ \ + && cp /tmp/dhparam.pem /etc/nginx/dhparam.pem \ && apt-get update -qq \ - && apt-get install --no-install-recommends --only-upgrade -y -qq openssl openssh-server \ - && apt --no-install-recommends -qq -y install rsync /tmp/dokku.deb \ - && apt-get purge -y -q syslog-ng-core \ - && apt-get autoremove -y -q \ + && apt-get upgrade -qq -y \ + && apt-get install --no-install-recommends --only-upgrade -qq -y openssl openssh-server \ + && apt install --no-install-recommends -qq -y rsync /tmp/dokku.deb \ + && apt-get purge -qq -y syslog-ng-core \ + && apt-get autoremove -qq -y \ && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* WORKDIR /tmp @@ -47,6 +50,7 @@ RUN \ && ln -sf /mnt/dokku/var/lib/dokku/config /var/lib/dokku/config \ && ln -sf /mnt/dokku/var/lib/dokku/data /var/lib/dokku/data \ && mv /etc/my_init.d/00_regen_ssh_host_keys.sh /etc/my_init.d/15_regen_ssh_host_keys \ - && rm /etc/nginx/sites-enabled/default /usr/share/nginx/html/index.html /etc/my_init.d/10_syslog-ng.init \ + && rm -f /etc/nginx/sites-enabled/default /usr/share/nginx/html/index.html /etc/my_init.d/10_syslog-ng.init \ + && rm -f /usr/local/openresty/nginx/conf/sites-enabled/default /usr/share/openresty/html/index.html \ && sed -i '/imklog/d' /etc/rsyslog.conf \ - && rm /var/log/btmp /var/log/wtmp /var/log/*log /var/log/apt/* /var/log/dokku/* /var/log/nginx/* + && rm -f /var/log/btmp /var/log/wtmp /var/log/*log /var/log/apt/* /var/log/dokku/* /var/log/nginx/* /var/log/openresty/* diff --git a/common.mk b/common.mk index 82b9edaeb..d2841ffca 100644 --- a/common.mk +++ b/common.mk @@ -1,4 +1,41 @@ +GO_ARGS ?= -a GO_REPO_ROOT := /go/src/github.com/dokku/dokku BUILD_IMAGE := golang:1.12 .PHONY: build-in-docker build clean src-clean + +build: $(BUILD) + +build-in-docker: clean + mkdir -p /tmp/dokku-go-build-cache + docker run --rm \ + -v $$PWD/../..:$(GO_REPO_ROOT) \ + -v /tmp/dokku-go-build-cache:/root/.cache/go-build \ + -e PLUGIN_NAME=$(PLUGIN_NAME) \ + -w $(GO_REPO_ROOT)/plugins/$(PLUGIN_NAME) \ + $(BUILD_IMAGE) \ + bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$? + +clean: + rm -rf commands subcommands triggers + find . -xtype l -delete + +commands: **/**/commands.go + go build $(GO_ARGS) -o commands src/commands/commands.go + +subcommands: + go build $(GO_ARGS) -o subcommands/subcommands src/subcommands/subcommands.go + $(MAKE) $(SUBCOMMANDS) + +subcommands/%: + ln -sf subcommands $@ + +src-clean: + rm -rf .gitignore src vendor Makefile *.go glide.* + +triggers: + go build $(GO_ARGS) -o triggers src/triggers/triggers.go + $(MAKE) $(TRIGGERS) + +triggers/%: + ln -sf triggers $(shell echo $@ | cut -d '/' -f2) diff --git a/contrib/bash-completion b/contrib/bash-completion index 8923244f1..ca4b0b09a 100644 --- a/contrib/bash-completion +++ b/contrib/bash-completion @@ -1,4 +1,4 @@ -# bash completion for dd -*- shell-script -*- +# bash completion for dokku -*- shell-script -*- _dokku_complete_verify() { declare desc="shows bash completion" diff --git a/contrib/copy-packages b/contrib/copy-packages index 69282e35b..24ad42482 100644 --- a/contrib/copy-packages +++ b/contrib/copy-packages @@ -42,7 +42,7 @@ def main(): download_urls['downloads/' + version['filename']] = version['download_url'] for filename, download_url in download_urls.items(): - print "downloading", filename + print("downloading {0}".format(filename)) download_file(filename, download_url) upload_file(filename) diff --git a/contrib/dokku-installer.py b/contrib/dokku-installer.py index 80484e024..180c29040 100755 --- a/contrib/dokku-installer.py +++ b/contrib/dokku-installer.py @@ -1,11 +1,15 @@ -#!/usr/bin/env python2.7 +#!/usr/bin/env python import cgi import json import os import re -import SimpleHTTPServer -import SocketServer +try: + import SimpleHTTPServer + import SocketServer +except ImportError: + import http.server as SimpleHTTPServer + import socketserver as SocketServer import subprocess import sys import threading @@ -47,12 +51,23 @@ except subprocess.CalledProcessError: ufw_display = 'none' +nginx_dir = '/etc/nginx' +nginx_init = '/etc/init.d/nginx' +try: + command = "test -x /usr/bin/openresty" + subprocess.check_output(command, shell=True).strip() + nginx_dir = '/usr/local/openresty/nginx/conf' + nginx_init = '/etc/init.d/openresty' +except subprocess.CalledProcessError: + pass + + def check_boot(): if 'onboot' not in sys.argv: return init_dir = os.getenv('INIT_DIR', '/etc/init') systemd_dir = os.getenv('SYSTEMD_DIR', '/etc/systemd/system') - nginx_dir = os.getenv('NGINX_DIR', '/etc/nginx/conf.d') + nginx_conf_dir = os.getenv('NGINX_CONF_DIR', '{0}/conf.d'.format(nginx_dir)) if os.path.exists(init_dir): with open('{0}/dokku-installer.conf'.format(init_dir), 'w') as f: @@ -79,7 +94,7 @@ def check_boot(): f.write(" }\n") f.write("}\n") - subprocess.call('rm -f /etc/nginx/sites-enabled/*', shell=True) + subprocess.call('rm -f {0}/sites-enabled/*'.format(nginx_dir), shell=True) sys.exit(0) @@ -203,7 +218,7 @@ class DeleteInstallerThread(object): thread.start() def run(self): - command = "rm /etc/nginx/conf.d/dokku-installer.conf && /etc/init.d/nginx stop && /etc/init.d/nginx start" + command = "rm {0}/conf.d/dokku-installer.conf && {1} stop && {1} start".format(nginx_dir, nginx_init) try: subprocess.call(command, shell=True) except: @@ -221,7 +236,7 @@ def main(): port = int(os.getenv('PORT', 2000)) httpd = SocketServer.TCPServer(("", port), GetHandler) - print "Listening on 0.0.0.0:{0}, CTRL+C to stop".format(port) + print("Listening on 0.0.0.0:{0}, CTRL+C to stop".format(port)) httpd.serve_forever() diff --git a/contrib/release-dokku b/contrib/release-dokku index d4ac927d5..c8dd76fd0 100755 --- a/contrib/release-dokku +++ b/contrib/release-dokku @@ -323,7 +323,6 @@ fn-build-docker-image() { declare desc="Builds the dokku docker image and tags it with the given version" declare VERSION="$1" docker build -t "dokku/dokku:$VERSION" . - docker push "dokku/dokku:$VERSION" } main() { @@ -365,10 +364,18 @@ main() { fn-extract-package "$IS_RELEASE" "dokku-${NEXT_VERSION}-1.x86_64.rpm" || log-fail "Error extracting rpm package" cp -f "build/dokku_${NEXT_VERSION}_amd64.deb" build/dokku.deb - if [[ "$RELEASE" != "build" ]]; then + if [[ "$RELEASE" == "build" ]]; then + fn-build-docker-image "latest" || log-fail "Error building docker image" + else fn-publish-package "$IS_RELEASE" "deb" "build/dokku_${NEXT_VERSION}_amd64.deb" || log-fail "Error publishing deb package" fn-publish-package "$IS_RELEASE" "rpm" "build/dokku-${NEXT_VERSION}-1.x86_64.rpm" || log-fail "Error publishing rpm package" fn-build-docker-image "$NEXT_VERSION" || log-fail "Error building docker image" + + if [[ "$IS_RELEASE" == "true" ]]; then + docker tag "dokku/dokku:$VERSION" "dokku/dokku:latest" + docker push "dokku/dokku:$VERSION" + docker push "dokku/dokku:latest" + fi fn-repo-push-tags "$IS_RELEASE" fi diff --git a/debian/control b/debian/control index d4246425a..a92d75596 100644 --- a/debian/control +++ b/debian/control @@ -3,9 +3,9 @@ Version: 0.18.5 Section: web Priority: optional Architecture: amd64 -Depends: locales, git, curl, man-db, netcat, sshcommand (>= 0.6.0), gliderlabs-sigil, docker-engine-cs (>= 1.7.1) | docker-engine (>= 1.7.1) | docker-io (>= 1.7.1) | docker.io (>= 1.7.1) | docker-ce | docker-ee, net-tools, software-properties-common, procfile-util, python-software-properties | python3-software-properties, rsyslog, dos2unix +Depends: locales, git, curl, man-db, netcat, sshcommand (>= 0.6.0), gliderlabs-sigil, docker-engine-cs (>= 1.13.0) | docker-engine (>= 1.13.0) | docker-io (>= 1.13.0) | docker.io (>= 1.13.0) | docker-ce (>= 1.13.0) | docker-ee (>= 1.13.0), net-tools, software-properties-common, procfile-util, python-software-properties | python3-software-properties, rsyslog, dos2unix, jq Recommends: herokuish (>= 0.3.4), parallel, dokku-update -Pre-Depends: nginx (>= 1.8.0) | openresty, dnsutils, cgroupfs-mount | cgroup-lite, plugn (>= 0.3.0), sudo, python2.7, debconf +Pre-Depends: nginx (>= 1.8.0) | openresty, dnsutils, cgroupfs-mount | cgroup-lite, plugn (>= 0.3.0), sudo, python | python2.7 | python3, debconf Maintainer: Jose Diaz-Gonzalez Description: Docker-powered PaaS that helps build and manage the lifecycle of applications Dokku is an extensible, open source Platform as a Service diff --git a/debian/lintian-overrides b/debian/lintian-overrides index 52a34c0e4..31e14eb7e 100644 --- a/debian/lintian-overrides +++ b/debian/lintian-overrides @@ -1,5 +1,5 @@ -dokku: command-with-path-in-maintainer-script postinst:16 /usr/bin/sshcommand -dokku: maintainer-script-calls-systemctl postinst:87 +dokku: command-with-path-in-maintainer-script postinst:22 /usr/bin/sshcommand +dokku: maintainer-script-calls-systemctl postinst:98 dokku: changelog-file-missing-in-native-package dokku: statically-linked-binary dokku: unstripped-binary-or-object @@ -10,3 +10,6 @@ dokku: hardening-no-relro # Built golang binaries link to libc dokku: missing-dependency-on-libc + +# Temporary python dependency until #2247 is resolved +dokku: python-script-but-no-python-dep usr/share/dokku/contrib/dokku-installer.py diff --git a/debian/postinst b/debian/postinst index 43c659402..de453d037 100755 --- a/debian/postinst +++ b/debian/postinst @@ -89,7 +89,10 @@ setup-sshcommand() { } setup-dokku-installer() { - if [[ -f /etc/nginx/conf.d/dokku-installer.conf ]]; then + NGINX_ROOT="/etc/nginx" + [[ -x /usr/bin/openresty ]] && NGINX_ROOT="/usr/local/openresty/nginx/conf" + + if [[ -f "$NGINX_ROOT/conf.d/dokku-installer.conf" ]]; then echo "Setting up dokku-installer" /usr/share/dokku/contrib/dokku-installer.py onboot diff --git a/debian/postrm b/debian/postrm index b37c0578d..f58c4869a 100755 --- a/debian/postrm +++ b/debian/postrm @@ -28,6 +28,8 @@ main() { fi if [[ "$1" == "purge" ]]; then + rm -f /usr/local/openresty/nginx/conf/conf.d/dokku.conf + rm -f /usr/local/openresty/nginx/conf/conf.d/dokku-installer.conf rm -f /etc/nginx/conf.d/dokku.conf rm -f /etc/nginx/conf.d/dokku-installer.conf rm -f ${DOKKU_ROOT}/.dokkurc ${DOKKU_ROOT}/dokkurc ${DOKKU_ROOT}/tls diff --git a/debian/preinst b/debian/preinst index c9a055344..3baaba9aa 100755 --- a/debian/preinst +++ b/debian/preinst @@ -7,41 +7,53 @@ if [[ -e /usr/share/debconf/confmodule ]]; then . /usr/share/debconf/confmodule fi +setup_dokku_installer() { + NGINX_BASE_PATH="$1" + NGINX_INIT_NAME="$2" + + NGINX_CONF="${NGINX_BASE_PATH}/conf.d/dokku-installer.conf" + + rm -f $NGINX_CONF + touch $NGINX_CONF + + { + echo 'upstream dokku-installer { server 127.0.0.1:2000; }' + echo 'server {' + echo ' listen 80;' + echo ' location / {' + echo ' proxy_pass http://dokku-installer;' + echo ' }' + echo '}' + } >>$NGINX_CONF + + rm -f $NGINX_BASE_PATH/sites-enabled/* + DOKKU_DISTRO="$( + . /etc/os-release >/dev/null 2>&1 || true + echo "$ID" + )" + case "$DOKKU_DISTRO" in + debian) + /usr/sbin/invoke-rc.d "$NGINX_INIT_NAME" reload || /usr/sbin/invoke-rc.d "$NGINX_INIT_NAME" start + ;; + ubuntu) + if [[ -x /usr/bin/sv ]]; then + /usr/bin/sv reload "$NGINX_INIT_NAME" || /usr/bin/sv start "$NGINX_INIT_NAME" + else + "/etc/init.d/$NGINX_INIT_NAME" reload || "/etc/init.d/$NGINX_INIT_NAME" start + fi + ;; + esac +} + case "$1" in install) db_get "dokku/web_config" if [ "$RET" = "true" ]; then - NGINX_CONF="/etc/nginx/conf.d/dokku-installer.conf" - - rm -f $NGINX_CONF - touch $NGINX_CONF - - { - echo 'upstream dokku-installer { server 127.0.0.1:2000; }' - echo 'server {' - echo ' listen 80;' - echo ' location / {' - echo ' proxy_pass http://dokku-installer;' - echo ' }' - echo '}' - } >>$NGINX_CONF - - rm -f /etc/nginx/sites-enabled/* - DOKKU_DISTRO="$( - . /etc/os-release >/dev/null 2>&1 || true - echo "$ID" - )" - case "$DOKKU_DISTRO" in - debian) - NGINX_INIT="/usr/sbin/invoke-rc.d" - "$NGINX_INIT" nginx reload || "$NGINX_INIT" nginx start - ;; - ubuntu) - NGINX_INIT="/etc/init.d/nginx" - "$NGINX_INIT" reload || "$NGINX_INIT" start - ;; - esac - exit 0 + if [[ -x /usr/bin/openresty ]]; then + setup_dokku_installer "/usr/local/openresty/nginx/conf" "openresty" + else + setup_dokku_installer "/etc/nginx" "nginx" + fi fi db_get "dokku/skip_key_file" diff --git a/docker/etc/my_init.d/10_dokku_init b/docker/etc/my_init.d/10_dokku_init index 7caff134b..d60ad507c 100755 --- a/docker/etc/my_init.d/10_dokku_init +++ b/docker/etc/my_init.d/10_dokku_init @@ -13,6 +13,8 @@ log-fail() { } main() { + local NGINX_ROOT + if [[ ! -d /mnt/dokku ]]; then log-info "Creating missing /mnt/dokku" mkdir -p /mnt/dokku @@ -49,14 +51,23 @@ main() { echo "export DOCKER_BIN=/usr/local/bin/docker" >"/home/dokku/.dokkurc/DOCKER_BIN" fi - if [[ ! -f /mnt/dokku/etc/nginx/dhparam.pem ]]; then - mkdir -p /mnt/dokku/etc/nginx - openssl dhparam -out /mnt/dokku/etc/nginx/dhparam.pem 2048 + NGINX_ROOT="/etc/nginx" + if [[ -x /usr/bin/openresty ]]; then + NGINX_ROOT="/usr/local/openresty/nginx/conf" + rm -rf /etc/runit/runsvdir/default/nginx + else + rm -rf /etc/runit/runsvdir/default/openresty fi - cp -f /mnt/dokku/etc/nginx/dhparam.pem /etc/nginx/dhparam.pem - chown root:root /etc/nginx/dhparam.pem - chown root:root /etc/nginx/conf.d + if [[ ! -f "/mnt/dokku${NGINX_ROOT}/dhparam.pem" ]]; then + mkdir -p "/mnt/dokku${NGINX_ROOT}" + openssl dhparam -out "/mnt/dokku${NGINX_ROOT}/dhparam.pem" 2048 + fi + + mkdir -p "${NGINX_ROOT}/conf.d" + cp -f "/mnt/dokku${NGINX_ROOT}/dhparam.pem" "${NGINX_ROOT}/dhparam.pem" + chown root:root "${NGINX_ROOT}/dhparam.pem" + chown root:root "${NGINX_ROOT}/conf.d" } main "$@" diff --git a/docker/etc/runit/runsvdir/default/openresty/run b/docker/etc/runit/runsvdir/default/openresty/run new file mode 100755 index 000000000..66cd2211e --- /dev/null +++ b/docker/etc/runit/runsvdir/default/openresty/run @@ -0,0 +1,7 @@ +#!/bin/bash + +exec >>/var/log/services/openresty +exec 2>&1 + +echo "Running openresty" +exec /usr/bin/openresty -c /usr/local/openresty/nginx/conf/nginx.conf -g "daemon off;" diff --git a/docker/usr/local/openresty/nginx/conf/nginx.conf b/docker/usr/local/openresty/nginx/conf/nginx.conf new file mode 100644 index 000000000..d465e846b --- /dev/null +++ b/docker/usr/local/openresty/nginx/conf/nginx.conf @@ -0,0 +1,30 @@ +user www-data; +worker_processes auto; +pid /run/openresty.pid; +include /usr/local/openresty/nginx/conf/modules-enabled/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /usr/local/openresty/nginx/conf/mime.types; + default_type application/octet-stream; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + + access_log /var/log/openresty/access.log; + error_log /var/log/openresty/error.log; + + gzip on; + + include /usr/local/openresty/nginx/conf/conf.d/*.conf; + include /usr/local/openresty/nginx/conf/sites-enabled/*; +} diff --git a/docs/configuration/environment-variables.md b/docs/configuration/environment-variables.md index ce6ea8096..976259b19 100644 --- a/docs/configuration/environment-variables.md +++ b/docs/configuration/environment-variables.md @@ -90,6 +90,7 @@ The following list config variables have special meaning and can be set in a var | `DOKKU_EVENTS_LOGFILE` | `$DOKKU_LOGS_DIR/events.log` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | Where the events log file is written to. | | `DOKKU_APP_NAME` | none | `--app APP` flag | Name of application to work on. Respected by core plugins. | | `DOKKU_APPS_FORCE_DELETE` | none | `--force` flag | Whether to force delete an application. Also used by other plugins for destructive actions. | +| `DOKKU_CHECKS_URL` | `http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/` | `/etc/environment`
`~dokku/.dokkurc`
`~dokku/.dokkurc/*` | Url displayed during deployment when no CHECKS file exists. | | `DOKKU_DETACH_CONTAINER` | none | `--detach` flag | Whether to detach a container started via `dokku run`. | | `DOKKU_QUIET_OUTPUT` | none | `--quiet` flag | Silences certain header output for `dokku` commands. | | `DOKKU_RM_CONTAINER` | none | `dokku config:set`
`--rm-container` flag
`--rm` flag | Whether to keep `dokku run` containers around or not. | diff --git a/docs/deployment/application-deployment.md b/docs/deployment/application-deployment.md index 0ccc37cef..6a86785bd 100644 --- a/docs/deployment/application-deployment.md +++ b/docs/deployment/application-deployment.md @@ -9,7 +9,7 @@ Once you have configured Dokku with at least one user, you can deploy applicatio ```shell # from your local machine # SSH access to github must be enabled on this host -git clone git@github.com:heroku/ruby-getting-started.git +git clone https://github.com/heroku/ruby-getting-started ``` ### Create the app diff --git a/docs/deployment/methods/git.md b/docs/deployment/methods/git.md index dd5e4d4bb..a13af5c15 100644 --- a/docs/deployment/methods/git.md +++ b/docs/deployment/methods/git.md @@ -76,3 +76,28 @@ This behavior can be disabled entirely on a per-app basis by setting the `rev-en # override for a specific app dokku git:set node-js-app rev-env-var "" ``` + +### Keeping the `.git` directory + +By default, Dokku will remove the contents of the `.git` before triggering a build for a given app. This is generally a safe default as shipping the entire source code history of your app in the deployed image artifact is unnecessary as it increases bloat and potentially can leak information if there are any security issues with your app code. + +To enable the `.git` directory, run the `git:set` command as follows: + +```shell +# on the Dokku host + +# keep the .git directory during builds +dokku git:set node-js-app keep-git-dir true +``` + +The default behavior is to delete this directory and it's contents. To revert to the default behavior, the `keep-git-dir` value can be set to either an empty string or `false`. + +```shell +# on the Dokku host + +# delete the .git directory during builds (default) +dokku git:set node-js-app keep-git-dir false + +# delete the .git directory during builds (default) +dokku git:set node-js-app keep-git-dir "" +``` diff --git a/docs/deployment/methods/images.md b/docs/deployment/methods/images.md index ce6408161..076a70862 100644 --- a/docs/deployment/methods/images.md +++ b/docs/deployment/methods/images.md @@ -92,7 +92,6 @@ dokku tags:deploy node-js-app v1 -----> Running post-deploy -----> Configuring node-js-app.dokku.me... -----> Creating http nginx.conf ------> Running nginx-pre-reload Reloading nginx -----> Shutting down old containers in 60 seconds =====> 025eec3fa3b442fded90933d58d8ed8422901f0449f5ea0c23d00515af5d3137 diff --git a/docs/deployment/one-off-processes.md b/docs/deployment/one-off-processes.md index 79dfb5a16..45d9895c6 100644 --- a/docs/deployment/one-off-processes.md +++ b/docs/deployment/one-off-processes.md @@ -46,6 +46,12 @@ dokku --rm-container run node-js-app ls -lah dokku --rm run node-js-app ls -lah ``` +Containers may have specific labels attached. In order to avoid issues with dokku internals, do not use any labels beginning with either `com.dokku` or `org.label-schema`. + +```shell +dokku --label=com.example.test-label=value run node-js-app ls -lah +``` + Finally, you may wish to run a container in "detached" mode via the `--detach` Dokku flag. Running a process in detached mode will immediately return a `CONTAINER_ID`. It is up to the user to then further manage this container in whatever manner they see fit, as Dokku will *not* automatically terminate the container. ```shell diff --git a/docs/deployment/zero-downtime-deploys.md b/docs/deployment/zero-downtime-deploys.md index 7ebee5124..d02a896df 100644 --- a/docs/deployment/zero-downtime-deploys.md +++ b/docs/deployment/zero-downtime-deploys.md @@ -123,7 +123,7 @@ To specify checks, add a `CHECKS` file to the root of your project directory. Th - comments (lines starting with #) - empty lines -> For Dockerfile-based deploys, the file *must* be in `/app/CHECKS` within the container. `/app` is used by default as the root container directory for buildpack-based deploys. +> For Dockerfile and Docker Image based deploys, the file *must* be in the `WORKDIR` directory of the built image. `/app` is used by default as the root container directory for buildpack-based deploys. ### Check instructions @@ -327,7 +327,6 @@ curl: (7) Failed to connect to 172.17.0.155 port 5000: Connection refused -----> Running post-deploy -----> Configuring myapp.dokku.me... -----> Creating http nginx.conf ------> Running nginx-pre-reload Reloading nginx -----> Shutting down old container in 60 seconds =====> Application deployed: diff --git a/docs/development/plugin-creation.md b/docs/development/plugin-creation.md index 642655163..162389ac1 100644 --- a/docs/development/plugin-creation.md +++ b/docs/development/plugin-creation.md @@ -159,7 +159,7 @@ Certain systems may require a wrapper function around the `docker` binary for pr ```shell # good -"$DOCKER_BIN" run -d $IMAGE /bin/bash -e -c "$COMMAND" +"$DOCKER_BIN" container run -d $IMAGE /bin/bash -e -c "$COMMAND" # bad docker run -d $IMAGE /bin/bash -e -c "$COMMAND" @@ -175,16 +175,16 @@ Note that where possible, a label `com.dokku.app-name=$APP` - where `$APP` is th ```shell # `docker build` example -"$DOCKER_BIN" build "--label=com.dokku.app-name=${APP}" $DOKKU_GLOBAL_BUILD_ARGS ... +"$DOCKER_BIN" image build "--label=com.dokku.app-name=${APP}" $DOKKU_GLOBAL_BUILD_ARGS ... # `docker commit` example # Note that the arguments must be set as a local array # as arrays cannot be exported in shell local DOKKU_COMMIT_ARGS=("--change" "LABEL org.label-schema.schema-version=1.0" "--change" "LABEL org.label-schema.vendor=dokku" "--change" "LABEL $DOKKU_CONTAINER_LABEL=") -"$DOCKER_BIN" commit --change "LABEL com.dokku.app-name=$APP" "${DOKKU_COMMIT_ARGS[@]}" ... +"$DOCKER_BIN" container commit --change "LABEL com.dokku.app-name=$APP" "${DOKKU_COMMIT_ARGS[@]}" ... # `docker run` example -"$DOCKER_BIN" run "--label=com.dokku.app-name=${APP}" $DOKKU_GLOBAL_RUN_ARGS ... +"$DOCKER_BIN" container run "--label=com.dokku.app-name=${APP}" $DOKKU_GLOBAL_RUN_ARGS ... ``` ## Copy files from the built image using `copy_from_image` diff --git a/docs/networking/port-management.md b/docs/networking/port-management.md index 27431dd73..276926b7f 100644 --- a/docs/networking/port-management.md +++ b/docs/networking/port-management.md @@ -65,7 +65,6 @@ dokku proxy:ports-add node-js-app http:8080:5000 DOKKU_PROXY_PORT_MAP: http:80:5000 http:8080:5000 -----> Configuring node-js-app.dokku.me...(using built-in template) -----> Creating http nginx.conf ------> Running nginx-pre-reload Reloading nginx ``` @@ -100,7 +99,6 @@ dokku proxy:ports-set node-js-app http:8080:5000 DOKKU_PROXY_PORT_MAP: http:80:5000 http:8080:5000 -----> Configuring node-js-app.dokku.me...(using built-in template) -----> Creating http nginx.conf ------> Running nginx-pre-reload Reloading nginx ``` @@ -126,7 +124,7 @@ For buildpack deployments, your application *must* respect the `PORT` environmen > Changed as of 0.5.0 -Dokku's default proxy implementation - nginx - only supports HTTP request proxying. At this time, we do not support proxying plain TCP or UDP ports. UDP ports can be exposed by disabling the nginx proxy with `dokku proxy:disable myapp`. If you would like to investigate alternative proxy methods, please refer to our [proxy management documentation](/docs/advanced-usage/proxy-management.md). +Dokku's default proxy implementation - nginx - supports HTTP and GRPC request proxying. At this time, we do not support proxying plain TCP or UDP ports. UDP ports can be exposed by disabling the nginx proxy with `dokku proxy:disable myapp`. If you would like to investigate alternative proxy methods, please refer to our [proxy management documentation](/docs/advanced-usage/proxy-management.md). #### Applications using EXPOSE diff --git a/docs/networking/proxy-management.md b/docs/networking/proxy-management.md index 869c706bf..3162704b0 100644 --- a/docs/networking/proxy-management.md +++ b/docs/networking/proxy-management.md @@ -69,7 +69,8 @@ The proxy port scheme is as follows: - `SCHEME:HOST_PORT:CONTAINER_PORT` -The scheme metadata can be used by proxy implementations in order to properly handle proxying of requests. For example, the built-in `nginx-vhosts` proxy implementation supports both the `http` and `https` schemes. +The scheme metadata can be used by proxy implementations in order to properly handle proxying of requests. For example, the built-in `nginx-vhosts` proxy implementation supports the `http`, `https`, `grpc` and `grpcs` schemes. +For the `grpc` and `grpcs` see [nginx blog post on grpc](https://www.nginx.com/blog/nginx-1-13-10-grpc/). Developers of proxy implementations are encouraged to use whatever schemes make the most sense, and ignore configurations which they do not support. For instance, a `udp` proxy implementation can safely ignore `http` and `https` port mappings. diff --git a/dokku b/dokku index 80a902e88..1cf34149d 100755 --- a/dokku +++ b/dokku @@ -87,13 +87,13 @@ if [[ "${args[0]}" =~ ^--.* ]]; then fi ! has_tty && DOKKU_QUIET_OUTPUT=1 -if [[ $(id -un) != "dokku" ]] && [[ ! $1 =~ plugin:* ]] && [[ ! $1 == "ssh-keys:add" ]]; then +if [[ $(id -un) != "dokku" ]] && [[ ! $1 =~ plugin:* ]] && [[ $1 != "ssh-keys:add" ]] && [[ $1 != "ssh-keys:remove" ]]; then export SSH_USER=$(id -un) sudo -u dokku -E -H "$0" "$@" exit $? fi -if [[ $1 =~ ^plugin:.* && $1 != "plugin:help" && $1 != "plugin:list" ]] || [[ $1 == "ssh-keys:add" ]]; then +if [[ $1 =~ ^plugin:.* && $1 != "plugin:help" && $1 != "plugin:list" ]] || [[ $1 == "ssh-keys:add" ]] || [[ $1 == "ssh-keys:remove" ]]; then if [[ $(id -un) != "root" ]]; then dokku_log_fail "This command must be run as root" else diff --git a/plugins/00_dokku-standard/commands b/plugins/00_dokku-standard/commands index 871a2854b..7e830763a 100755 --- a/plugins/00_dokku-standard/commands +++ b/plugins/00_dokku-standard/commands @@ -1,14 +1,15 @@ #!/usr/bin/env bash -[[ " help help:help run:help trace:help url:help urls:help version:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" +[[ " help help:help cleanup:help run:help trace:help url:help urls:help version:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT" set -eo pipefail [[ $DOKKU_TRACE ]] && set -x case "$1" in - help | run:help | trace:help | url:help | urls:help | version:help) + help | cleanup:help | run:help | trace:help | url:help | urls:help | version:help) [[ $(echo "$1" | sed '/.*:help/!d') ]] && help_topic="${1%\:help}" help_content_func() { declare desc="return standard plugin help content" cat <], Cleans up exited/dead Docker containers and removes dangling images run [--env KEY=VALUE] , Run a command in a new container using the current application image url , Show the first URL for an application (compatibility) urls , Show all URLs for an application diff --git a/plugins/00_dokku-standard/subcommands/report b/plugins/00_dokku-standard/subcommands/report index cc3975a77..a8751baf3 100755 --- a/plugins/00_dokku-standard/subcommands/report +++ b/plugins/00_dokku-standard/subcommands/report @@ -14,10 +14,10 @@ dokku_report_cmd() { dokku_log_info1 "docker version: " "$DOCKER_BIN" version | sed "s/^/ /" dokku_log_info1 "docker daemon info: " - "$DOCKER_BIN" -D info | sed "s/^/ /" + "$DOCKER_BIN" -D system info | sed "s/^/ /" dokku_log_info1 "sigil version: $(sigil -v)" dokku_log_info1 "herokuish version: " - "$DOCKER_BIN" run $DOKKU_GLOBAL_RUN_ARGS --rm "$DOKKU_IMAGE" herokuish version | sed "s/^/ /" + "$DOCKER_BIN" container run $DOKKU_GLOBAL_RUN_ARGS --rm "$DOKKU_IMAGE" herokuish version | sed "s/^/ /" dokku_log_info1 "dokku version: $(dokku version)" dokku_log_info1 "dokku plugins: " dokku plugin:list | sed "s/^/ /" diff --git a/plugins/app-json/internal-functions b/plugins/app-json/internal-functions index fe2aca3f7..cdb8ff68c 100755 --- a/plugins/app-json/internal-functions +++ b/plugins/app-json/internal-functions @@ -17,7 +17,7 @@ get_phase_script() { return 0 fi - get_json_value "scripts.dokku.${PHASE_SCRIPT_KEY}" <"$APP_JSON_FILE" + get_json_value ".scripts.dokku.${PHASE_SCRIPT_KEY}" <"$APP_JSON_FILE" } get_release_cmd() { @@ -98,8 +98,8 @@ execute_script() { DOKKU_APP_SHELL="$(config_get "$APP" DOKKU_APP_SHELL || echo "$DOKKU_APP_SHELL")" [[ -z "$DOKKU_APP_SHELL" ]] && DOKKU_APP_SHELL="/bin/bash" - id=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -e DOKKU_TRACE="$DOKKU_TRACE" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_HOST_DIR:/cache" "${ARG_ARRAY[@]}" "$IMAGE" "$DOKKU_APP_SHELL" -c "$COMMAND") - if test "$("$DOCKER_BIN" wait "$id")" -ne 0; then + id=$("$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --env DOKKU_TRACE="$DOKKU_TRACE" --label=dokku_phase_script="${PHASE_SCRIPT_KEY}" -d -v "$CACHE_HOST_DIR:/cache" "${ARG_ARRAY[@]}" "$IMAGE" "$DOKKU_APP_SHELL" -c "$COMMAND") + if test "$("$DOCKER_BIN" container wait "$id")" -ne 0; then dokku_container_log_verbose_quiet "$id" dokku_log_fail "execution of '$SCRIPT_CMD' failed!" fi @@ -121,5 +121,5 @@ execute_script() { local DOCKER_COMMIT_ARGS="$DOCKER_COMMIT_ENTRYPOINT_CHANGE_ARG $DOCKER_COMMIT_CMD_CHANGE_ARG" fi - eval "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "${DOCKER_COMMIT_ARGS[@]}" "$id" "$IMAGE" >/dev/null + eval "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "${DOCKER_COMMIT_ARGS[@]}" "$id" "$IMAGE" >/dev/null } diff --git a/plugins/apps/functions b/plugins/apps/functions index b891675b9..abd9521b1 100755 --- a/plugins/apps/functions +++ b/plugins/apps/functions @@ -34,7 +34,7 @@ apps_destroy() { fi fi - echo "Destroying $APP (including all add-ons)" + dokku_log_info1 "Destroying $APP (including all add-ons)" plugn trigger pre-delete "$APP" "$IMAGE_TAG" local DOKKU_SCHEDULER=$(get_app_scheduler "$APP") diff --git a/plugins/apps/post-delete b/plugins/apps/post-delete index 8efe6e80d..1a5d60dd7 100755 --- a/plugins/apps/post-delete +++ b/plugins/apps/post-delete @@ -16,7 +16,7 @@ app_post_delete() { fi # shellcheck disable=SC2046 - "$DOCKER_BIN" rmi $("$DOCKER_BIN" images -q "$IMAGE_REPO" | xargs) &>/dev/null || true + "$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --quiet "$IMAGE_REPO" | xargs) &>/dev/null || true } app_post_delete "$@" diff --git a/plugins/apps/subcommands/clone b/plugins/apps/subcommands/clone index 9bcecbca4..8ab7ec1a3 100755 --- a/plugins/apps/subcommands/clone +++ b/plugins/apps/subcommands/clone @@ -46,7 +46,7 @@ apps_clone_cmd() { plugn trigger post-app-clone-setup "$OLD_APP" "$NEW_APP" if [[ -d "$NEW_CACHE_DIR" ]] && ! rmdir "$NEW_CACHE_DIR"; then - "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm -v "$NEW_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache + "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$NEW_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache fi rm -rf "$NEW_CACHE_DIR" diff --git a/plugins/apps/subcommands/rename b/plugins/apps/subcommands/rename index ade93e38a..ed94cb1dc 100755 --- a/plugins/apps/subcommands/rename +++ b/plugins/apps/subcommands/rename @@ -18,7 +18,7 @@ apps_rename_cmd() { local DOCKER_RUN_LABEL_ARGS="--label=com.dokku.app-name=$OLD_APP" if [[ -d "$OLD_CACHE_DIR" ]] && ! rmdir "$OLD_CACHE_DIR" >/dev/null 2>&1; then - "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm -v "$OLD_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache + "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --rm --volume "$OLD_CACHE_HOST_DIR:/cache" "dokku/$OLD_APP" chmod 777 -R /cache fi rm -rf "$OLD_CACHE_DIR" apps_create "$NEW_APP" diff --git a/plugins/builder-dockerfile/builder-build b/plugins/builder-dockerfile/builder-build index 79563ac31..ccf27252f 100755 --- a/plugins/builder-dockerfile/builder-build +++ b/plugins/builder-dockerfile/builder-build @@ -37,7 +37,7 @@ trigger-builder-build-builder-dockerfile() { declare -a ARG_ARRAY eval "ARG_ARRAY=($DOCKER_ARGS)" - "$DOCKER_BIN" build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE . + "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" "${DOKKU_DOCKER_BUILD_OPTS[@]}" -t $IMAGE . plugn trigger post-build-dockerfile "$APP" } diff --git a/plugins/builder-herokuish/builder-build b/plugins/builder-herokuish/builder-build index f881eb86c..602edb498 100755 --- a/plugins/builder-herokuish/builder-build +++ b/plugins/builder-herokuish/builder-build @@ -28,13 +28,13 @@ trigger-builder-build-builder-herokuish() { NEW_DOKKU_IMAGE=$(plugn trigger builder-dokku-image "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" "$DOKKU_IMAGE") [[ -n "$NEW_DOKKU_IMAGE" ]] && DOKKU_IMAGE="$NEW_DOKKU_IMAGE" - CID=$(tar -c . | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app") - if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then + CID=$(tar -c . | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$DOKKU_IMAGE" /bin/bash -c "mkdir -p /app && tar -xC /app") + if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then dokku_log_warn "Failure extracting app code" return 1 fi - "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null + "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null [[ -d $DOKKU_APP_CACHE_DIR ]] || mkdir -p "$DOKKU_APP_CACHE_DIR" plugn trigger pre-build-buildpack "$APP" "$SOURCECODE_WORK_DIR" @@ -45,14 +45,14 @@ trigger-builder-build-builder-herokuish() { declare -a ARG_ARRAY eval "ARG_ARRAY=($DOCKER_ARGS)" # shellcheck disable=SC2086 - CID=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d -v $DOKKU_APP_HOST_CACHE_DIR:/cache -e CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build) - "$DOCKER_BIN" attach "$CID" - if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then + CID=$("$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d -v $DOKKU_APP_HOST_CACHE_DIR:/cache -e CACHE_PATH=/cache "${ARG_ARRAY[@]}" $IMAGE /build) + "$DOCKER_BIN" container attach "$CID" + if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then dokku_log_warn "Failure during app build" return 1 fi - "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null + "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null plugn trigger post-build-buildpack "$APP" "$SOURCECODE_WORK_DIR" } diff --git a/plugins/builder-herokuish/builder-release b/plugins/builder-herokuish/builder-release index 2292c7a22..952e6de92 100755 --- a/plugins/builder-herokuish/builder-release +++ b/plugins/builder-herokuish/builder-release @@ -19,22 +19,22 @@ trigger-builder-release-builder-herokuish() { plugn trigger pre-release-buildpack "$APP" "$IMAGE_TAG" if [[ -n $(config_export global) ]]; then - CID=$(config_export global | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh") - if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then + CID=$(config_export global | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/00-global-env.sh") + if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then dokku_log_warn "Failure injecting global environment variables" return 1 fi - "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null + "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null fi if [[ -n $(config_export app "$APP") ]]; then - CID=$(config_export app "$APP" | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh") - if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then + CID=$(config_export app "$APP" | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /app/.profile.d && cat > /app/.profile.d/01-app-env.sh") + if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then dokku_log_warn "Failure injecting app environment variables" return 1 fi - "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null + "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null fi plugn trigger post-release-buildpack "$APP" "$IMAGE_TAG" } diff --git a/plugins/builder-herokuish/pre-build-buildpack b/plugins/builder-herokuish/pre-build-buildpack index e82b5cc1e..e0f2ff6e3 100755 --- a/plugins/builder-herokuish/pre-build-buildpack +++ b/plugins/builder-herokuish/pre-build-buildpack @@ -22,22 +22,22 @@ trigger-pre-build-buildpack-builder-herokuish() { 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 - CID=$(config_bundle --merged "$APP" | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; cat | tar -x -C /tmp/env") - if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then + CID=$(config_bundle --merged "$APP" | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; cat | tar -x -C /tmp/env") + if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then dokku_log_warn "Failure injecting BUILD_ENV into build environment" return 1 fi - "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null + "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null # create build env for 'old style' buildpacks and dokku plugins - CID=$(config_export app "$APP" --format envfile --merged | "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env") - if test "$("$DOCKER_BIN" wait "$CID")" -ne 0; then + CID=$(config_export app "$APP" --format envfile --merged | "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env") + if test "$("$DOCKER_BIN" container wait "$CID")" -ne 0; then dokku_log_warn "Failure injecting old-style BUILD_ENV" return 1 fi - "$DOCKER_BIN" commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null + "$DOCKER_BIN" container commit "${DOCKER_COMMIT_LABEL_ARGS[@]}" "$CID" "$IMAGE" >/dev/null } trigger-pre-build-buildpack-builder-herokuish "$@" diff --git a/plugins/buildpacks/.gitignore b/plugins/buildpacks/.gitignore index cd4903d6f..053d0cfd9 100644 --- a/plugins/buildpacks/.gitignore +++ b/plugins/buildpacks/.gitignore @@ -1,6 +1,7 @@ /commands /subcommands/* /triggers/* +/triggers /install /post-delete /post-extract diff --git a/plugins/buildpacks/Makefile b/plugins/buildpacks/Makefile index 889c22529..74a13c23e 100644 --- a/plugins/buildpacks/Makefile +++ b/plugins/buildpacks/Makefile @@ -1,37 +1,6 @@ -include ../../common.mk - -GO_ARGS ?= -a - SUBCOMMANDS = subcommands/add subcommands/clear subcommands/list subcommands/remove subcommands/report subcommands/set TRIGGERS = triggers/install triggers/post-delete triggers/post-extract triggers/report -build-in-docker: clean - docker run --rm \ - -v $$PWD/../..:$(GO_REPO_ROOT) \ - -w $(GO_REPO_ROOT)/plugins/buildpacks \ - $(BUILD_IMAGE) \ - bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$? +BUILD = commands subcommands triggers +PLUGIN_NAME = buildpacks -build: commands subcommands triggers - $(MAKE) triggers-copy - -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 triggers install post-delete post-extract report - -src-clean: - rm -rf .gitignore src triggers vendor Makefile *.go glide.* - -triggers: $(TRIGGERS) - -triggers/%: src/triggers/*/%.go - go build $(GO_ARGS) -o $@ $< - -triggers-copy: - cp triggers/* . +include ../../common.mk diff --git a/plugins/buildpacks/src/subcommands/add/add.go b/plugins/buildpacks/src/subcommands/add/add.go deleted file mode 100644 index 8aa71e01b..000000000 --- a/plugins/buildpacks/src/subcommands/add/add.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/buildpacks" - "github.com/dokku/dokku/plugins/common" -) - -func main() { - args := flag.NewFlagSet("buildpacks:add", flag.ExitOnError) - index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs") - args.Parse(os.Args[2:]) - err := buildpacks.CommandAdd(args.Args(), *index) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/buildpacks/src/subcommands/clear/clear.go b/plugins/buildpacks/src/subcommands/clear/clear.go deleted file mode 100644 index 32b60ba10..000000000 --- a/plugins/buildpacks/src/subcommands/clear/clear.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/buildpacks" - "github.com/dokku/dokku/plugins/common" -) - -func main() { - args := flag.NewFlagSet("buildpacks:clear", flag.ExitOnError) - args.Parse(os.Args[2:]) - err := buildpacks.CommandClear(args.Args()) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/buildpacks/src/subcommands/list/list.go b/plugins/buildpacks/src/subcommands/list/list.go deleted file mode 100644 index 44d56967e..000000000 --- a/plugins/buildpacks/src/subcommands/list/list.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/buildpacks" -) - -func main() { - args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError) - args.Parse(os.Args[2:]) - buildpacks.CommandList(args.Args()) -} diff --git a/plugins/buildpacks/src/subcommands/remove/remove.go b/plugins/buildpacks/src/subcommands/remove/remove.go deleted file mode 100644 index b10875caa..000000000 --- a/plugins/buildpacks/src/subcommands/remove/remove.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/buildpacks" - "github.com/dokku/dokku/plugins/common" -) - -func main() { - args := flag.NewFlagSet("buildpacks:remove", flag.ExitOnError) - index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs") - args.Parse(os.Args[2:]) - err := buildpacks.CommandRemove(args.Args(), *index) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/buildpacks/src/subcommands/report/report.go b/plugins/buildpacks/src/subcommands/report/report.go deleted file mode 100644 index 507ae416d..000000000 --- a/plugins/buildpacks/src/subcommands/report/report.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "flag" - "strings" - - "github.com/dokku/dokku/plugins/buildpacks" - "github.com/dokku/dokku/plugins/common" -) - -// displays a buildpacks report for one or more apps -func main() { - flag.Parse() - appName := flag.Arg(1) - infoFlag := flag.Arg(2) - - if strings.HasPrefix(appName, "--") { - infoFlag = appName - appName = "" - } - - if len(appName) == 0 { - apps, err := common.DokkuApps() - if err != nil { - return - } - for _, appName := range apps { - buildpacks.ReportSingleApp(appName, infoFlag) - } - return - } - - buildpacks.ReportSingleApp(appName, infoFlag) -} diff --git a/plugins/buildpacks/src/subcommands/set/set.go b/plugins/buildpacks/src/subcommands/set/set.go deleted file mode 100644 index cf97ca5ce..000000000 --- a/plugins/buildpacks/src/subcommands/set/set.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/buildpacks" - "github.com/dokku/dokku/plugins/common" -) - -func main() { - args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError) - index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs") - args.Parse(os.Args[2:]) - err := buildpacks.CommandSet(args.Args(), *index) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/buildpacks/src/subcommands/subcommands.go b/plugins/buildpacks/src/subcommands/subcommands.go new file mode 100644 index 000000000..212898cfe --- /dev/null +++ b/plugins/buildpacks/src/subcommands/subcommands.go @@ -0,0 +1,55 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/buildpacks" + "github.com/dokku/dokku/plugins/common" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + var err error + switch subcommand { + case "add": + args := flag.NewFlagSet("buildpacks:add", flag.ExitOnError) + index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs") + args.Parse(os.Args[2:]) + err = buildpacks.CommandAdd(args.Args(), *index) + case "clear": + args := flag.NewFlagSet("buildpacks:clear", flag.ExitOnError) + args.Parse(os.Args[2:]) + err = buildpacks.CommandClear(args.Args()) + case "list": + args := flag.NewFlagSet("buildpacks:list", flag.ExitOnError) + args.Parse(os.Args[2:]) + buildpacks.CommandList(args.Args()) + case "remove": + args := flag.NewFlagSet("buildpacks:remove", flag.ExitOnError) + index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs") + args.Parse(os.Args[2:]) + err = buildpacks.CommandRemove(args.Args(), *index) + case "report": + flag.Parse() + appName := flag.Arg(1) + infoFlag := flag.Arg(2) + buildpacks.CommandReport(appName, infoFlag) + case "set": + args := flag.NewFlagSet("buildpacks:set", flag.ExitOnError) + index := args.Int("index", 0, "--index: the 1-based index of the URL in the list of URLs") + args.Parse(os.Args[2:]) + err = buildpacks.CommandSet(args.Args(), *index) + default: + common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand)) + } + + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/buildpacks/src/triggers/install/install.go b/plugins/buildpacks/src/triggers/install/install.go deleted file mode 100644 index 9c3a8e092..000000000 --- a/plugins/buildpacks/src/triggers/install/install.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/dokku/dokku/plugins/common" -) - -// runs the install step for the buildpacks plugin -func main() { - if err := common.PropertySetup("buildpacks"); err != nil { - common.LogFail(fmt.Sprintf("Unable to install the buildpacks plugin: %s", err.Error())) - } -} diff --git a/plugins/buildpacks/src/triggers/post-delete/post-delete.go b/plugins/buildpacks/src/triggers/post-delete/post-delete.go deleted file mode 100644 index 3535d48bf..000000000 --- a/plugins/buildpacks/src/triggers/post-delete/post-delete.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/common" -) - -// destroys the buildpacks property for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - - err := common.PropertyDestroy("buildpacks", appName) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/buildpacks/src/triggers/report/report.go b/plugins/buildpacks/src/triggers/report/report.go deleted file mode 100644 index 7f1e74440..000000000 --- a/plugins/buildpacks/src/triggers/report/report.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/buildpacks" -) - -// displays a buildpacks report for one or more apps -func main() { - flag.Parse() - appName := flag.Arg(0) - - buildpacks.ReportSingleApp(appName, "") -} diff --git a/plugins/buildpacks/src/triggers/triggers.go b/plugins/buildpacks/src/triggers/triggers.go new file mode 100644 index 000000000..83e01740b --- /dev/null +++ b/plugins/buildpacks/src/triggers/triggers.go @@ -0,0 +1,35 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/buildpacks" + "github.com/dokku/dokku/plugins/common" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + switch trigger { + case "install": + buildpacks.TriggerInstall() + case "post-delete": + appName := flag.Arg(0) + buildpacks.TriggerPostDelete(appName) + case "post-extract": + appName := flag.Arg(0) + sourceWorkDir := flag.Arg(1) + buildpacks.TriggerPostExtract(appName, sourceWorkDir) + case "report": + appName := flag.Arg(0) + buildpacks.ReportSingleApp(appName, "") + default: + common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger)) + } +} diff --git a/plugins/buildpacks/subcommands.go b/plugins/buildpacks/subcommands.go index 88a3e0856..060a9f32f 100644 --- a/plugins/buildpacks/subcommands.go +++ b/plugins/buildpacks/subcommands.go @@ -3,6 +3,7 @@ package buildpacks import ( "errors" "fmt" + "strings" "github.com/dokku/dokku/plugins/common" ) @@ -115,6 +116,27 @@ func CommandRemove(args []string, index int) (err error) { return } +// CommandReport displays a buildpacks report for one or more apps +func CommandReport(appName string, infoFlag string) { + if strings.HasPrefix(appName, "--") { + infoFlag = appName + appName = "" + } + + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return + } + for _, appName := range apps { + ReportSingleApp(appName, infoFlag) + } + return + } + + ReportSingleApp(appName, infoFlag) +} + // CommandSet implements buildpacks:set func CommandSet(args []string, index int) (err error) { var appName string diff --git a/plugins/buildpacks/src/triggers/post-extract/post-extract.go b/plugins/buildpacks/triggers.go similarity index 50% rename from plugins/buildpacks/src/triggers/post-extract/post-extract.go rename to plugins/buildpacks/triggers.go index 495a34855..d06e387e4 100644 --- a/plugins/buildpacks/src/triggers/post-extract/post-extract.go +++ b/plugins/buildpacks/triggers.go @@ -1,8 +1,7 @@ -package main +package buildpacks import ( "bufio" - "flag" "fmt" "os" "path" @@ -10,12 +9,23 @@ import ( "github.com/dokku/dokku/plugins/common" ) -// writes a .buildpacks file into the app -func main() { - flag.Parse() - appName := flag.Arg(0) - tmpWorkDir := flag.Arg(1) +// TriggerInstall runs the install step for the buildpacks plugin +func TriggerInstall() { + if err := common.PropertySetup("buildpacks"); err != nil { + common.LogFail(fmt.Sprintf("Unable to install the buildpacks plugin: %s", err.Error())) + } +} +// TriggerPostDelete destroys the buildpacks property for a given app container +func TriggerPostDelete(appName string) { + err := common.PropertyDestroy("buildpacks", appName) + if err != nil { + common.LogFail(err.Error()) + } +} + +// TriggerPostExtract writes a .buildpacks file into the app +func TriggerPostExtract(appName string, sourceWorkDir string) { buildpacks, err := common.PropertyListGet("buildpacks", appName, "buildpacks") if err != nil { return @@ -25,7 +35,7 @@ func main() { return } - buildpacksPath := path.Join(tmpWorkDir, ".buildpacks") + buildpacksPath := path.Join(sourceWorkDir, ".buildpacks") file, err := os.OpenFile(buildpacksPath, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0600) if err != nil { common.LogFail(fmt.Sprintf("Error writing .buildpacks file: %s", err.Error())) diff --git a/plugins/common/common.go b/plugins/common/common.go index 0f70f8d59..23038b960 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -325,7 +325,7 @@ func VerifyAppName(appName string) (err error) { // VerifyImage returns true if docker image exists in local repo func VerifyImage(image string) bool { - imageCmd := NewShellCmd(strings.Join([]string{DockerBin(), "inspect", image}, " ")) + imageCmd := NewShellCmd(strings.Join([]string{DockerBin(), "image", "inspect", image}, " ")) imageCmd.ShowOutput = false return imageCmd.Execute() } diff --git a/plugins/common/functions b/plugins/common/functions index ebf714ab8..66cf890ae 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -171,7 +171,7 @@ dokku_container_log_verbose_quiet() { OIFS=$IFS IFS=$'\n' local line - for line in $("$DOCKER_BIN" logs "$CID" 2>&1); do + for line in $("$DOCKER_BIN" container logs "$CID" 2>&1); do dokku_log_verbose_quiet "$line" done IFS=$OIFS @@ -203,7 +203,7 @@ verify_app_name() { verify_image() { declare desc="verify image existence" local IMAGE="$1" - if "$DOCKER_BIN" inspect "$IMAGE" &>/dev/null; then + if "$DOCKER_BIN" image inspect "$IMAGE" &>/dev/null; then return 0 else return 1 @@ -286,7 +286,7 @@ get_running_image_tag() { verify_app_name "$APP" local CIDS=($(get_app_container_ids "$APP")) - local RUNNING_IMAGE_TAG=$("$DOCKER_BIN" inspect -f '{{ .Config.Image }}' "${CIDS[0]}" 2>/dev/null | awk -F: '{ print $2 }' || echo '') + local RUNNING_IMAGE_TAG=$("$DOCKER_BIN" container inspect --format '{{ .Config.Image }}' "${CIDS[0]}" 2>/dev/null | awk -F: '{ print $2 }' || echo '') echo "$RUNNING_IMAGE_TAG" } @@ -300,13 +300,13 @@ is_image_herokuish_based() { fi # due to how the build process works, all herokuish images have the Environment variable USER=herokuishuser - USER_VALUE="$("$DOCKER_BIN" inspect -f '{{range .Config.Env}}{{if eq . "USER=herokuishuser" }}{{println .}}{{end}}{{end}}' "$IMAGE")" + USER_VALUE="$("$DOCKER_BIN" image inspect --format '{{range .Config.Env}}{{if eq . "USER=herokuishuser" }}{{println .}}{{end}}{{end}}' "$IMAGE")" [[ "$USER_VALUE" == "" ]] && return 1 return 0 } get_docker_version() { - CLIENT_VERSION_STRING="$("$DOCKER_BIN" version -f="{{ .Client.Version }}")" + CLIENT_VERSION_STRING="$("$DOCKER_BIN" version --format "{{ .Client.Version }}")" echo "$CLIENT_VERSION_STRING" } @@ -336,6 +336,8 @@ parse_args() { local next_index=1 local skip=false local args=("$@") + local flags + for arg in "$@"; do if [[ "$skip" == "true" ]]; then next_index=$((next_index + 1)) @@ -364,8 +366,22 @@ parse_args() { skip=true ;; esac + + if [[ "$skip" == "true" ]]; then + flags="${flags} ${arg}" + elif [[ "$arg" == "--app" ]]; then + flags="${flags} ${arg}=${args[$next_index]}" + elif [[ "$arg" =~ ^--.* ]]; then + flags="${flags} ${arg}" + fi + next_index=$((next_index + 1)) done + + if [[ -z "$DOKKU_GLOBAL_FLAGS" ]]; then + export DOKKU_GLOBAL_FLAGS="$(echo -e "${flags}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + fi + return 0 } @@ -382,7 +398,7 @@ copy_from_image() { if is_image_herokuish_based "$IMAGE"; then WORKDIR="/app" else - WORKDIR="$("$DOCKER_BIN" inspect -f '{{.Config.WorkingDir}}' "$IMAGE")" + WORKDIR="$("$DOCKER_BIN" image inspect --format '{{.Config.WorkingDir}}' "$IMAGE")" fi if [[ -n "$WORKDIR" ]]; then @@ -393,9 +409,9 @@ copy_from_image() { TMP_FILE_COMMAND_OUTPUT=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") trap "rm -rf '$TMP_FILE_COMMAND_OUTPUT' >/dev/null 2>&1 || true" RETURN - local CID=$("$DOCKER_BIN" create "${DOCKER_CREATE_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "$IMAGE") - "$DOCKER_BIN" cp "$CID:$SRC_FILE" "$TMP_FILE_COMMAND_OUTPUT" 2>/dev/null || true - "$DOCKER_BIN" rm -f "$CID" &>/dev/null + local CID=$("$DOCKER_BIN" container create "${DOCKER_CREATE_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "$IMAGE") + "$DOCKER_BIN" container cp "$CID:$SRC_FILE" "$TMP_FILE_COMMAND_OUTPUT" 2>/dev/null || true + "$DOCKER_BIN" container rm --force "$CID" &>/dev/null # docker cp exits with status 1 when run as non-root user when it tries to chown the file # after successfully copying the file. Thus, we suppress stderr. @@ -492,7 +508,7 @@ is_container_running() { local CONTAINER_STATUS dokku_log_warn "Deprecated: common#is_container_status" - CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f '{{.State.Running}}' "$CID" || true) + CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Running}}' "$CID" || true) if [[ "$CONTAINER_STATUS" == "true" ]]; then return 0 @@ -505,7 +521,7 @@ is_container_status() { declare desc="return 0 if given docker container id is in given state" local CID=$1 local TEMPLATE="{{.State.$2}}" - local CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f "$TEMPLATE" "$CID" 2>/dev/null || true) + local CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format "$TEMPLATE" "$CID" 2>/dev/null || true) if [[ "$CONTAINER_STATUS" == "true" ]]; then return 0 @@ -522,7 +538,7 @@ is_app_running() { dokku_log_warn "Deprecated: ps#fn-is-app-running" verify_app_name "$APP" - local APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP") + local APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null) if [[ -n "$APP_RUNNING_CONTAINER_IDS" ]]; then return 0 @@ -641,30 +657,30 @@ docker_cleanup() { if [[ -n "$APP" ]]; then # delete all non-running containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=exited" -f "label=$DOKKU_CONTAINER_LABEL" -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true # delete all dead containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=dead" -f "label=$DOKKU_CONTAINER_LABEL" -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true # delete danging images # shellcheck disable=SC2046 - "$DOCKER_BIN" rmi $("$DOCKER_BIN" images -f 'dangling=true' -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true + "$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true # delete unused images "$DOCKER_BIN" image prune --all --filter "label=com.dokku.app-name=$APP" --force &>/dev/null || true else # delete all non-running containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=exited" -f "label=$DOKKU_CONTAINER_LABEL" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true # delete all dead containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=dead" -f "label=$DOKKU_CONTAINER_LABEL" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true # delete danging images # shellcheck disable=SC2046 - "$DOCKER_BIN" rmi $("$DOCKER_BIN" images -f 'dangling=true' -q) &>/dev/null || true + "$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --quiet) &>/dev/null || true fi } @@ -747,7 +763,7 @@ get_exposed_ports_from_image() { local IMAGE="$1" verify_image "$IMAGE" # shellcheck disable=SC2016 - local DOCKER_IMAGE_EXPOSED_PORTS="$("$DOCKER_BIN" inspect -f '{{range $key, $value := .Config.ExposedPorts}}{{$key}} {{end}}' "$IMAGE")" + local DOCKER_IMAGE_EXPOSED_PORTS="$("$DOCKER_BIN" image inspect --format '{{range $key, $value := .Config.ExposedPorts}}{{$key}} {{end}}' "$IMAGE")" echo "$DOCKER_IMAGE_EXPOSED_PORTS" } @@ -755,7 +771,7 @@ get_entrypoint_from_image() { declare desc="return .Config.Entrypoint from passed image name" local IMAGE="$1" verify_image "$IMAGE" - local DOCKER_IMAGE_ENTRYPOINT="$("$DOCKER_BIN" inspect --format '{{range .Config.Entrypoint}}{{.}} {{end}}' "$IMAGE")" + local DOCKER_IMAGE_ENTRYPOINT="$("$DOCKER_BIN" image inspect --format '{{range .Config.Entrypoint}}{{.}} {{end}}' "$IMAGE")" echo "ENTRYPOINT $DOCKER_IMAGE_ENTRYPOINT" } @@ -763,7 +779,7 @@ get_cmd_from_image() { declare desc="return .Config.Cmd from passed image name" local IMAGE="$1" verify_image "$IMAGE" - local DOCKER_IMAGE_CMD="$("$DOCKER_BIN" inspect --format '{{range .Config.Cmd}}{{.}} {{end}}' "$IMAGE")" + local DOCKER_IMAGE_CMD="$("$DOCKER_BIN" image inspect --format '{{range .Config.Cmd}}{{.}} {{end}}' "$IMAGE")" DOCKER_IMAGE_CMD="${DOCKER_IMAGE_CMD/\/bin\/sh -c/}" echo "CMD $DOCKER_IMAGE_CMD" } @@ -801,7 +817,7 @@ get_container_ports() { local cid for cid in $APP_CIDS; do - local container_ports="$("$DOCKER_BIN" port "$cid" | awk '{ print $3 "->" $1}' | awk -F ":" '{ print $2 }')" + local container_ports="$("$DOCKER_BIN" container port "$cid" | awk '{ print $3 "->" $1}' | awk -F ":" '{ print $2 }')" done echo "$container_ports" @@ -907,24 +923,10 @@ internal_get_app_urls() { get_json_value() { declare desc="return value of provided json key from a json stream on stdin" # JSON_NODE should be expresses as either a top-level object that has no children - # or in the format of json.node.path + # or in the format of .json.node.path local JSON_NODE="$1" - local JSON_NODE=${JSON_NODE//\./\"][\"} - local JSON_NODE="[\"${JSON_NODE}\"]" - cat | python2.7 -c 'import json,sys;obj=json.load(sys.stdin);print json.dumps(obj'"${JSON_NODE}"').strip("\"")' -} -get_json_keys() { - declare desc="return space-separated list of json keys from json provided on stdin" - # JSON_NODE should be expressed as json.node.path and is expected to have children - local JSON_NODE="$1" - local JSON_NODE=${JSON_NODE//\./\"][\"} - local JSON_NODE="[\"${JSON_NODE}\"]" - if [[ "$JSON_NODE" == "[\"\"]" ]]; then - cat | python2.7 -c 'import json,sys;obj=json.load(sys.stdin);print " ".join(obj.keys())' - else - cat | python2.7 -c 'import json,sys;obj=json.load(sys.stdin);print " ".join(obj'"${JSON_NODE}"'.keys())' - fi + cat | jq -r "${JSON_NODE} | select (.!=null)" 2>/dev/null } strip_inline_comments() { diff --git a/plugins/config/.gitignore b/plugins/config/.gitignore index 0f6770b1e..cc45caec7 100644 --- a/plugins/config/.gitignore +++ b/plugins/config/.gitignore @@ -1,2 +1,4 @@ /commands /subcommands/* +/triggers/* +/triggers diff --git a/plugins/config/Makefile b/plugins/config/Makefile index 5e65eb98e..fcc94b7d9 100644 --- a/plugins/config/Makefile +++ b/plugins/config/Makefile @@ -1,28 +1,5 @@ -include ../../common.mk - -GO_ARGS ?= -a - SUBCOMMANDS = subcommands/export subcommands/get subcommands/set subcommands/unset subcommands/keys subcommands/bundle +BUILD = commands subcommands +PLUGIN_NAME = config -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 -j4 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 glide.* +include ../../common.mk diff --git a/plugins/config/src/subcommands/bundle/bundle.go b/plugins/config/src/subcommands/bundle/bundle.go deleted file mode 100644 index e00238177..000000000 --- a/plugins/config/src/subcommands/bundle/bundle.go +++ /dev/null @@ -1,16 +0,0 @@ -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) -} diff --git a/plugins/config/src/subcommands/clear/clear.go b/plugins/config/src/subcommands/clear/clear.go deleted file mode 100644 index 8fe985330..000000000 --- a/plugins/config/src/subcommands/clear/clear.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/config" -) - -//clear all entries from the given environment -func main() { - args := flag.NewFlagSet("config:clear", 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.CommandClear(args.Args(), *global, *noRestart) -} diff --git a/plugins/config/src/subcommands/export/export.go b/plugins/config/src/subcommands/export/export.go deleted file mode 100644 index c83f8a6f6..000000000 --- a/plugins/config/src/subcommands/export/export.go +++ /dev/null @@ -1,20 +0,0 @@ -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 | pretty | json | json-list ] which format to export as)") - args.Parse(os.Args[2:]) - config.CommandExport(args.Args(), *global, *merged, *format) -} diff --git a/plugins/config/src/subcommands/get/get.go b/plugins/config/src/subcommands/get/get.go deleted file mode 100644 index 52840b3fa..000000000 --- a/plugins/config/src/subcommands/get/get.go +++ /dev/null @@ -1,17 +0,0 @@ -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) -} diff --git a/plugins/config/src/subcommands/keys/keys.go b/plugins/config/src/subcommands/keys/keys.go deleted file mode 100644 index 4f1bbbbc8..000000000 --- a/plugins/config/src/subcommands/keys/keys.go +++ /dev/null @@ -1,16 +0,0 @@ -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) -} diff --git a/plugins/config/src/subcommands/set/set.go b/plugins/config/src/subcommands/set/set.go deleted file mode 100644 index cb6c8f4ff..000000000 --- a/plugins/config/src/subcommands/set/set.go +++ /dev/null @@ -1,18 +0,0 @@ -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) -} diff --git a/plugins/config/src/subcommands/subcommands.go b/plugins/config/src/subcommands/subcommands.go new file mode 100644 index 000000000..9f9eeae7a --- /dev/null +++ b/plugins/config/src/subcommands/subcommands.go @@ -0,0 +1,67 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/config" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + switch subcommand { + case "bundle": + 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) + case "clear": + args := flag.NewFlagSet("config:clear", 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.CommandClear(args.Args(), *global, *noRestart) + case "export": + 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 | pretty | json | json-list ] which format to export as)") + args.Parse(os.Args[2:]) + config.CommandExport(args.Args(), *global, *merged, *format) + case "get": + 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) + case "keys": + 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) + case "set": + 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) + case "unset": + 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) + default: + common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand)) + } + +} diff --git a/plugins/config/src/subcommands/unset/unset.go b/plugins/config/src/subcommands/unset/unset.go deleted file mode 100644 index c6c4ee814..000000000 --- a/plugins/config/src/subcommands/unset/unset.go +++ /dev/null @@ -1,17 +0,0 @@ -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) -} diff --git a/plugins/enter/subcommands/default b/plugins/enter/subcommands/default index 5eb6ffbc3..35e8b06bb 100755 --- a/plugins/enter/subcommands/default +++ b/plugins/enter/subcommands/default @@ -60,7 +60,7 @@ enter_default_cmd() { has_tty && local DOKKU_RUN_OPTS+=" -i -t" is_image_herokuish_based "$IMAGE" && local EXEC_CMD="/exec" # shellcheck disable=SC2086 - "$DOCKER_BIN" exec $DOKKU_RUN_OPTS $ID $EXEC_CMD "${@:-$DOKKU_APP_SHELL}" + "$DOCKER_BIN" container exec $DOKKU_RUN_OPTS $ID $EXEC_CMD "${@:-$DOKKU_APP_SHELL}" } enter_default_cmd "$@" diff --git a/plugins/git/functions b/plugins/git/functions index c980841aa..db4ab4837 100755 --- a/plugins/git/functions +++ b/plugins/git/functions @@ -67,7 +67,10 @@ git_build_app_repo() { fi suppress_output env -u GIT_QUARANTINE_PATH git submodule update --init --recursive - find . -name .git -prune -exec rm -rf {} \; >/dev/null + local DOKKU_KEEP_GIT_DIR="$(fn-plugin-property-get "git" "$APP" "keep-git-dir" "")" + if [[ "$DOKKU_KEEP_GIT_DIR" != "true" ]]; then + find . -name .git -prune -exec rm -rf {} \; >/dev/null + fi if use_git_worktree; then pushd "$DOKKU_ROOT/$APP" >/dev/null @@ -238,7 +241,8 @@ fn-git-create-hook() { cat >"$PRERECEIVE_HOOK" < 0 { - dockerfilePorts = strings.Split(dokkuDockerfilePorts, " ") - } - } - - var ports []string - if len(dockerfilePorts) == 0 { - ports = append(ports, "5000") - } else { - for _, port := range dockerfilePorts { - port = strings.TrimSuffix(strings.TrimSpace(port), "/tcp") - if port == "" || strings.HasSuffix(port, "/udp") { - continue - } - ports = append(ports, port) - } - } - fmt.Fprint(os.Stdout, strings.Join(ports, " ")) -} diff --git a/plugins/network/src/triggers/network-config-exists/network-config-exists.go b/plugins/network/src/triggers/network-config-exists/network-config-exists.go deleted file mode 100644 index b604fb5de..000000000 --- a/plugins/network/src/triggers/network-config-exists/network-config-exists.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/dokku/dokku/plugins/network" -) - -// writes true or false to stdout whether a given app has network config -func main() { - flag.Parse() - appName := flag.Arg(0) - - if network.HasNetworkConfig(appName) { - fmt.Fprintln(os.Stdout, "true") - return - } - - fmt.Fprintln(os.Stdout, "false") -} diff --git a/plugins/network/src/triggers/network-get-ipaddr/network-get-ipaddr.go b/plugins/network/src/triggers/network-get-ipaddr/network-get-ipaddr.go deleted file mode 100644 index 237526b64..000000000 --- a/plugins/network/src/triggers/network-get-ipaddr/network-get-ipaddr.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/dokku/dokku/plugins/network" -) - -// write the ipaddress to stdout for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - processType := flag.Arg(1) - containerID := flag.Arg(2) - - ipAddress := network.GetContainerIpaddress(appName, processType, containerID) - fmt.Fprintln(os.Stdout, ipAddress) -} diff --git a/plugins/network/src/triggers/network-get-listeners/network-get-listeners.go b/plugins/network/src/triggers/network-get-listeners/network-get-listeners.go deleted file mode 100644 index 9c999fe4e..000000000 --- a/plugins/network/src/triggers/network-get-listeners/network-get-listeners.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "strings" - - "github.com/dokku/dokku/plugins/network" -) - -// returns the listeners (host:port combinations) for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - - listeners := network.GetListeners(appName) - fmt.Fprint(os.Stdout, strings.Join(listeners, " ")) -} diff --git a/plugins/network/src/triggers/network-get-port/network-get-port.go b/plugins/network/src/triggers/network-get-port/network-get-port.go deleted file mode 100644 index 389265da7..000000000 --- a/plugins/network/src/triggers/network-get-port/network-get-port.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/dokku/dokku/plugins/common" - network "github.com/dokku/dokku/plugins/network" -) - -// write the port to stdout for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - processType := flag.Arg(1) - isHerokuishContainer := common.ToBool(flag.Arg(2)) - containerID := flag.Arg(3) - - port := network.GetContainerPort(appName, processType, isHerokuishContainer, containerID) - fmt.Fprintln(os.Stdout, port) -} diff --git a/plugins/network/src/triggers/network-get-property/network-get-property.go b/plugins/network/src/triggers/network-get-property/network-get-property.go deleted file mode 100644 index 9da6f0ba1..000000000 --- a/plugins/network/src/triggers/network-get-property/network-get-property.go +++ /dev/null @@ -1,21 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/dokku/dokku/plugins/common" - network "github.com/dokku/dokku/plugins/network" -) - -// writes the network property to stdout for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - property := flag.Arg(1) - - defaultValue := network.GetDefaultValue(property) - value := common.PropertyGetDefault("network", appName, property, defaultValue) - fmt.Fprintln(os.Stdout, value) -} diff --git a/plugins/network/src/triggers/network-write-ipaddr/network-write-ipaddr.go b/plugins/network/src/triggers/network-write-ipaddr/network-write-ipaddr.go deleted file mode 100644 index 3cf618120..000000000 --- a/plugins/network/src/triggers/network-write-ipaddr/network-write-ipaddr.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "strings" - - "github.com/dokku/dokku/plugins/common" -) - -// writes the ip to disk -func main() { - flag.Parse() - appName := flag.Arg(0) - processType := flag.Arg(1) - containerIndex := flag.Arg(2) - ip := flag.Arg(3) - - if appName == "" { - common.LogFail("Please specify an app to run the command on") - } - err := common.VerifyAppName(appName) - if err != nil { - common.LogFail(err.Error()) - } - - appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/") - filename := fmt.Sprintf("%v/IP.%v.%v", appRoot, processType, containerIndex) - f, err := os.Create(filename) - if err != nil { - common.LogFail(err.Error()) - } - defer f.Close() - - ipBytes := []byte(ip) - _, err = f.Write(ipBytes) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/network/src/triggers/network-write-port/network-write-port.go b/plugins/network/src/triggers/network-write-port/network-write-port.go deleted file mode 100644 index e263cd786..000000000 --- a/plugins/network/src/triggers/network-write-port/network-write-port.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - "strings" - - "github.com/dokku/dokku/plugins/common" -) - -// writes the port to disk -func main() { - flag.Parse() - appName := flag.Arg(0) - processType := flag.Arg(1) - containerIndex := flag.Arg(2) - port := flag.Arg(3) - - if appName == "" { - common.LogFail("Please specify an app to run the command on") - } - err := common.VerifyAppName(appName) - if err != nil { - common.LogFail(err.Error()) - } - - appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/") - filename := fmt.Sprintf("%v/PORT.%v.%v", appRoot, processType, containerIndex) - f, err := os.Create(filename) - if err != nil { - common.LogFail(err.Error()) - } - defer f.Close() - - portBytes := []byte(port) - _, err = f.Write(portBytes) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/network/src/triggers/post-app-clone-setup/post-app-clone-setup.go b/plugins/network/src/triggers/post-app-clone-setup/post-app-clone-setup.go deleted file mode 100644 index 70adb14ce..000000000 --- a/plugins/network/src/triggers/post-app-clone-setup/post-app-clone-setup.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/network" -) - -// cleanup network files for a new app clone -func main() { - flag.Parse() - appName := flag.Arg(1) - - success := network.PostAppCloneSetup(appName) - if !success { - os.Exit(1) - } -} diff --git a/plugins/network/src/triggers/post-create/post-create.go b/plugins/network/src/triggers/post-create/post-create.go deleted file mode 100644 index c71d07b9c..000000000 --- a/plugins/network/src/triggers/post-create/post-create.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/common" -) - -// set bind-all-interfaces to false by default -func main() { - flag.Parse() - appName := flag.Arg(0) - - err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false") - if err != nil { - common.LogWarn(err.Error()) - } -} diff --git a/plugins/network/src/triggers/post-delete/post-delete.go b/plugins/network/src/triggers/post-delete/post-delete.go deleted file mode 100644 index 7d29808b5..000000000 --- a/plugins/network/src/triggers/post-delete/post-delete.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/common" -) - -// destroys the network property for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - - err := common.PropertyDestroy("network", appName) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/network/src/triggers/report/report.go b/plugins/network/src/triggers/report/report.go deleted file mode 100644 index 780ecf065..000000000 --- a/plugins/network/src/triggers/report/report.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/network" -) - -// displays a network report for one or more apps -func main() { - flag.Parse() - appName := flag.Arg(0) - - network.ReportSingleApp(appName, "") -} diff --git a/plugins/network/src/triggers/triggers.go b/plugins/network/src/triggers/triggers.go new file mode 100644 index 000000000..0f34ca578 --- /dev/null +++ b/plugins/network/src/triggers/triggers.go @@ -0,0 +1,78 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/network" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + switch trigger { + case "install": + network.TriggerInstall() + case "network-build-config": + appName := flag.Arg(0) + network.BuildConfig(appName) + case "network-compute-ports": + appName := flag.Arg(0) + processType := flag.Arg(1) + isHerokuishContainer := common.ToBool(flag.Arg(2)) + network.TriggerNetworkComputePorts(appName, processType, isHerokuishContainer) + case "network-config-exists": + appName := flag.Arg(0) + network.TriggerNetworkConfigExists(appName) + case "network-get-ipaddr": + appName := flag.Arg(0) + processType := flag.Arg(1) + containerID := flag.Arg(2) + network.TriggerNetworkGetIppaddr(appName, processType, containerID) + case "network-get-listeners": + appName := flag.Arg(0) + network.TriggerNetworkGetListeners(appName) + case "network-get-port": + appName := flag.Arg(0) + processType := flag.Arg(1) + isHerokuishContainer := common.ToBool(flag.Arg(2)) + containerID := flag.Arg(3) + network.TriggerNetworkGetPort(appName, processType, isHerokuishContainer, containerID) + case "network-get-property": + appName := flag.Arg(0) + property := flag.Arg(1) + network.TriggerNetworkGetProperty(appName, property) + case "network-write-ipaddr": + appName := flag.Arg(0) + processType := flag.Arg(1) + containerIndex := flag.Arg(2) + ip := flag.Arg(3) + network.TriggerNetworkWriteIpaddr(appName, processType, containerIndex, ip) + case "network-write-port": + appName := flag.Arg(0) + processType := flag.Arg(1) + containerIndex := flag.Arg(2) + port := flag.Arg(3) + network.TriggerNetworkWritePort(appName, processType, containerIndex, port) + case "post-app-clone-setup": + appName := flag.Arg(1) + network.TriggerPostAppCloneSetup(appName) + case "post-create": + appName := flag.Arg(0) + network.TriggerPostCreate(appName) + case "post-delete": + appName := flag.Arg(0) + network.TriggerPostDelete(appName) + case "report": + appName := flag.Arg(0) + network.ReportSingleApp(appName, "") + default: + common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger)) + } +} diff --git a/plugins/network/subcommands.go b/plugins/network/subcommands.go new file mode 100644 index 000000000..3e5cdc7d2 --- /dev/null +++ b/plugins/network/subcommands.go @@ -0,0 +1,48 @@ +package network + +import ( + "strings" + + "github.com/dokku/dokku/plugins/common" +) + +// CommandRebuildall rebuilds network settings for all apps +func CommandRebuildall() { + apps, err := common.DokkuApps() + if err != nil { + common.LogFail(err.Error()) + } + for _, appName := range apps { + BuildConfig(appName) + } +} + +// CommandReport displays a network report for one or more apps +func CommandReport(appName string, infoFlag string) { + if strings.HasPrefix(appName, "--") { + infoFlag = appName + appName = "" + } + + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return + } + for _, appName := range apps { + ReportSingleApp(appName, infoFlag) + } + return + } + + ReportSingleApp(appName, infoFlag) +} + +// CommandSet set or clear a network property for an app +func CommandSet(appName string, property string, value string) { + if property == "bind-all-interfaces" && value == "" { + value = "false" + } + + common.CommandPropertySet("network", appName, property, value, DefaultProperties) +} diff --git a/plugins/network/triggers.go b/plugins/network/triggers.go new file mode 100644 index 000000000..22f8f3956 --- /dev/null +++ b/plugins/network/triggers.go @@ -0,0 +1,178 @@ +package network + +import ( + "fmt" + "os" + "strings" + "unicode/utf8" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/config" + "github.com/dokku/dokku/plugins/proxy" +) + +// TriggerInstall runs the install step for the network plugin +func TriggerInstall() { + if err := common.PropertySetup("network"); err != nil { + common.LogFail(fmt.Sprintf("Unable to install the network plugin: %s", err.Error())) + } + + apps, err := common.DokkuApps() + if err != nil { + return + } + for _, appName := range apps { + if common.PropertyExists("network", appName, "bind-all-interfaces") { + continue + } + if proxy.IsAppProxyEnabled(appName) { + common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to false") + if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false"); err != nil { + common.LogWarn(err.Error()) + } + } else { + common.LogVerboseQuiet("Setting network property 'bind-all-interfaces' to true") + if err := common.PropertyWrite("network", appName, "bind-all-interfaces", "true"); err != nil { + common.LogWarn(err.Error()) + } + } + } +} + +// TriggerNetworkComputePorts computes the ports for a given app container +func TriggerNetworkComputePorts(appName string, processType string, isHerokuishContainer bool) { + if processType != "web" { + return + } + + var dockerfilePorts []string + if !isHerokuishContainer { + dokkuDockerfilePorts := strings.Trim(config.GetWithDefault(appName, "DOKKU_DOCKERFILE_PORTS", ""), " ") + if utf8.RuneCountInString(dokkuDockerfilePorts) > 0 { + dockerfilePorts = strings.Split(dokkuDockerfilePorts, " ") + } + } + + var ports []string + if len(dockerfilePorts) == 0 { + ports = append(ports, "5000") + } else { + for _, port := range dockerfilePorts { + port = strings.TrimSuffix(strings.TrimSpace(port), "/tcp") + if port == "" || strings.HasSuffix(port, "/udp") { + continue + } + ports = append(ports, port) + } + } + fmt.Fprint(os.Stdout, strings.Join(ports, " ")) +} + +// TriggerNetworkConfigExists writes true or false to stdout whether a given app has network config +func TriggerNetworkConfigExists(appName string) { + if HasNetworkConfig(appName) { + fmt.Fprintln(os.Stdout, "true") + return + } + + fmt.Fprintln(os.Stdout, "false") +} + +// TriggerNetworkGetIppaddr writes the ipaddress to stdout for a given app container +func TriggerNetworkGetIppaddr(appName string, processType string, containerID string) { + ipAddress := GetContainerIpaddress(appName, processType, containerID) + fmt.Fprintln(os.Stdout, ipAddress) +} + +// TriggerNetworkGetListeners returns the listeners (host:port combinations) for a given app container +func TriggerNetworkGetListeners(appName string) { + listeners := GetListeners(appName) + fmt.Fprint(os.Stdout, strings.Join(listeners, " ")) +} + +// TriggerNetworkGetPort writes the port to stdout for a given app container +func TriggerNetworkGetPort(appName string, processType string, isHerokuishContainer bool, containerID string) { + port := GetContainerPort(appName, processType, isHerokuishContainer, containerID) + fmt.Fprintln(os.Stdout, port) +} + +// TriggerNetworkGetProperty writes the network property to stdout for a given app container +func TriggerNetworkGetProperty(appName string, property string) { + defaultValue := GetDefaultValue(property) + value := common.PropertyGetDefault("network", appName, property, defaultValue) + fmt.Fprintln(os.Stdout, value) +} + +// TriggerNetworkWriteIpaddr writes the ip to disk +func TriggerNetworkWriteIpaddr(appName string, processType string, containerIndex string, ip string) { + if appName == "" { + common.LogFail("Please specify an app to run the command on") + } + err := common.VerifyAppName(appName) + if err != nil { + common.LogFail(err.Error()) + } + + appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/") + filename := fmt.Sprintf("%v/IP.%v.%v", appRoot, processType, containerIndex) + f, err := os.Create(filename) + if err != nil { + common.LogFail(err.Error()) + } + defer f.Close() + + ipBytes := []byte(ip) + _, err = f.Write(ipBytes) + if err != nil { + common.LogFail(err.Error()) + } +} + +// TriggerNetworkWritePort writes the port to disk +func TriggerNetworkWritePort(appName string, processType string, containerIndex string, port string) { + if appName == "" { + common.LogFail("Please specify an app to run the command on") + } + err := common.VerifyAppName(appName) + if err != nil { + common.LogFail(err.Error()) + } + + appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/") + filename := fmt.Sprintf("%v/PORT.%v.%v", appRoot, processType, containerIndex) + f, err := os.Create(filename) + if err != nil { + common.LogFail(err.Error()) + } + defer f.Close() + + portBytes := []byte(port) + _, err = f.Write(portBytes) + if err != nil { + common.LogFail(err.Error()) + } +} + +// TriggerPostAppCloneSetup cleans up network files for a new app clone +func TriggerPostAppCloneSetup(appName string) { + success := PostAppCloneSetup(appName) + if !success { + os.Exit(1) + } +} + +// TriggerPostCreate sets bind-all-interfaces to false by default +func TriggerPostCreate(appName string) { + err := common.PropertyWrite("network", appName, "bind-all-interfaces", "false") + if err != nil { + common.LogWarn(err.Error()) + } +} + +// TriggerPostDelete destroys the network property for a given app container +func TriggerPostDelete(appName string) { + err := common.PropertyDestroy("network", appName) + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/nginx-vhosts/functions b/plugins/nginx-vhosts/functions index 8016cdf24..098382d4c 100755 --- a/plugins/nginx-vhosts/functions +++ b/plugins/nginx-vhosts/functions @@ -11,18 +11,7 @@ source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions" get_nginx_location() { declare desc="check that nginx is at the expected location and return it" - local NGINX_LOCATION - - NGINX_LOCATION=$(which nginx 2>/dev/null) - if [[ -z "$NGINX_LOCATION" ]]; then - NGINX_LOCATION="/usr/sbin/nginx" - fi - - if [[ ! -x "$NGINX_LOCATION" ]]; then - dokku_log_fail "Could not find nginx binary in \$PATH or at '${NGINX_LOCATION}'." - fi - - echo "$NGINX_LOCATION" + fn-nginx-vhosts-nginx-location } validate_nginx() { @@ -69,32 +58,18 @@ validate_nginx() { restart_nginx() { declare desc="restart nginx for given distros" - case "$DOKKU_DISTRO" in - debian) - sudo /usr/sbin/invoke-rc.d nginx reload >/dev/null - ;; - - ubuntu) - sudo /etc/init.d/nginx reload >/dev/null - ;; - - opensuse) - sudo /sbin/service nginx reload >/dev/null - ;; - - arch | centos | rhel) - sudo /usr/bin/systemctl reload nginx - ;; - esac + fn-nginx-vhosts-nginx-init-cmd "reload" } nginx_logs() { declare desc="display app nginx logs" - local APP="$2" + declare NGINX_LOGS_TYPE="${1#nginx:}" APP="$2" + local NGINX_LOG_ROOT="/var/log/nginx" verify_app_name "$APP" - local NGINX_LOGS_TYPE=${1#nginx:} + + fn-nginx-vhosts-uses-openresty && NGINX_LOG_ROOT="/var/log/openresty" local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs} - local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log" + local NGINX_LOGS_PATH="$NGINX_LOG_ROOT/$APP-$NGINX_LOGS_TYPE.log" if [[ $3 == "-t" ]]; then local NGINX_LOGS_ARGS="-F" @@ -259,6 +234,28 @@ is_http2_enabled() { echo $HAS_SUPPORT } +is_grpc_enabled() { + declare desc="detects whether the installed nginx version has grpc support" + local NGINX_VERSION="$1" + local MAJOR_VERSION MINOR_VERSION PATCH_VERSION + local HAS_SUPPORT=false + + MAJOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[1]}') + MINOR_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[2]}') + PATCH_VERSION=$(echo "$NGINX_VERSION" | awk '{split($0,a,"."); print a[3]}') + if [[ "$MAJOR_VERSION" -ge "2" ]]; then + HAS_SUPPORT=true + elif [[ "$MAJOR_VERSION" -eq "1" ]]; then + if [[ "$MINOR_VERSION" -eq "13" ]] && [[ "$PATCH_VERSION" -ge "10" ]]; then + HAS_SUPPORT=true + elif [[ "$MINOR_VERSION" -ge "14" ]]; then + HAS_SUPPORT=true + fi + fi + + echo $HAS_SUPPORT +} + nginx_build_config() { declare desc="build nginx config to proxy app containers using sigil" local APP="$1" @@ -324,7 +321,7 @@ nginx_build_config() { done fi - local NGINX_LOCATION NGINX_VERSION SPDY_SUPPORTED HTTP2_SUPPORTED HTTP2_PUSH_SUPPORTED + local NGINX_LOCATION NGINX_VERSION SPDY_SUPPORTED HTTP2_SUPPORTED HTTP2_PUSH_SUPPORTED GRPC_SUPPORTED NGINX_LOCATION=$(get_nginx_location) if [[ -z "$NGINX_LOCATION" ]]; then exit 1 @@ -333,9 +330,13 @@ nginx_build_config() { SPDY_SUPPORTED="$(is_spdy_enabled "$NGINX_VERSION")" HTTP2_SUPPORTED="$(is_http2_enabled "$NGINX_VERSION")" HTTP2_PUSH_SUPPORTED="$(is_http2_push_enabled "$NGINX_VERSION")" + GRPC_SUPPORTED="$(is_grpc_enabled "$NGINX_VERSION")" PROXY_PORT_MAP=$(echo "$PROXY_PORT_MAP" | xargs) # trailing spaces mess up default template + local NGINX_LOG_ROOT="/var/log/nginx" + fn-nginx-vhosts-uses-openresty && NGINX_LOG_ROOT="/var/log/openresty" + if [[ -z "$DOKKU_APP_LISTENERS" ]]; then dokku_log_warn_quiet "No web listeners specified for $APP" elif (is_deployed "$APP"); then @@ -366,7 +367,9 @@ nginx_build_config() { PASSED_LISTEN_IP_PORT="$PASSED_LISTEN_IP_PORT" SPDY_SUPPORTED="$SPDY_SUPPORTED" HTTP2_SUPPORTED="$HTTP2_SUPPORTED" + NGINX_LOG_ROOT="$NGINX_LOG_ROOT" HTTP2_PUSH_SUPPORTED="$HTTP2_PUSH_SUPPORTED" + GRPC_SUPPORTED="$GRPC_SUPPORTED" DOKKU_APP_LISTEN_PORT="$DOKKU_APP_LISTEN_PORT" DOKKU_APP_LISTEN_IP="$DOKKU_APP_LISTEN_IP" APP_SSL_PATH="$APP_SSL_PATH" SSL_INUSE="$SSL_INUSE" SSL_SERVER_NAME="$SSL_SERVER_NAME" # @TODO: Remove this after a few versions @@ -381,11 +384,10 @@ nginx_build_config() { dokku_log_info1 "Creating $SCHEME nginx.conf" mv "$NGINX_CONF" "$DOKKU_ROOT/$APP/nginx.conf" - dokku_log_info1 "Running nginx-pre-reload" plugn trigger nginx-pre-reload "$APP" "$DOKKU_APP_LISTEN_PORT" "$DOKKU_APP_LISTEN_IP" dokku_log_verbose "Reloading nginx" - validate_nginx && restart_nginx + validate_nginx && restart_nginx >/dev/null fi if ([[ -n "$NONSSL_VHOSTS" ]] || [[ -n "$SSL_VHOSTS" ]]) && [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then @@ -401,7 +403,7 @@ nginx_build_config() { if (is_deployed "$APP"); then dokku_log_info1 "reloading nginx after nginx.conf deletion" - validate_nginx && restart_nginx + validate_nginx && restart_nginx >/dev/null fi fi fi diff --git a/plugins/nginx-vhosts/install b/plugins/nginx-vhosts/install index c48e451b0..6ff611a04 100755 --- a/plugins/nginx-vhosts/install +++ b/plugins/nginx-vhosts/install @@ -3,63 +3,81 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" source "$PLUGIN_AVAILABLE_PATH/config/functions" +source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/internal-functions" + +NGINX_BIN="$(fn-nginx-vhosts-nginx-location)" +NGINX_ROOT="/etc/nginx" +NGINX_LOG_ROOT="/var/log/nginx" +NGINX_INIT_NAME="nginx" +NGINX_SUDOERS_FILE="/etc/sudoers.d/dokku-nginx" +if fn-nginx-vhosts-uses-openresty; then + NGINX_ROOT="/usr/local/openresty/nginx/conf" + NGINX_LOG_ROOT="/var/log/openresty" + NGINX_INIT_NAME="openresty" + NGINX_SUDOERS_FILE="/etc/sudoers.d/dokku-openresty" +fi case "$DOKKU_DISTRO" in debian) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/usr/sbin/invoke-rc.d $NGINX_INIT_NAME reload, $NGINX_BIN -t, ${NGINX_BIN} -t -c *" >"$NGINX_SUDOERS_FILE" ;; ubuntu) - echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + if [[ -x /usr/bin/sv ]]; then + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/sv reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + else + echo "%dokku ALL=(ALL) NOPASSWD:/etc/init.d/$NGINX_INIT_NAME reload, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + fi ;; opensuse) - echo "%dokku ALL=(ALL) NOPASSWD:/sbin/service nginx reload, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/sbin/service $NGINX_INIT_NAME reload, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" ;; arch) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" ;; centos | rhel) - echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload nginx, /usr/sbin/nginx -t, /usr/sbin/nginx -t -c *" >/etc/sudoers.d/dokku-nginx - echo "Defaults:dokku !requiretty" >>/etc/sudoers.d/dokku-nginx + echo "%dokku ALL=(ALL) NOPASSWD:/usr/bin/systemctl reload $NGINX_INIT_NAME, $NGINX_BIN -t, $NGINX_BIN -t -c *" >"$NGINX_SUDOERS_FILE" + echo "Defaults:dokku !requiretty" >>"$NGINX_SUDOERS_FILE" ;; esac -chmod 0440 /etc/sudoers.d/dokku-nginx +chmod 0440 "$NGINX_SUDOERS_FILE" # if dhparam.pem has not been created, create it the first time -if [[ ! -f /etc/nginx/dhparam.pem ]]; then - openssl dhparam -out /etc/nginx/dhparam.pem 2048 +if [[ ! -f "$NGINX_ROOT/dhparam.pem" ]]; then + openssl dhparam -out "$NGINX_ROOT/dhparam.pem" 2048 fi -mkdir -p /etc/nginx/conf.d -chown root:root /etc/nginx/dhparam.pem -chown root:root /etc/nginx/conf.d -cat </etc/nginx/conf.d/dokku.conf +mkdir -p "$NGINX_ROOT/conf.d" +chown root:root "$NGINX_ROOT/dhparam.pem" +chown root:root "$NGINX_ROOT/conf.d" +cat <"$NGINX_ROOT/conf.d/dokku.conf" include $DOKKU_ROOT/*/nginx.conf; server_tokens off; # Settings from https://mozilla.github.io/server-side-tls/ssl-config-generator/ -ssl_session_cache shared:SSL:20m; +ssl_session_cache shared:SSL:20m; ssl_session_timeout 1d; -ssl_session_tickets on; +ssl_session_tickets off; -ssl_dhparam /etc/nginx/dhparam.pem; -ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384; +ssl_dhparam $NGINX_ROOT/dhparam.pem; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; EOF # allow users to override their server_names_hash_bucket_size -if [[ ! -f /etc/nginx/conf.d/server_names_hash_bucket_size.conf ]]; then - echo 'server_names_hash_bucket_size 512;' >|/etc/nginx/conf.d/server_names_hash_bucket_size.conf +if [[ ! -f "$NGINX_ROOT/conf.d/server_names_hash_bucket_size.conf" ]]; then + echo 'server_names_hash_bucket_size 512;' >|"$NGINX_ROOT/conf.d/server_names_hash_bucket_size.conf" fi # revert dokku group changes +mkdir -p "$NGINX_LOG_ROOT" gpasswd -a dokku adm -chgrp --quiet -R adm /var/log/nginx +chgrp --quiet -R adm "$NGINX_LOG_ROOT" gpasswd -M "$(egrep ^dokku: /etc/group | awk -F ":" '{ print $4 }')" dokku [[ -f /etc/logrotate.d/nginx ]] && sed -i -e 's/create 0640 www-data dokku/create 0640 www-data adm/g' /etc/logrotate.d/nginx @@ -93,24 +111,9 @@ for app in $(dokku_apps); do fi done -case "$DOKKU_DISTRO" in - debian) - NGINX_INIT="/usr/sbin/invoke-rc.d" - "$NGINX_INIT" nginx start || "$NGINX_INIT" nginx reload - ;; - - ubuntu) - NGINX_INIT="/etc/init.d/nginx" - "$NGINX_INIT" start || "$NGINX_INIT" reload - ;; - - opensuse) - NGINX_INIT="/sbin/service" - "$NGINX_INIT" nginx start || "$NGINX_INIT" nginx reload - ;; - - arch | centos | rhel) - NGINX_INIT="/usr/bin/systemctl" - "$NGINX_INIT" start nginx || "$NGINX_INIT" reload nginx - ;; -esac +# avoid failing runit init calls on install +# the runit binaries are not yet available during dockerfile building +# and therefore both these calls will fail +if [[ ! -x /usr/bin/sv ]]; then + fn-nginx-vhosts-nginx-init-cmd start || fn-nginx-vhosts-nginx-init-cmd reload +fi diff --git a/plugins/nginx-vhosts/internal-functions b/plugins/nginx-vhosts/internal-functions index 576db3504..4fef273f0 100755 --- a/plugins/nginx-vhosts/internal-functions +++ b/plugins/nginx-vhosts/internal-functions @@ -1,6 +1,71 @@ #!/usr/bin/env bash set -eo pipefail [[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" + +fn-nginx-vhosts-uses-openresty() { + declare desc="returns whether openresty is in use or not" + + if [[ -x /usr/bin/openresty ]]; then + return + fi + + return 1 +} + +fn-nginx-vhosts-nginx-location() { + declare desc="check that nginx is at the expected location and return it" + local NGINX_LOCATION + + NGINX_LOCATION=$(which nginx 2>/dev/null) + if [[ -z "$NGINX_LOCATION" ]]; then + NGINX_LOCATION="/usr/sbin/nginx" + fi + + if fn-nginx-vhosts-uses-openresty; then + NGINX_LOCATION="/usr/bin/openresty" + fi + + if [[ ! -x "$NGINX_LOCATION" ]]; then + dokku_log_fail "Could not find nginx binary in \$PATH or at '${NGINX_LOCATION}'." + fi + + echo "$NGINX_LOCATION" +} + +fn-nginx-vhosts-nginx-init-cmd() { + declare desc="start nginx for given distros" + declare CMD="$1" + local NGINX_INIT_NAME + + NGINX_INIT_NAME=nginx + if fn-nginx-vhosts-uses-openresty; then + NGINX_INIT_NAME=openresty + fi + + case "$DOKKU_DISTRO" in + debian) + sudo /usr/sbin/invoke-rc.d "$NGINX_INIT_NAME" "$CMD" + ;; + + ubuntu) + # support docker-based installations + if [[ -x /usr/bin/sv ]]; then + sudo /usr/bin/sv "$CMD" "$NGINX_INIT_NAME" + else + sudo "/etc/init.d/$NGINX_INIT_NAME" "$CMD" + fi + ;; + + opensuse) + sudo /sbin/service "$NGINX_INIT_NAME" "$CMD" + ;; + + arch | centos | rhel) + sudo /usr/bin/systemctl "$CMD" "$NGINX_INIT_NAME" + ;; + esac +} nginx_vhosts_validate_single_func() { declare APP="$1" FLAG="$2" diff --git a/plugins/nginx-vhosts/post-delete b/plugins/nginx-vhosts/post-delete index 115723393..f857dc99c 100755 --- a/plugins/nginx-vhosts/post-delete +++ b/plugins/nginx-vhosts/post-delete @@ -3,4 +3,4 @@ set -eo pipefail [[ $DOKKU_TRACE ]] && set -x source "$PLUGIN_AVAILABLE_PATH/nginx-vhosts/functions" -restart_nginx "$@" +restart_nginx "$@" >/dev/null diff --git a/plugins/nginx-vhosts/templates/nginx.conf.sigil b/plugins/nginx-vhosts/templates/nginx.conf.sigil index 7ad4595a5..7a0c04b9d 100644 --- a/plugins/nginx-vhosts/templates/nginx.conf.sigil +++ b/plugins/nginx-vhosts/templates/nginx.conf.sigil @@ -9,8 +9,8 @@ server { listen [::]:{{ $listen_port }}; listen {{ $listen_port }}; {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} - access_log /var/log/nginx/{{ $.APP }}-access.log; - error_log /var/log/nginx/{{ $.APP }}-error.log; + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; {{ if (and (eq $listen_port "80") ($.SSL_INUSE)) }} return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri; {{ else }} @@ -60,13 +60,13 @@ server { listen {{ $listen_port }} ssl {{ if eq $.HTTP2_SUPPORTED "true" }}http2{{ else if eq $.SPDY_SUPPORTED "true" }}spdy{{ end }}; {{ if $.SSL_SERVER_NAME }}server_name {{ $.SSL_SERVER_NAME }}; {{ end }} {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} - access_log /var/log/nginx/{{ $.APP }}-access.log; - error_log /var/log/nginx/{{ $.APP }}-error.log; + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; - ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; - ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key; - ssl_protocols TLSv1.2; - ssl_prefer_server_ciphers on; + ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; + ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers off; keepalive_timeout 70; {{ if and (eq $.SPDY_SUPPORTED "true") (ne $.HTTP2_SUPPORTED "true") }}add_header Alternate-Protocol {{ $.PROXY_SSL_PORT }}:npn-spdy/2;{{ end }} @@ -117,7 +117,42 @@ server { internal; } } +{{ else if eq $scheme "grpc"}} +{{ if eq $.GRPC_SUPPORTED "true"}}{{ if eq $.HTTP2_SUPPORTED "true"}} +server { + listen [::]:{{ $listen_port }} http2; + listen {{ $listen_port }} http2; + {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; + location / { + grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }}; + } + include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf; +} {{ end }}{{ end }} +{{ else if eq $scheme "grpcs"}} +{{ if eq $.GRPC_SUPPORTED "true"}}{{ if eq $.HTTP2_SUPPORTED "true"}} +server { + listen [::]:{{ $listen_port }} ssl http2; + listen {{ $listen_port }} ssl http2; + {{ if $.NOSSL_SERVER_NAME }}server_name {{ $.NOSSL_SERVER_NAME }}; {{ end }} + access_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-access.log; + error_log {{ $.NGINX_LOG_ROOT }}/{{ $.APP }}-error.log; + + ssl_certificate {{ $.APP_SSL_PATH }}/server.crt; + ssl_certificate_key {{ $.APP_SSL_PATH }}/server.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers off; + + location / { + grpc_pass grpc://{{ $.APP }}-{{ $upstream_port }}; + } + include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf; +} +{{ end }}{{ end }} +{{ end }} +{{ end }} {{ if $.DOKKU_APP_LISTENERS }} {{ range $upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }} diff --git a/plugins/ps/internal-functions b/plugins/ps/internal-functions index dc816f641..ca775b8f9 100755 --- a/plugins/ps/internal-functions +++ b/plugins/ps/internal-functions @@ -62,7 +62,7 @@ cmd-ps-report-single() { local APP_CONTAINER_STATUS for CONTAINER_FILE in $CONTAINER_FILES; do CID=$(<"$DOKKU_ROOT/$APP/$CONTAINER_FILE") - APP_CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f '{{.State.Status}}' "$CID" 2>/dev/null || true) + APP_CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Status}}' "$CID" 2>/dev/null || true) [[ -z "$APP_CONTAINER_STATUS" ]] && APP_CONTAINER_STATUS="missing" STATUSES+=("${CONTAINER_FILE#*.}:$APP_CONTAINER_STATUS#${CID:0:12}") done diff --git a/plugins/ps/subcommands/default b/plugins/ps/subcommands/default index 8fc9f35c2..3f136c8d1 100755 --- a/plugins/ps/subcommands/default +++ b/plugins/ps/subcommands/default @@ -14,14 +14,14 @@ ps_main_cmd() { verify_app_name "$APP" ! (is_deployed "$APP") && dokku_log_warn "App $APP has not been deployed" && exit 0 - local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP") + local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null) local CID for CID in $DOKKU_APP_RUNNING_CONTAINER_IDS; do has_tty && local DOKKU_RUN_OPTS="-i -t" dokku_log_info1_quiet "running processes in container: $CID" # shellcheck disable=SC2086 - "$DOCKER_BIN" exec $DOKKU_RUN_OPTS $CID /bin/sh -c "ps auxwww" + "$DOCKER_BIN" container exec $DOKKU_RUN_OPTS $CID /bin/sh -c "ps auxwww" done } diff --git a/plugins/repo/.gitignore b/plugins/repo/.gitignore index 0f6770b1e..2983228bd 100644 --- a/plugins/repo/.gitignore +++ b/plugins/repo/.gitignore @@ -1,2 +1,5 @@ /commands /subcommands/* +/triggers/* +/triggers +/pre-delete diff --git a/plugins/repo/Makefile b/plugins/repo/Makefile index 706a28900..2dd00e389 100644 --- a/plugins/repo/Makefile +++ b/plugins/repo/Makefile @@ -1,37 +1,6 @@ -include ../../common.mk - -GO_ARGS ?= -a - SUBCOMMANDS = subcommands/gc subcommands/purge-cache TRIGGERS = triggers/pre-delete -build-in-docker: clean - docker run --rm \ - -v $$PWD/../..:$(GO_REPO_ROOT) \ - -w $(GO_REPO_ROOT)/plugins/repo \ - $(BUILD_IMAGE) \ - bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$? +BUILD = commands subcommands triggers +PLUGIN_NAME = repo -build: commands subcommands triggers - $(MAKE) triggers-copy - -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 triggers pre-delete - -src-clean: - rm -rf .gitignore src triggers vendor Makefile *.go glide.* - -triggers: $(TRIGGERS) - -triggers/%: src/triggers/*/%.go - go build $(GO_ARGS) -o $@ $< - -triggers-copy: - cp triggers/* . +include ../../common.mk diff --git a/plugins/repo/repo.go b/plugins/repo/repo.go index 8474d6482..ce7813cd8 100644 --- a/plugins/repo/repo.go +++ b/plugins/repo/repo.go @@ -24,7 +24,8 @@ func PurgeCache(appName string) error { dockerLabelArgs := fmt.Sprintf("--label=com.dokku.app-name=%s", appName) purgeCacheCmd := common.NewShellCmd(strings.Join([]string{ common.DockerBin(), - "run --rm", dockerLabelArgs, dokkuGlobalRunArgs, + "container", + "run", "--rm", dockerLabelArgs, dokkuGlobalRunArgs, "-v", strings.Join([]string{cacheHostDir, ":/cache"}, ""), image, `find /cache -depth -mindepth 1 -maxdepth 1 -exec rm -Rf {} ;`}, " ")) purgeCacheCmd.Execute() diff --git a/plugins/repo/src/subcommands/purge-cache/purge-cache.go b/plugins/repo/src/subcommands/purge-cache/purge-cache.go deleted file mode 100644 index 63665ca18..000000000 --- a/plugins/repo/src/subcommands/purge-cache/purge-cache.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/repo" -) - -// deletes the contents of the build cache stored in the repository -func main() { - flag.Parse() - appName := flag.Arg(1) - if appName == "" { - common.LogFail("Please specify an app to run the command on") - } - - err := repo.PurgeCache(appName) - if err != nil { - common.LogWarn(err.Error()) - } -} diff --git a/plugins/repo/src/subcommands/subcommands.go b/plugins/repo/src/subcommands/subcommands.go new file mode 100644 index 000000000..4194cb147 --- /dev/null +++ b/plugins/repo/src/subcommands/subcommands.go @@ -0,0 +1,35 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/repo" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + flag.Parse() + + var err error + switch subcommand { + case "gc": + flag.Parse() + appName := flag.Arg(1) + err = repo.CommandGc(appName) + case "purge-cache": + appName := flag.Arg(1) + err = repo.CommandPurgeCache(appName) + default: + common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand)) + } + + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/repo/src/triggers/pre-delete/pre-delete.go b/plugins/repo/src/triggers/pre-delete/pre-delete.go deleted file mode 100644 index c43f5fba0..000000000 --- a/plugins/repo/src/triggers/pre-delete/pre-delete.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/repo" -) - -// destroys the buildpacks property for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - - err := repo.PurgeCache(appName) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/repo/src/triggers/triggers.go b/plugins/repo/src/triggers/triggers.go new file mode 100644 index 000000000..b0dbd6eff --- /dev/null +++ b/plugins/repo/src/triggers/triggers.go @@ -0,0 +1,31 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/repo" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + var err error + switch trigger { + case "pre-delete": + appName := flag.Arg(0) + err = repo.PurgeCache(appName) + default: + common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger)) + } + + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/repo/src/subcommands/gc/gc.go b/plugins/repo/subcommands.go similarity index 52% rename from plugins/repo/src/subcommands/gc/gc.go rename to plugins/repo/subcommands.go index 1edcc741a..238c0b8fc 100644 --- a/plugins/repo/src/subcommands/gc/gc.go +++ b/plugins/repo/subcommands.go @@ -1,22 +1,20 @@ -package main +package repo import ( - "flag" + "errors" "strings" "github.com/dokku/dokku/plugins/common" ) -// runs 'git gc --aggressive' against the application's repo -func main() { - flag.Parse() - appName := flag.Arg(1) +// CommandGc runs 'git gc --aggressive' against the application's repo +func CommandGc(appName string) error { if appName == "" { - common.LogFail("Please specify an app to run the command on") + return errors.New("Please specify an app to run the command on") } err := common.VerifyAppName(appName) if err != nil { - common.LogFail(err.Error()) + return err } appRoot := strings.Join([]string{common.MustGetEnv("DOKKU_ROOT"), appName}, "/") @@ -26,4 +24,14 @@ func main() { gitGcCmd := common.NewShellCmd("git gc --aggressive") gitGcCmd.Env = cmdEnv gitGcCmd.Execute() + return nil +} + +// CommandPurgeCache deletes the contents of the build cache stored in the repository +func CommandPurgeCache(appName string) error { + if appName == "" { + common.LogFail("Please specify an app to run the command on") + } + + return PurgeCache(appName) } diff --git a/plugins/resource/.gitignore b/plugins/resource/.gitignore index bdb6a1395..a34683d35 100644 --- a/plugins/resource/.gitignore +++ b/plugins/resource/.gitignore @@ -1,6 +1,7 @@ /commands /subcommands/* /triggers/* +/triggers /install /post-delete /report diff --git a/plugins/resource/Makefile b/plugins/resource/Makefile index 3a2bf7315..ea16485f9 100644 --- a/plugins/resource/Makefile +++ b/plugins/resource/Makefile @@ -1,38 +1,6 @@ -include ../../common.mk - -GO_ARGS ?= -a - SUBCOMMANDS = subcommands/limit subcommands/limit-clear subcommands/report subcommands/reserve subcommands/reserve-clear TRIGGERS = triggers/docker-args-process-deploy triggers/install triggers/post-delete triggers/report triggers/resource-get-property -build-in-docker: clean - docker run --rm \ - -v $$PWD/../..:$(GO_REPO_ROOT) \ - -w $(GO_REPO_ROOT)/plugins/resource \ - $(BUILD_IMAGE) \ - bash -c "GO_ARGS='$(GO_ARGS)' make -j4 build" || exit $$? +BUILD = commands subcommands triggers +PLUGIN_NAME = resource -build: commands subcommands triggers - $(MAKE) triggers-copy - -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 triggers docker-args-process-deploy docker-args-process-run install post-delete report resource-get-property - -src-clean: - rm -rf .gitignore src triggers vendor Makefile *.go glide.* - -triggers: $(TRIGGERS) - -triggers/%: src/triggers/*/%.go - go build $(GO_ARGS) -o $@ $< - -triggers-copy: - cp triggers/* . - ln -sf docker-args-process-deploy docker-args-process-run +include ../../common.mk diff --git a/plugins/resource/src/subcommands/limit-clear/limit-clear.go b/plugins/resource/src/subcommands/limit-clear/limit-clear.go deleted file mode 100644 index b794dfc30..000000000 --- a/plugins/resource/src/subcommands/limit-clear/limit-clear.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/resource" -) - -func main() { - args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError) - processType := args.String("process-type", "", "process-type: A process type to clear") - args.Parse(os.Args[2:]) - - err := resource.CommandLimitClear(args.Args(), *processType) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/resource/src/subcommands/limit/limit.go b/plugins/resource/src/subcommands/limit/limit.go deleted file mode 100644 index d45438e3a..000000000 --- a/plugins/resource/src/subcommands/limit/limit.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/resource" -) - -func main() { - args := flag.NewFlagSet("resource:limit", flag.ExitOnError) - processType := args.String("process-type", "", "process-type: A process type to manage") - cpu := args.String("cpu", "", "cpu: The amount of cpu to limit processes by") - memory := args.String("memory", "", "memory: The amount of memory to limit processes by") - memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to limit processes by") - network := args.String("network", "", "network: The amount of network bandwidth to limit processes by") - networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to limit processes by") - networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by") - args.Parse(os.Args[2:]) - - resources := resource.Resource{ - CPU: *cpu, - Memory: *memory, - MemorySwap: *memorySwap, - Network: *network, - NetworkIngress: *networkIngress, - NetworkEgress: *networkEgress, - } - - err := resource.CommandLimit(args.Args(), *processType, resources) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/resource/src/subcommands/report/report.go b/plugins/resource/src/subcommands/report/report.go deleted file mode 100644 index f8385c3bd..000000000 --- a/plugins/resource/src/subcommands/report/report.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "flag" - "strings" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/resource" -) - -// displays a resource report for one or more apps -func main() { - flag.Parse() - appName := flag.Arg(1) - infoFlag := flag.Arg(2) - - if strings.HasPrefix(appName, "--") { - common.LogFail("The resource:report command does not support flags without an app name") - } - - if len(appName) == 0 { - apps, err := common.DokkuApps() - if err != nil { - return - } - for _, appName := range apps { - resource.ReportSingleApp(appName, infoFlag) - } - return - } - - resource.ReportSingleApp(appName, infoFlag) -} diff --git a/plugins/resource/src/subcommands/reserve-clear/reserve-clear.go b/plugins/resource/src/subcommands/reserve-clear/reserve-clear.go deleted file mode 100644 index 4f882388d..000000000 --- a/plugins/resource/src/subcommands/reserve-clear/reserve-clear.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/resource" -) - -func main() { - args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError) - processType := args.String("process-type", "", "process-type: A process type to clear") - args.Parse(os.Args[2:]) - - err := resource.CommandReserveClear(args.Args(), *processType) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/resource/src/subcommands/reserve/reserve.go b/plugins/resource/src/subcommands/reserve/reserve.go deleted file mode 100644 index afeccb551..000000000 --- a/plugins/resource/src/subcommands/reserve/reserve.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/resource" -) - -func main() { - args := flag.NewFlagSet("resource:reserve", flag.ExitOnError) - processType := args.String("process-type", "", "process-type: A process type to manage") - cpu := args.String("cpu", "", "cpu: The amount of cpu to reserve for processes") - memory := args.String("memory", "", "memory: The amount of memory to reserve for processes") - memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to reserve for processes") - network := args.String("network", "", "network: The amount of network bandwidth to reserve for processes") - networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to reserve for processes") - networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes") - args.Parse(os.Args[2:]) - - resources := resource.Resource{ - CPU: *cpu, - Memory: *memory, - MemorySwap: *memorySwap, - Network: *network, - NetworkIngress: *networkIngress, - NetworkEgress: *networkEgress, - } - - err := resource.CommandReserve(args.Args(), *processType, resources) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/resource/src/subcommands/subcommands.go b/plugins/resource/src/subcommands/subcommands.go new file mode 100644 index 000000000..c3b105fa9 --- /dev/null +++ b/plugins/resource/src/subcommands/subcommands.go @@ -0,0 +1,84 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/resource" +) + +// main entrypoint to all subcommands +func main() { + parts := strings.Split(os.Args[0], "/") + subcommand := parts[len(parts)-1] + + var err error + switch subcommand { + case "limit": + args := flag.NewFlagSet("resource:limit", flag.ExitOnError) + processType := args.String("process-type", "", "process-type: A process type to manage") + cpu := args.String("cpu", "", "cpu: The amount of cpu to limit processes by") + memory := args.String("memory", "", "memory: The amount of memory to limit processes by") + memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to limit processes by") + network := args.String("network", "", "network: The amount of network bandwidth to limit processes by") + networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to limit processes by") + networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to limit processes by") + args.Parse(os.Args[2:]) + + resources := resource.Resource{ + CPU: *cpu, + Memory: *memory, + MemorySwap: *memorySwap, + Network: *network, + NetworkIngress: *networkIngress, + NetworkEgress: *networkEgress, + } + + err = resource.CommandLimit(args.Args(), *processType, resources) + case "limit-clear": + args := flag.NewFlagSet("resource:limit-clear", flag.ExitOnError) + processType := args.String("process-type", "", "process-type: A process type to clear") + args.Parse(os.Args[2:]) + err = resource.CommandLimitClear(args.Args(), *processType) + case "report": + flag.Parse() + appName := flag.Arg(1) + infoFlag := flag.Arg(2) + resource.CommandReport(appName, infoFlag) + case "reserve": + args := flag.NewFlagSet("resource:reserve", flag.ExitOnError) + processType := args.String("process-type", "", "process-type: A process type to manage") + cpu := args.String("cpu", "", "cpu: The amount of cpu to reserve for processes") + memory := args.String("memory", "", "memory: The amount of memory to reserve for processes") + memorySwap := args.String("memory-swap", "", "memory-swap: The amount of swap memory to reserve for processes") + network := args.String("network", "", "network: The amount of network bandwidth to reserve for processes") + networkIngress := args.String("network-ingress", "", "network-ingress: The amount of ingress network bandwidth to reserve for processes") + networkEgress := args.String("network-egress", "", "network-egress: The amount of egress network bandwidth to reserve for processes") + args.Parse(os.Args[2:]) + + resources := resource.Resource{ + CPU: *cpu, + Memory: *memory, + MemorySwap: *memorySwap, + Network: *network, + NetworkIngress: *networkIngress, + NetworkEgress: *networkEgress, + } + + err = resource.CommandReserve(args.Args(), *processType, resources) + case "reserve-clear": + args := flag.NewFlagSet("resource:reserve-clear", flag.ExitOnError) + processType := args.String("process-type", "", "process-type: A process type to clear") + args.Parse(os.Args[2:]) + err = resource.CommandReserveClear(args.Args(), *processType) + default: + common.LogFail(fmt.Sprintf("Invalid plugin subcommand call: %s", subcommand)) + } + + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/resource/src/triggers/install/install.go b/plugins/resource/src/triggers/install/install.go deleted file mode 100644 index 77f7d14ed..000000000 --- a/plugins/resource/src/triggers/install/install.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/dokku/dokku/plugins/common" -) - -// runs the install step for the resource plugin -func main() { - if err := common.PropertySetup("resource"); err != nil { - common.LogFail(fmt.Sprintf("Unable to install the resource plugin: %s", err.Error())) - } -} diff --git a/plugins/resource/src/triggers/post-delete/post-delete.go b/plugins/resource/src/triggers/post-delete/post-delete.go deleted file mode 100644 index d22ceccea..000000000 --- a/plugins/resource/src/triggers/post-delete/post-delete.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/common" -) - -// destroys the resource property for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - - err := common.PropertyDestroy("resource", appName) - if err != nil { - common.LogFail(err.Error()) - } -} diff --git a/plugins/resource/src/triggers/report/report.go b/plugins/resource/src/triggers/report/report.go deleted file mode 100644 index b34ad49e0..000000000 --- a/plugins/resource/src/triggers/report/report.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "flag" - - "github.com/dokku/dokku/plugins/resource" -) - -// displays a resource report for one or more apps -func main() { - flag.Parse() - appName := flag.Arg(0) - - resource.ReportSingleApp(appName, "") -} diff --git a/plugins/resource/src/triggers/resource-get-property/resource-get-property.go b/plugins/resource/src/triggers/resource-get-property/resource-get-property.go deleted file mode 100644 index cacd856d9..000000000 --- a/plugins/resource/src/triggers/resource-get-property/resource-get-property.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/dokku/dokku/plugins/common" - "github.com/dokku/dokku/plugins/resource" -) - -// writes the resource key to stdout for a given app container -func main() { - flag.Parse() - appName := flag.Arg(0) - processType := flag.Arg(1) - resourceType := flag.Arg(2) - key := flag.Arg(3) - - value, err := resource.GetResourceValue(appName, processType, resourceType, key) - if err != nil { - common.LogFail(err.Error()) - } - - fmt.Fprintln(os.Stdout, value) -} diff --git a/plugins/resource/src/triggers/triggers.go b/plugins/resource/src/triggers/triggers.go new file mode 100644 index 000000000..2bdf6d362 --- /dev/null +++ b/plugins/resource/src/triggers/triggers.go @@ -0,0 +1,46 @@ +package main + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/resource" +) + +// main entrypoint to all triggers +func main() { + parts := strings.Split(os.Args[0], "/") + trigger := parts[len(parts)-1] + flag.Parse() + + var err error + switch trigger { + case "docker-args-process-deploy": + appName := flag.Arg(0) + processType := flag.Arg(3) + err = resource.TriggerDockerArgsProcessDeploy(appName, processType) + case "install": + err = resource.TriggerInstall() + case "post-delete": + appName := flag.Arg(0) + err = resource.TriggerPostDelete(appName) + case "report": + appName := flag.Arg(0) + resource.ReportSingleApp(appName, "") + case "resource-get-property": + appName := flag.Arg(0) + processType := flag.Arg(1) + resourceType := flag.Arg(2) + key := flag.Arg(3) + err = resource.TriggerResourceGetProperty(appName, processType, resourceType, key) + default: + common.LogFail(fmt.Sprintf("Invalid plugin trigger call: %s", trigger)) + } + + if err != nil { + common.LogFail(err.Error()) + } +} diff --git a/plugins/resource/subcommands.go b/plugins/resource/subcommands.go index b607a4609..e705d3016 100644 --- a/plugins/resource/subcommands.go +++ b/plugins/resource/subcommands.go @@ -2,6 +2,8 @@ package resource import ( "fmt" + "strings" + "github.com/dokku/dokku/plugins/common" ) @@ -26,6 +28,27 @@ func CommandLimitClear(args []string, processType string) error { return nil } +// CommandReport displays a resource report for one or more apps +func CommandReport(appName string, infoFlag string) { + if strings.HasPrefix(appName, "--") { + infoFlag = appName + appName = "" + } + + if len(appName) == 0 { + apps, err := common.DokkuApps() + if err != nil { + return + } + for _, appName := range apps { + ReportSingleApp(appName, infoFlag) + } + return + } + + ReportSingleApp(appName, infoFlag) +} + // CommandReserve implements resource:reserve func CommandReserve(args []string, processType string, r Resource) error { appName, err := getAppName(args) diff --git a/plugins/resource/src/triggers/docker-args-process-deploy/docker-args-process-deploy.go b/plugins/resource/triggers.go similarity index 59% rename from plugins/resource/src/triggers/docker-args-process-deploy/docker-args-process-deploy.go rename to plugins/resource/triggers.go index c8f8da8f9..4b9469a79 100644 --- a/plugins/resource/src/triggers/docker-args-process-deploy/docker-args-process-deploy.go +++ b/plugins/resource/triggers.go @@ -1,7 +1,6 @@ -package main +package resource import ( - "flag" "fmt" "io/ioutil" "os" @@ -10,26 +9,22 @@ import ( "github.com/dokku/dokku/plugins/common" ) -// outputs the process-specific docker options -func main() { +// TriggerDockerArgsProcessDeploy outputs the process-specific docker options +func TriggerDockerArgsProcessDeploy(appName string, processType string) error { stdin, err := ioutil.ReadAll(os.Stdin) if err != nil { - common.LogFail(err.Error()) + return err } - flag.Parse() - appName := flag.Arg(0) - processType := flag.Arg(3) - if os.Getenv("DOKKU_OMIT_RESOURCE_ARGS") == "1" { fmt.Print(string(stdin)) - return + return nil } resources, err := common.PropertyGetAll("resource", appName) if err != nil { fmt.Print(string(stdin)) - return + return nil } limits := make(map[string]string) @@ -86,4 +81,29 @@ func main() { } fmt.Print(string(stdin)) + return nil +} + +// TriggerInstall runs the install step for the resource plugin +func TriggerInstall() error { + if err := common.PropertySetup("resource"); err != nil { + return fmt.Errorf("Unable to install the resource plugin: %v", err) + } + return nil +} + +// TriggerPostDelete destroys the resource property for a given app container +func TriggerPostDelete(appName string) error { + return common.PropertyDestroy("resource", appName) +} + +// TriggerResourceGetProperty writes the resource key to stdout for a given app container +func TriggerResourceGetProperty(appName string, processType string, resourceType string, key string) error { + value, err := GetResourceValue(appName, processType, resourceType, key) + if err != nil { + return err + } + + fmt.Fprintln(os.Stdout, value) + return nil } diff --git a/plugins/scheduler-docker-local/check-deploy b/plugins/scheduler-docker-local/check-deploy index 57321ff1e..52eca560b 100755 --- a/plugins/scheduler-docker-local/check-deploy +++ b/plugins/scheduler-docker-local/check-deploy @@ -79,6 +79,7 @@ scheduler-docker-local-check-deploy() { local TIMEOUT="${DOKKU_CHECKS_TIMEOUT:-30}" # use this number of retries for checks local ATTEMPTS="${DOKKU_CHECKS_ATTEMPTS:-5}" + local CHECKS_URL="${DOKKU_CHECKS_URL:-http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/}" local CHECK_DEPLOY_TMP_WORK_DIR=$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX") local CHECKS_FILENAME=${CHECK_DEPLOY_TMP_WORK_DIR}/CHECKS @@ -101,9 +102,8 @@ scheduler-docker-local-check-deploy() { if [[ ! -s "${CHECKS_FILENAME}" ]] || [[ "$DOKKU_APP_CONTAINER_TYPE" != "web" ]]; then # We allow custom check for web instances only if [[ "$DOKKU_APP_CONTAINER_TYPE" == "web" ]]; then - dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS." - dokku_log_verbose "See http://dokku.viewdocs.io/dokku/deployment/zero-downtime-deploys/ for examples" dokku_log_verbose "CHECKS file not found in container: Running simple container check..." + dokku_log_verbose "For more efficient zero downtime deployments, create a file CHECKS. See ${CHECKS_URL} for examples" else dokku_log_verbose "Non web container detected: Running default container check..." fi @@ -116,10 +116,10 @@ scheduler-docker-local-check-deploy() { sleep "$DOKKU_DEFAULT_CHECKS_WAIT" ! (is_container_status "$DOKKU_APP_CONTAINER_ID" "Running") && dokku_log_fail "App container failed to start!!" - local container_restarts="$("$DOCKER_BIN" inspect -f "{{ .RestartCount }}" "$DOKKU_APP_CONTAINER_ID")" + local container_restarts="$("$DOCKER_BIN" container inspect --format "{{ .RestartCount }}" "$DOKKU_APP_CONTAINER_ID")" if [[ $container_restarts -ne 0 ]]; then "$DOCKER_BIN" container update --restart=no "$DOKKU_APP_CONTAINER_ID" &>/dev/null || true - "$DOCKER_BIN" stop "$DOKKU_APP_CONTAINER_ID" || true + "$DOCKER_BIN" container stop "$DOKKU_APP_CONTAINER_ID" || true dokku_log_fail "App container failed to start!!" fi diff --git a/plugins/scheduler-docker-local/core-post-deploy b/plugins/scheduler-docker-local/core-post-deploy index f6733ade8..c2bb39db5 100755 --- a/plugins/scheduler-docker-local/core-post-deploy +++ b/plugins/scheduler-docker-local/core-post-deploy @@ -37,26 +37,26 @@ scheduler-docker-local-core-post-deploy() { local NAME="$APP.$DYNO" local CURRENT_CONTAINER_ID="$(<"$container")" # TODO: Ensure these are from the current service - local PREVIOUS_CIDS=$("$DOCKER_BIN" ps -a -q -f name="^.?$NAME\$" | xargs) || true + local PREVIOUS_CIDS=$("$DOCKER_BIN" container list --all --quiet --filter name="^.?$NAME\$" | xargs) || true if [[ -n $PREVIOUS_CIDS ]]; then dokku_log_verbose_quiet "Found previous container(s) ($PREVIOUS_CIDS) named $NAME" # in case $PREVIOUS_CIDS has more than one entry local cid for cid in $PREVIOUS_CIDS; do - local PREVIOUS_CONTAINER_STATUS=$("$DOCKER_BIN" inspect -f '{{.State.Status}}' "$cid" || echo "dead") + local PREVIOUS_CONTAINER_STATUS=$("$DOCKER_BIN" container inspect --format '{{.State.Status}}' "$cid" || echo "dead") # dead containers cannot be renamed if [[ "$PREVIOUS_CONTAINER_STATUS" != "dead" ]]; then local CONTAINER_DATE_NAME="$NAME.$(date +%s)" dokku_log_verbose_quiet "Renaming container ($cid) ${NAME} to $CONTAINER_DATE_NAME" - "$DOCKER_BIN" rename "$NAME" "$CONTAINER_DATE_NAME" >/dev/null 2>&1 || dokku_log_warn "Unable to rename container" + "$DOCKER_BIN" container rename "$NAME" "$CONTAINER_DATE_NAME" >/dev/null 2>&1 || dokku_log_warn "Unable to rename container" fi done fi local ID=$(cat "$container") - local CURRENT_NAME=$("$DOCKER_BIN" inspect -f '{{.Name}}' "$ID" | tr -d /) + local CURRENT_NAME=$("$DOCKER_BIN" container inspect --format '{{.Name}}' "$ID" | tr -d /) if [[ -n "$CURRENT_NAME" ]]; then dokku_log_verbose_quiet "Renaming container (${ID:0:12}) $CURRENT_NAME to $NAME" - "$DOCKER_BIN" rename "$CURRENT_NAME" "$NAME" >/dev/null + "$DOCKER_BIN" container rename "$CURRENT_NAME" "$NAME" >/dev/null fi done shopt -u nullglob diff --git a/plugins/scheduler-docker-local/internal-functions b/plugins/scheduler-docker-local/internal-functions index b787a067d..955f9b5df 100755 --- a/plugins/scheduler-docker-local/internal-functions +++ b/plugins/scheduler-docker-local/internal-functions @@ -95,7 +95,7 @@ fn-scheduler-docker-local-retire-container() { declare APP="$1" CID="$2" DEAD_TIME="$3" local STATE - STATE="$("$DOCKER_BIN" inspect -f "{{ .State.Status }}" "$CID" 2>/dev/null || true)" + STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)" if [[ -z "$STATE" ]]; then return fi @@ -104,7 +104,7 @@ fn-scheduler-docker-local-retire-container() { [[ $DOKKU_DOCKER_STOP_TIMEOUT ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}" if [[ "$STATE" == "restarting" ]]; then - "$DOCKER_BIN" update --restart=no "$CID" >/dev/null 2>&1 + "$DOCKER_BIN" container update --restart=no "$CID" >/dev/null 2>&1 fi if [[ "$STATE" != "dead" ]] && [[ "$STATE" != "exited" ]]; then @@ -112,18 +112,18 @@ fn-scheduler-docker-local-retire-container() { # to not send SIGKILL as the docs would indicate. If that fails, move # on to the next. # shellcheck disable=SC2086 - "$DOCKER_BIN" stop $DOCKER_STOP_TIME_ARG "$CID" \ - || "$DOCKER_BIN" kill "$CID" \ + "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$CID" \ + || "$DOCKER_BIN" container kill "$CID" \ || dokku_log_warn "Unable to kill container ${CID}" fi - STATE="$("$DOCKER_BIN" inspect -f "{{ .State.Status }}" "$CID" 2>/dev/null || true)" + STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)" if [[ -z "$STATE" ]]; then return fi if [[ "$STATE" != "dead" ]] && [[ "$STATE" != "exited" ]]; then - if ! "$DOCKER_BIN" kill "$CID"; then + if ! "$DOCKER_BIN" container kill "$CID"; then dokku_log_warn "Unable to kill container ${CID}" fi fi diff --git a/plugins/scheduler-docker-local/post-delete b/plugins/scheduler-docker-local/post-delete index 405ecde4f..75df108a9 100755 --- a/plugins/scheduler-docker-local/post-delete +++ b/plugins/scheduler-docker-local/post-delete @@ -18,14 +18,14 @@ scheduler-docker-local-post-delete() { # remove all application containers & images # shellcheck disable=SC2046 - local DOKKU_APP_CIDS=$("$DOCKER_BIN" ps -a --no-trunc | egrep "dokku/${APP}:" | awk '{ print $1 }' | xargs) + local DOKKU_APP_CIDS=$("$DOCKER_BIN" container list --all --no-trunc | egrep "dokku/${APP}:" | awk '{ print $1 }' | xargs) if [[ -n "$DOKKU_APP_CIDS" ]]; then # shellcheck disable=SC2086 - "$DOCKER_BIN" rm -f $DOKKU_APP_CIDS >/dev/null 2>&1 || true + "$DOCKER_BIN" container rm --force $DOKKU_APP_CIDS >/dev/null 2>&1 || true fi # shellcheck disable=SC2046 - "$DOCKER_BIN" rmi $("$DOCKER_BIN" images -q "$IMAGE_REPO" | xargs) &>/dev/null || true + "$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --quiet "$IMAGE_REPO" | xargs) &>/dev/null || true } scheduler-docker-local-post-delete "$@" diff --git a/plugins/scheduler-docker-local/pre-deploy b/plugins/scheduler-docker-local/pre-deploy index 1e89b0d07..6dbb97b67 100755 --- a/plugins/scheduler-docker-local/pre-deploy +++ b/plugins/scheduler-docker-local/pre-deploy @@ -44,7 +44,7 @@ scheduler-docker-local-pre-deploy() { fi # shellcheck disable=SC2086 - "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $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 + "$DOCKER_BIN" container run "${DOCKER_RUN_LABEL_ARGS[@]}" $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 } scheduler-docker-local-pre-deploy "$@" diff --git a/plugins/scheduler-docker-local/pre-restore b/plugins/scheduler-docker-local/pre-restore index 802167ffb..a2a427c9b 100755 --- a/plugins/scheduler-docker-local/pre-restore +++ b/plugins/scheduler-docker-local/pre-restore @@ -14,7 +14,7 @@ scheduler-docker-local-pre-restore() { # delete all "old" containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps --format "{{.Names}}" -a -f "label=$DOKKU_CONTAINER_LABEL" -q | grep -E '(.+\..+\.[0-9]+\.[0-9]+$)') &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --format "{{.Names}}" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet | grep -E '(.+\..+\.[0-9]+\.[0-9]+$)') &>/dev/null || true } scheduler-docker-local-pre-restore "$@" diff --git a/plugins/scheduler-docker-local/scheduler-deploy b/plugins/scheduler-docker-local/scheduler-deploy index 9a5dc70f3..6138f081f 100755 --- a/plugins/scheduler-docker-local/scheduler-deploy +++ b/plugins/scheduler-docker-local/scheduler-deploy @@ -50,7 +50,7 @@ scheduler-docker-local-scheduler-deploy() { if [[ "$(is_app_proctype_checks_disabled "$APP" "$PROC_TYPE")" == "true" ]]; then dokku_log_info1 "zero downtime is disabled for app ($APP.$PROC_TYPE). stopping currently running containers" - local cid proctype_oldids="$(get_app_running_container_ids "$APP" "$PROC_TYPE")" + local cid proctype_oldids="$(get_app_running_container_ids "$APP" "$PROC_TYPE" 2>/dev/null)" for cid in $proctype_oldids; do dokku_log_info2 "stopping $APP.$PROC_TYPE ($cid)" @@ -58,7 +58,7 @@ scheduler-docker-local-scheduler-deploy() { "$DOCKER_BIN" container update --restart=no "$cid" &>/dev/null || true # shellcheck disable=SC2086 - "$DOCKER_BIN" stop $DOCKER_STOP_TIME_ARG "$cid" &>/dev/null + "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$cid" &>/dev/null # remove cid from oldids to skip the old container finish processing oldids="$(remove_val_from_list "$cid" "$oldids" " ")" done @@ -98,16 +98,16 @@ scheduler-docker-local-scheduler-deploy() { START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH" "$DOKKU_PORT") if [[ "$DOKKU_NETWORK_BIND_ALL" == "false" ]]; then # shellcheck disable=SC2086 - cid=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d -e PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) + cid=$("$DOCKER_BIN" container run --label=com.dokku.container-type=deploy "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --detach --env PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) else # shellcheck disable=SC2086 - cid=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d $DOKKU_DOCKER_PORT_ARGS -e PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) + cid=$("$DOCKER_BIN" container run --label=com.dokku.container-type=deploy "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --detach $DOKKU_DOCKER_PORT_ARGS --env PORT=$DOKKU_PORT "${ARG_ARRAY[@]}" $IMAGE $START_CMD) fi else START_CMD=$(fn-scheduler-docker-local-extract-start-cmd "$APP" "$PROC_TYPE" "$START_CMD" "$DOKKU_HEROKUISH") # shellcheck disable=SC2086 - cid=$("$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS -d "${ARG_ARRAY[@]}" $IMAGE $START_CMD) + cid=$("$DOCKER_BIN" container run --label=com.dokku.container-type=deploy "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS --detach "${ARG_ARRAY[@]}" $IMAGE $START_CMD) fi ipaddr=$(plugn trigger network-get-ipaddr "$APP" "$PROC_TYPE" "$cid") @@ -118,10 +118,10 @@ scheduler-docker-local-scheduler-deploy() { declare CID="$1" PROC_TYPE="$2" CONTAINER_INDEX="$3" mkdir -p "${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP" echo "${CID} ${PROC_TYPE}.${CONTAINER_INDEX}" >>"${DOKKU_LIB_ROOT}/data/scheduler-docker-local/$APP/failed-containers" - "$DOCKER_BIN" inspect "$CID" &>/dev/null && { + "$DOCKER_BIN" container inspect "$CID" &>/dev/null && { # Disable the container restart policy "$DOCKER_BIN" container update --restart=no "$CID" &>/dev/null || true - "$DOCKER_BIN" stop "$CID" >/dev/null && "$DOCKER_BIN" kill "$CID" &>/dev/null + "$DOCKER_BIN" container stop "$CID" >/dev/null && "$DOCKER_BIN" container kill "$CID" &>/dev/null } trap - INT TERM EXIT kill -9 $$ @@ -191,8 +191,8 @@ scheduler-docker-local-scheduler-deploy() { # to not send SIGKILL as the docs would indicate. If that fails, move # on to the next. # shellcheck disable=SC2086 - "$DOCKER_BIN" stop $DOCKER_STOP_TIME_ARG "$oldid" \ - || "$DOCKER_BIN" kill "$oldid" \ + "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG "$oldid" \ + || "$DOCKER_BIN" container kill "$oldid" \ || plugn trigger retire-container-failed "$APP" "$oldid" # plugin trigger for event logging done ) & diff --git a/plugins/scheduler-docker-local/scheduler-docker-cleanup b/plugins/scheduler-docker-local/scheduler-docker-cleanup index 7d9325bc5..6c041d1a5 100755 --- a/plugins/scheduler-docker-local/scheduler-docker-cleanup +++ b/plugins/scheduler-docker-local/scheduler-docker-cleanup @@ -15,30 +15,30 @@ scheduler-docker-local-scheduler-docker-cleanup() { if [[ -n "$APP" ]]; then # delete all non-running containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=exited" -f "label=$DOKKU_CONTAINER_LABEL" -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true # delete all dead containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=dead" -f "label=$DOKKU_CONTAINER_LABEL" -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true # delete danging images # shellcheck disable=SC2046 - "$DOCKER_BIN" rmi $("$DOCKER_BIN" images -f 'dangling=true' -f "label=com.dokku.app-name=$APP" -q) &>/dev/null || true + "$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --filter "label=com.dokku.app-name=$APP" --quiet) &>/dev/null || true # delete unused images "$DOCKER_BIN" image prune --all --filter "label=com.dokku.app-name=$APP" --force &>/dev/null || true else # delete all non-running containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=exited" -f "label=$DOKKU_CONTAINER_LABEL" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=exited" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true # delete all dead containers # shellcheck disable=SC2046 - "$DOCKER_BIN" rm $("$DOCKER_BIN" ps -a -f "status=dead" -f "label=$DOKKU_CONTAINER_LABEL" -q) &>/dev/null || true + "$DOCKER_BIN" container rm $("$DOCKER_BIN" container list --all --filter "status=dead" --filter "label=$DOKKU_CONTAINER_LABEL" --quiet) &>/dev/null || true # delete danging images # shellcheck disable=SC2046 - "$DOCKER_BIN" rmi $("$DOCKER_BIN" images -f 'dangling=true' -q) &>/dev/null || true + "$DOCKER_BIN" image rm $("$DOCKER_BIN" image list --filter 'dangling=true' --quiet) &>/dev/null || true fi } diff --git a/plugins/scheduler-docker-local/scheduler-inspect b/plugins/scheduler-docker-local/scheduler-inspect index 5fd7e8e2e..c6ef49d06 100755 --- a/plugins/scheduler-docker-local/scheduler-inspect +++ b/plugins/scheduler-docker-local/scheduler-inspect @@ -40,7 +40,7 @@ for container in data: container['Config']['Env'] = env output.append(container) -print json.dumps(data, sort_keys=True, indent=4) +print(json.dumps(data, sort_keys=True, indent=4)) EOF local CONTAINER_FILES="$(find "$DOKKU_ROOT/$APP" -maxdepth 1 -name "CONTAINER.*" -printf "%f\n" 2>/dev/null | sort -t . -k 2 -n | xargs)" @@ -48,7 +48,7 @@ EOF for CONTAINER_FILE in $CONTAINER_FILES; do CIDS+="$(<"$DOKKU_ROOT/$APP/$CONTAINER_FILE")" done - "$DOCKER_BIN" inspect "${CIDS[@]}" | python2.7 "$TMP_INSPECT_CMD" + "$DOCKER_BIN" container inspect "${CIDS[@]}" | python2.7 "$TMP_INSPECT_CMD" } diff --git a/plugins/scheduler-docker-local/scheduler-logs-failed b/plugins/scheduler-docker-local/scheduler-logs-failed index 476e91b72..f231b9bdc 100755 --- a/plugins/scheduler-docker-local/scheduler-logs-failed +++ b/plugins/scheduler-docker-local/scheduler-logs-failed @@ -24,7 +24,7 @@ scheduler-docker-local-scheduler-logs-failed() { while read -r LINE || [[ -n "$LINE" ]]; do CID="$(echo "$LINE" | cut -d ' ' -f1)" PREFIX="$(echo "$LINE" | cut -d ' ' -f2)" - if "$DOCKER_BIN" inspect "${CID}" >/dev/null 2>&1; then + if "$DOCKER_BIN" container inspect "${CID}" >/dev/null 2>&1; then RUNNING_CONTAINERS+=("$CID") else DEAD_CONTAINERS+=("$CID") diff --git a/plugins/scheduler-docker-local/scheduler-retire b/plugins/scheduler-docker-local/scheduler-retire index af24e75ad..d60d8f8e2 100755 --- a/plugins/scheduler-docker-local/scheduler-retire +++ b/plugins/scheduler-docker-local/scheduler-retire @@ -27,7 +27,7 @@ scheduler-docker-local-scheduler-retire() { fi fn-scheduler-docker-local-retire-container "$APP" "$CID" "$DEAD_TIME" - STATE="$("$DOCKER_BIN" inspect -f "{{ .State.Status }}" "$CID" 2>/dev/null || true)" + STATE="$("$DOCKER_BIN" container inspect --format "{{ .State.Status }}" "$CID" 2>/dev/null || true)" if [[ -z "$STATE" ]]; then DEAD_CONTAINERS+=("$CID") continue @@ -38,8 +38,8 @@ scheduler-docker-local-scheduler-retire() { continue fi - "$DOCKER_BIN" rm -f "$CID" >/dev/null 2>&1 || true - if "$DOCKER_BIN" inspect "${CID}" >/dev/null 2>&1; then + "$DOCKER_BIN" container rm --force "$CID" >/dev/null 2>&1 || true + if "$DOCKER_BIN" container inspect "${CID}" >/dev/null 2>&1; then dokku_log_warn "Container ${CID} still running" continue fi diff --git a/plugins/scheduler-docker-local/scheduler-run b/plugins/scheduler-docker-local/scheduler-run index d72d1f30b..2ef1a89f5 100755 --- a/plugins/scheduler-docker-local/scheduler-run +++ b/plugins/scheduler-docker-local/scheduler-run @@ -31,15 +31,15 @@ scheduler-docker-local-scheduler-run() { local DOCKER_ARGS=$(: | plugn trigger docker-args-run "$APP" "$IMAGE_TAG") [[ "$DOKKU_TRACE" ]] && DOCKER_ARGS+=" -e TRACE=true " + local DYNO_NUMBER="$RANDOM" local IMAGE_SOURCE_TYPE="dockerfile" is_image_herokuish_based "$IMAGE" && IMAGE_SOURCE_TYPE="herokuish" DOCKER_ARGS+=$(: | plugn trigger docker-args-process-run "$APP" "$IMAGE_TAG" "$IMAGE_SOURCE_TYPE") - DOCKER_ARGS+=" -e DYNO=run.$RANDOM" + DOCKER_ARGS+=" -e DYNO=run.$DYNO_NUMBER --name $APP.run.$DYNO_NUMBER" declare -a ARG_ARRAY eval "ARG_ARRAY=($DOCKER_ARGS)" - local DOKKU_RUN_OPTS=" -e DYNO=run.$RANDOM" if [[ "$DOKKU_RM_CONTAINER" ]]; then DOCKER_ARGS+=" --rm" elif [[ "$DOKKU_DETACH_CONTAINER" ]]; then @@ -53,6 +53,15 @@ scheduler-docker-local-scheduler-run() { DOCKER_ARGS_ARRAY+=("--env=$env_pair") done + if [[ -n "$DOKKU_GLOBAL_FLAGS" ]]; then + read -ra flags <<<"$DOKKU_GLOBAL_FLAGS" + for flag in "${flags[@]}"; do + if [[ "$flag" =~ ^--label.* ]]; then + DOCKER_ARGS_ARRAY+=("$flag") + fi + done + fi + [[ "$IMAGE_SOURCE_TYPE" == "herokuish" ]] && local EXEC_CMD="/exec" DOKKU_QUIET_OUTPUT=1 extract_procfile "$APP" @@ -67,7 +76,7 @@ scheduler-docker-local-scheduler-run() { fi # shellcheck disable=SC2086 - "$DOCKER_BIN" run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "${DOCKER_ARGS_ARRAY[@]}" $IMAGE $EXEC_CMD "$@" + "$DOCKER_BIN" container run --label=com.dokku.container-type=run "${DOCKER_RUN_LABEL_ARGS[@]}" $DOKKU_GLOBAL_RUN_ARGS "${DOCKER_ARGS_ARRAY[@]}" $IMAGE $EXEC_CMD "$@" } scheduler-docker-local-scheduler-run "$@" diff --git a/plugins/scheduler-docker-local/scheduler-stop b/plugins/scheduler-docker-local/scheduler-stop index 553b950bd..f5a8787ca 100755 --- a/plugins/scheduler-docker-local/scheduler-stop +++ b/plugins/scheduler-docker-local/scheduler-stop @@ -13,7 +13,7 @@ scheduler-docker-local-scheduler-stop() { return fi - local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP") + local DOKKU_APP_RUNNING_CONTAINER_IDS=$(get_app_running_container_ids "$APP" 2>/dev/null) local DOKKU_DOCKER_STOP_TIMEOUT="$(config_get "$APP" DOKKU_DOCKER_STOP_TIMEOUT || true)" [[ -n "$DOKKU_DOCKER_STOP_TIMEOUT" ]] && DOCKER_STOP_TIME_ARG="--time=${DOKKU_DOCKER_STOP_TIMEOUT}" @@ -24,7 +24,7 @@ scheduler-docker-local-scheduler-stop() { "$DOCKER_BIN" container update --restart=no $DOKKU_APP_RUNNING_CONTAINER_IDS &>/dev/null || true # shellcheck disable=SC2086 - "$DOCKER_BIN" stop $DOCKER_STOP_TIME_ARG $DOKKU_APP_RUNNING_CONTAINER_IDS >/dev/null || true + "$DOCKER_BIN" container stop $DOCKER_STOP_TIME_ARG $DOKKU_APP_RUNNING_CONTAINER_IDS >/dev/null || true fi if [[ "$REMOVE_CONTAINERS" == "true" ]]; then @@ -32,7 +32,7 @@ scheduler-docker-local-scheduler-stop() { if [[ -n "$DOKKU_APP_CIDS" ]]; then # shellcheck disable=SC2086 - "$DOCKER_BIN" rm -f $DOKKU_APP_CIDS >/dev/null 2>&1 || true + "$DOCKER_BIN" container rm --force $DOKKU_APP_CIDS >/dev/null 2>&1 || true fi fi } diff --git a/plugins/scheduler-docker-local/scheduler-tags-create b/plugins/scheduler-docker-local/scheduler-tags-create index 5d04aa6f7..128d499da 100755 --- a/plugins/scheduler-docker-local/scheduler-tags-create +++ b/plugins/scheduler-docker-local/scheduler-tags-create @@ -15,7 +15,7 @@ scheduler-docker-local-scheduler-tags-create() { local TAG_OPTS="" [[ $(is_tag_force_available) ]] && TAG_OPTS="-f" # shellcheck disable=SC2086 - "$DOCKER_BIN" tag $TAG_OPTS "$SOURCE_IMAGE" "$TARGET_IMAGE" + "$DOCKER_BIN" image tag $TAG_OPTS "$SOURCE_IMAGE" "$TARGET_IMAGE" } is_tag_force_available() { diff --git a/plugins/scheduler-docker-local/scheduler-tags-destroy b/plugins/scheduler-docker-local/scheduler-tags-destroy index 0fbaeab2f..078905659 100755 --- a/plugins/scheduler-docker-local/scheduler-tags-destroy +++ b/plugins/scheduler-docker-local/scheduler-tags-destroy @@ -12,7 +12,7 @@ scheduler-docker-local-scheduler-tags-destroy() { return fi - "$DOCKER_BIN" rmi "$IMAGE_REPO:$IMAGE_TAG" + "$DOCKER_BIN" image rm "$IMAGE_REPO:$IMAGE_TAG" } scheduler-docker-local-scheduler-tags-destroy "$@" diff --git a/plugins/ssh-keys/user-auth b/plugins/ssh-keys/user-auth deleted file mode 100755 index 6fea1dca8..000000000 --- a/plugins/ssh-keys/user-auth +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -eo pipefail -[[ $DOKKU_TRACE ]] && set -x -source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" - -check_ssh_keys_user() { - declare desc="check user passed by user-auth for ssh-keys plugin" - local SSH_USER=$1 SSH_NAME=$2 - [[ "$SSH_USER" == "root" || "$SSH_NAME" == *admin* ]] || dokku_log_fail "You must be root, or a dokku admin, to execute this command" -} - -if [[ "$3" =~ (ssh-keys:add|ssh-keys:remove) ]]; then - check_ssh_keys_user "$@" -fi diff --git a/plugins/tags/subcommands/default b/plugins/tags/subcommands/default index 7ccecf21e..fd9272e1e 100755 --- a/plugins/tags/subcommands/default +++ b/plugins/tags/subcommands/default @@ -12,7 +12,7 @@ tags_main_cmd() { verify_app_name "$APP" dokku_log_info2_quiet "Image tags for $IMAGE_REPO" - "$DOCKER_BIN" images "$IMAGE_REPO" + "$DOCKER_BIN" image list "$IMAGE_REPO" } tags_main_cmd "$@" diff --git a/plugins/trace/plugin.toml b/plugins/trace/plugin.toml old mode 100755 new mode 100644 diff --git a/rpm.mk b/rpm.mk index ccc0ca9af..fb5cdbe86 100644 --- a/rpm.mk +++ b/rpm.mk @@ -65,6 +65,7 @@ endif --depends 'dos2unix' \ --depends 'git' \ --depends 'gliderlabs-sigil' \ + --depends 'jq' \ --depends 'man-db' \ --depends 'nc' \ --depends 'nginx >= 1.8.0' \ diff --git a/tests/apps/gogrpc/Dockerfile b/tests/apps/gogrpc/Dockerfile new file mode 100644 index 000000000..855e9ddce --- /dev/null +++ b/tests/apps/gogrpc/Dockerfile @@ -0,0 +1,9 @@ +FROM golang:1.12 + +RUN mkdir /app +WORKDIR /app + +ADD . /app +RUN go install ./... + +CMD /go/bin/greeter_server diff --git a/tests/apps/gogrpc/go.mod b/tests/apps/gogrpc/go.mod new file mode 100644 index 000000000..0f08a07e1 --- /dev/null +++ b/tests/apps/gogrpc/go.mod @@ -0,0 +1,23 @@ +module github.com/dokku/dokko/tests/apps/gorpc + +go 1.12 + +require ( + cloud.google.com/go v0.44.3 // indirect + github.com/golang/protobuf v1.3.2 + github.com/google/go-cmp v0.3.1 // indirect + github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/kr/pty v1.1.8 // indirect + golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 // indirect + golang.org/x/mobile v0.0.0-20190814143026-e8b3e6111d02 // indirect + golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 + golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect + golang.org/x/tools v0.0.0-20190822000311-fc82fb2afd64 // indirect + google.golang.org/api v0.9.0 // indirect + google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect + google.golang.org/grpc v1.23.0 + honnef.co/go/tools v0.0.1-2019.2.2 // indirect +) + +replace google.golang.org/grpc/examples/helloworld/helloworld => ./helloworld diff --git a/tests/apps/gogrpc/go.sum b/tests/apps/gogrpc/go.sum new file mode 100644 index 000000000..02004b956 --- /dev/null +++ b/tests/apps/gogrpc/go.sum @@ -0,0 +1,143 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190814143026-e8b3e6111d02/go.mod h1:z5wpDCy2wbnXyFdvEuY3LhY9gBUL86/IOILm+Hsjx+E= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190822000311-fc82fb2afd64/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/tests/apps/gogrpc/greeter_client/main.go b/tests/apps/gogrpc/greeter_client/main.go new file mode 100644 index 000000000..7274c1088 --- /dev/null +++ b/tests/apps/gogrpc/greeter_client/main.go @@ -0,0 +1,66 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package main implements a client for Greeter service. +package main + +import ( + "context" + "crypto/tls" + "flag" + "fmt" + "log" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + pb "google.golang.org/grpc/examples/helloworld/helloworld" +) + +var ( + address = flag.String("address", "", "address to call") + name = flag.String("name", "world", "the name") + selfSignedTLS = flag.Bool("tls", false, "use self signed tls") +) + +func main() { + flag.Parse() + // Set up a connection to the server. + var opts []grpc.DialOption + if *selfSignedTLS { + creds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}) + opts = append(opts, grpc.WithTransportCredentials(creds)) + } else { + opts = append(opts, grpc.WithInsecure()) + } + conn, err := grpc.Dial(*address, opts...) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + // Contact the server and print out its response. + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + fmt.Printf("Greeting: %s", r.Message) +} diff --git a/tests/apps/gogrpc/greeter_server/main.go b/tests/apps/gogrpc/greeter_server/main.go new file mode 100644 index 000000000..e99fb26a3 --- /dev/null +++ b/tests/apps/gogrpc/greeter_server/main.go @@ -0,0 +1,56 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +//go:generate protoc -I ../helloworld --go_out=plugins=grpc:../helloworld ../helloworld/helloworld.proto + +// Package main implements a server for Greeter service. +package main + +import ( + "context" + "log" + "net" + + "google.golang.org/grpc" + pb "google.golang.org/grpc/examples/helloworld/helloworld" +) + +const ( + port = ":50051" +) + +// server is used to implement helloworld.GreeterServer. +type server struct{} + +// SayHello implements helloworld.GreeterServer +func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + log.Printf("Received: %v", in.Name) + return &pb.HelloReply{Message: "Hello " + in.Name}, nil +} + +func main() { + lis, err := net.Listen("tcp", port) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterGreeterServer(s, &server{}) + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} diff --git a/tests/apps/gogrpc/helloworld/helloworld.pb.go b/tests/apps/gogrpc/helloworld/helloworld.pb.go new file mode 100644 index 000000000..11383d740 --- /dev/null +++ b/tests/apps/gogrpc/helloworld/helloworld.pb.go @@ -0,0 +1,198 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: helloworld.proto + +package helloworld + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// The request message containing the user's name. +type HelloRequest struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelloRequest) Reset() { *m = HelloRequest{} } +func (m *HelloRequest) String() string { return proto.CompactTextString(m) } +func (*HelloRequest) ProtoMessage() {} +func (*HelloRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_helloworld_71e208cbdc16936b, []int{0} +} +func (m *HelloRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelloRequest.Unmarshal(m, b) +} +func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic) +} +func (dst *HelloRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelloRequest.Merge(dst, src) +} +func (m *HelloRequest) XXX_Size() int { + return xxx_messageInfo_HelloRequest.Size(m) +} +func (m *HelloRequest) XXX_DiscardUnknown() { + xxx_messageInfo_HelloRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_HelloRequest proto.InternalMessageInfo + +func (m *HelloRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +// The response message containing the greetings +type HelloReply struct { + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelloReply) Reset() { *m = HelloReply{} } +func (m *HelloReply) String() string { return proto.CompactTextString(m) } +func (*HelloReply) ProtoMessage() {} +func (*HelloReply) Descriptor() ([]byte, []int) { + return fileDescriptor_helloworld_71e208cbdc16936b, []int{1} +} +func (m *HelloReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelloReply.Unmarshal(m, b) +} +func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic) +} +func (dst *HelloReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelloReply.Merge(dst, src) +} +func (m *HelloReply) XXX_Size() int { + return xxx_messageInfo_HelloReply.Size(m) +} +func (m *HelloReply) XXX_DiscardUnknown() { + xxx_messageInfo_HelloReply.DiscardUnknown(m) +} + +var xxx_messageInfo_HelloReply proto.InternalMessageInfo + +func (m *HelloReply) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func init() { + proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest") + proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// GreeterClient is the client API for Greeter service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type GreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type greeterClient struct { + cc *grpc.ClientConn +} + +func NewGreeterClient(cc *grpc.ClientConn) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GreeterServer is the server API for Greeter service. +type GreeterServer interface { + // Sends a greeting + SayHello(context.Context, *HelloRequest) (*HelloReply, error) +} + +func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) { + s.RegisterService(&_Greeter_serviceDesc, srv) +} + +func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/helloworld.Greeter/SayHello", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Greeter_serviceDesc = grpc.ServiceDesc{ + ServiceName: "helloworld.Greeter", + HandlerType: (*GreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _Greeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helloworld.proto", +} + +func init() { proto.RegisterFile("helloworld.proto", fileDescriptor_helloworld_71e208cbdc16936b) } + +var fileDescriptor_helloworld_71e208cbdc16936b = []byte{ + // 175 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9, + 0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88, + 0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42, + 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92, + 0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71, + 0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a, + 0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64, + 0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x14, 0xe4, 0x54, 0x2a, 0x31, 0x38, 0x19, 0x70, 0x49, 0x67, 0xe6, + 0xeb, 0xa5, 0x17, 0x15, 0x24, 0xeb, 0xa5, 0x56, 0x24, 0xe6, 0x16, 0xe4, 0xa4, 0x16, 0x23, 0xa9, + 0x75, 0xe2, 0x07, 0x2b, 0x0e, 0x07, 0xb1, 0x03, 0x40, 0x5e, 0x0a, 0x60, 0x4c, 0x62, 0x03, 0xfb, + 0xcd, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x0f, 0xb7, 0xcd, 0xf2, 0xef, 0x00, 0x00, 0x00, +} diff --git a/tests/apps/gogrpc/helloworld/helloworld.proto b/tests/apps/gogrpc/helloworld/helloworld.proto new file mode 100644 index 000000000..d79a6a0d1 --- /dev/null +++ b/tests/apps/gogrpc/helloworld/helloworld.proto @@ -0,0 +1,37 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/tests/apps/multi/requirements.txt b/tests/apps/multi/requirements.txt index f4154234b..93d7fd192 100644 --- a/tests/apps/multi/requirements.txt +++ b/tests/apps/multi/requirements.txt @@ -1,2 +1,2 @@ -Flask==0.10.1 -gunicorn==18.0 +Flask==1.1.1 +gunicorn==19.9.0 diff --git a/tests/apps/python-flask/requirements.txt b/tests/apps/python-flask/requirements.txt index 7299a1046..46d297b21 100644 --- a/tests/apps/python-flask/requirements.txt +++ b/tests/apps/python-flask/requirements.txt @@ -1,5 +1,5 @@ -Flask==0.9 -Jinja2==2.6 -Werkzeug==0.8.3 -gunicorn==0.17.2 +Flask==1.1.1 +Jinja2==2.10.1 +Werkzeug==0.15.6 +gunicorn==19.9.0 diff --git a/tests/ci/setup.sh b/tests/ci/setup.sh index 01951d58d..eb888f58c 100755 --- a/tests/ci/setup.sh +++ b/tests/ci/setup.sh @@ -29,7 +29,7 @@ install_dependencies() { sudo add-apt-repository -y ppa:nginx/stable sudo apt-get update - sudo apt-get -qq -y install cgroupfs-mount dos2unix nginx + sudo apt-get -qq -y install cgroupfs-mount dos2unix jq nginx sudo cp "${ROOT_DIR}/tests/dhparam.pem" /etc/nginx/dhparam.pem sudo dpkg -i "${ROOT_DIR}/build/$HEROKUISH_PACKAGE_NAME" \ diff --git a/tests/unit/30_core_1.bats b/tests/unit/30_core_1.bats index edb22b6ce..26746d0eb 100644 --- a/tests/unit/30_core_1.bats +++ b/tests/unit/30_core_1.bats @@ -111,12 +111,17 @@ assert_urls() { @test "(core) run (detached)" { deploy_app - RANDOM_RUN_CID="$(dokku --detach run $TEST_APP sleep 300)" + RANDOM_RUN_CID="$(dokku --label=com.dokku.test-label=value --detach run $TEST_APP sleep 300)" run /bin/bash -c "docker inspect -f '{{ .State.Status }}' $RANDOM_RUN_CID" echo "output: $output" echo "status: $status" assert_output "running" + run /bin/bash -c "docker inspect $RANDOM_RUN_CID --format '{{ index .Config.Labels \"com.dokku.test-label\" }}'" + echo "output: $output" + echo "status: $status" + assert_output "value" + run /bin/bash -c "docker stop $RANDOM_RUN_CID" echo "output: $output" echo "status: $status" diff --git a/tests/unit/40_core_2.bats b/tests/unit/40_core_2.bats index ffd74ff6b..f237a56c5 100644 --- a/tests/unit/40_core_2.bats +++ b/tests/unit/40_core_2.bats @@ -31,6 +31,13 @@ assert_url() { assert_output "${url}" } +@test "(core) cleanup:help" { + run /bin/bash -c "dokku cleanup:help" + echo "output: $output" + echo "status: $status" + assert_output_contains "Cleans up exited/dead Docker containers and removes dangling image" +} + @test "(core) run (with --options)" { deploy_app run /bin/bash -c "dokku --force --quiet run $TEST_APP node --version" diff --git a/tests/unit/40_nginx-vhosts_3.bats b/tests/unit/40_nginx-vhosts_3.bats new file mode 100644 index 000000000..65e184986 --- /dev/null +++ b/tests/unit/40_nginx-vhosts_3.bats @@ -0,0 +1,41 @@ +#!/usr/bin/env bats + +load test_helper +source "$PLUGIN_CORE_AVAILABLE_PATH/config/functions" + +setup() { + global_setup + [[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak" + [[ -f "$DOKKU_ROOT/HOSTNAME" ]] && cp -fp "$DOKKU_ROOT/HOSTNAME" "$DOKKU_ROOT/HOSTNAME.bak" + create_app + docker build "${BATS_TEST_DIRNAME}/../../tests/apps/gogrpc" -t ${TEST_APP}-docker-image +} + +teardown() { + destroy_app 0 $TEST_APP + [[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST" + [[ -f "$DOKKU_ROOT/HOSTNAME.bak" ]] && mv "$DOKKU_ROOT/HOSTNAME.bak" "$DOKKU_ROOT/HOSTNAME" && chown dokku:dokku "$DOKKU_ROOT/HOSTNAME" + global_teardown +} + +@test "(nginx-vhosts) grpc endpoint" { + deploy_app gogrpc + dokku proxy:ports-add "$TEST_APP" "grpc:80:50051" + run /bin/bash -c "docker run --rm ${TEST_APP}-docker-image /go/bin/greeter_client -address ${TEST_APP}.dokku.me:80 -name grpc" + assert_output "Greeting: Hello grpc" +} + +@test "(nginx-vhosts) grpc endpoint on a port other than 80" { + deploy_app gogrpc + dokku proxy:ports-add "$TEST_APP" "grpc:8080:50051" + run /bin/bash -c "docker run --rm ${TEST_APP}-docker-image /go/bin/greeter_client -address ${TEST_APP}.dokku.me:8080 -name grpc8080" + assert_output "Greeting: Hello grpc8080" +} + +@test "(nginx-vhosts) grpcs endpoint" { + setup_test_tls + deploy_app gogrpc + dokku proxy:ports-add "$TEST_APP" "grpcs:443:50051" + run /bin/bash -c "docker run --rm ${TEST_APP}-docker-image /go/bin/greeter_client -address ${TEST_APP}.dokku.me:443 -name grpcs -tls" + assert_output "Greeting: Hello grpcs" +}