diff --git a/.dockerignore b/.dockerignore index 0ef019adc..c49b5c3b1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,3 +6,4 @@ contrib docs tests !contrib/dokku-installer.py +!contrib/dokku-update diff --git a/contrib/build.Dockerfile b/contrib/build.Dockerfile index bcfc2bbbd..98ca33291 100644 --- a/contrib/build.Dockerfile +++ b/contrib/build.Dockerfile @@ -36,8 +36,8 @@ RUN PLUGIN_MAKE_TARGET=${PLUGIN_MAKE_TARGET} \ SKIP_GO_CLEAN=true \ make version copyfiles \ && rm -rf plugins/common/*.go plugins/common/glide* plugins/common/vendor/ \ - && make deb-herokuish deb-dokku deb-plugn deb-sshcommand deb-sigil \ - rpm-herokuish rpm-dokku rpm-plugn rpm-sshcommand rpm-sigil + && make deb-herokuish deb-dokku deb-plugn deb-sshcommand deb-sigil deb-dokku-update \ + rpm-herokuish rpm-dokku rpm-plugn rpm-sshcommand rpm-sigil rpm-dokku-update RUN mkdir -p /data \ && cp /tmp/*.deb /data \ diff --git a/contrib/release-dokku-update b/contrib/release-dokku-update new file mode 100755 index 000000000..7babd2b4e --- /dev/null +++ b/contrib/release-dokku-update @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $TRACE ]] && set -x + +readonly ROOT_DIR="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)" +readonly TMP_WORK_DIR="$(mktemp -d "/tmp/dokku-release.XXXX")" +readonly DOKKU_GIT_REV="$(git rev-parse HEAD)" + +trap 'rm -rf "$TMP_WORK_DIR" > /dev/null' RETURN INT TERM EXIT + +log-info() { + # shellcheck disable=SC2034 + declare desc="Log info formatter" + echo "$*" +} + +log-error() { + # shellcheck disable=SC2034 + declare desc="Log error formatter" + echo "! $*" 1>&2 +} + +log-fail() { + # shellcheck disable=SC2034 + declare desc="Log fail formatter" + log-error "$*" + exit -1 +} + +fn-build-dokku() { + declare desc="Builds dokku packages within a docker container" + + pushd "$ROOT_DIR" >/dev/null + docker build \ + -f "contrib/update-build.Dockerfile" \ + -t dokku-update:build . + return "$?" +} + +fn-extract-package() { + declare desc="Extract packages from a docker container to the root directory" + declare PACKAGE_NAME="$1" + + if [[ -z "$PACKAGE_NAME" ]]; then + log-error "Invalid deb file specified" + return 1 + fi + + log-info "(extract-package) writing ${PACKAGE_NAME} to correct path" + docker run --rm --entrypoint cat dokku-update:build "/data/${PACKAGE_NAME}" > "${ROOT_DIR}/${PACKAGE_NAME}" + return "$?" +} + +fn-publish-package() { + declare desc="Publishes a package to packagecloud" + declare RELEASE="$1" RELEASE_TYPE="$2" PACKAGE_NAME="$3" + local REPOSITORY=dokku/dokku-betafish DIST=ubuntu/trusty + + [[ "$RELEASE" != "betafish" ]] && REPOSITORY=dokku/dokku + [[ "$RELEASE_TYPE" == "rpm" ]] && DIST=el/7 + log-info "(release-dokku) pushing ${RELEASE_TYPE} to packagecloud.com/${REPOSITORY}/${DIST}" + package_cloud push "${REPOSITORY}/${DIST}" "$PACKAGE_NAME" + return "$?" +} + +fn-in-array() { + declare desc="return true if value ($1) is in list (all other arguments)" + + local e + for e in "${@:2}"; do + [[ "$e" == "$1" ]] && return 0 + done + return 1 +} + +fn-require-bin() { + declare desc="Checks that a binary exists" + declare BINARY="$1" + if ! command -v "$BINARY" &>/dev/null; then + log-fail "Missing ${BINARY}, please install it" + fi +} + +main() { + declare RELEASE="$1" + local CURRENT_VERSION NEXT_VERSION major minor patch versions + local VALID_RELEASE_LEVELS=("major" "minor" "patch" "betafish") + + if [[ "$RELEASE" == '--trace' ]]; then + shift 1 + RELEASE="$1" + TRACE=1 && set -x + fi + + if [[ -z "$RELEASE" ]]; then + log-fail "Argument 1 must be one of [major, minor, patch, betafish], none given" + fi + + if ! fn-in-array "$RELEASE" "${VALID_RELEASE_LEVELS[@]}"; then + log-fail "Argument 1 must be one of [major, minor, patch, betafish], '${RELEASE}' given" + fi + + fn-require-bin "docker" + fn-require-bin "package_cloud" + [[ -n "$PACKAGECLOUD_API_TOKEN" ]] || log-fail "Missing PACKAGECLOUD_API_TOKEN environment variable" + + NEXT_VERSION="$(grep DOKKU_UPDATE_VERSION deb.mk | head -n1 | cut -d'=' -f2 | xargs)" + + fn-build-dokku || log-fail "Error building package" + + fn-extract-package "dokku-update_${NEXT_VERSION}_amd64.deb" || log-fail "Error extracting deb package" + + fn-extract-package "dokku-update-${NEXT_VERSION}-1.x86_64.rpm" || log-fail "Error extracting rpm package" + + fn-publish-package "$RELEASE" "deb" "dokku-update_${NEXT_VERSION}_amd64.deb" || log-fail "Error publishing deb package" + + fn-publish-package "$RELEASE" "rpm" "dokku-update-${NEXT_VERSION}-1.x86_64.rpm" || log-fail "Error publishing rpm package" + +} + +main "$@" diff --git a/contrib/update-build.Dockerfile b/contrib/update-build.Dockerfile new file mode 100644 index 000000000..fb7424860 --- /dev/null +++ b/contrib/update-build.Dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:14.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get -y install gcc git build-essential wget ruby-dev ruby1.9.1 lintian rpm help2man man-db +RUN command -v fpm > /dev/null || sudo gem install fpm --no-ri --no-rdoc + +ARG WORKDIR=/go/src/github.com/dokku/dokku + +WORKDIR ${WORKDIR} + +COPY . ${WORKDIR} + +RUN make deb-dokku-update rpm-dokku-update + +RUN mkdir -p /data \ + && cp /tmp/*.deb /data \ + && cp /tmp/*.rpm /data \ + && ls -lha /data/ diff --git a/deb.mk b/deb.mk index c1e73643c..0c6f0e7ac 100644 --- a/deb.mk +++ b/deb.mk @@ -8,6 +8,12 @@ DOKKU_DESCRIPTION = 'Docker powered PaaS that helps you build and manage the lif DOKKU_REPO_NAME ?= dokku/dokku DOKKU_ARCHITECTURE = amd64 +DOKKU_UPDATE_DESCRIPTION = 'Binary that handles updating Dokku and related systems' +DOKKU_UPDATE_REPO_NAME ?= dokku/dokku +DOKKU_UPDATE_VERSION ?= 0.1.0 +DOKKU_UPDATE_ARCHITECTURE = amd64 +DOKKU_UPDATE_PACKAGE_NAME = dokku-update_$(DOKKU_UPDATE_VERSION)_$(DOKKU_UPDATE_ARCHITECTURE).deb + define PLUGN_DESCRIPTION Hook system that lets users extend your application with plugins Plugin triggers are simply scripts that are executed by the system. @@ -52,7 +58,7 @@ export PLUGN_DESCRIPTION export SIGIL_DESCRIPTION export SSHCOMMAND_DESCRIPTION -.PHONY: install-from-deb deb-all deb-herokuish deb-dokku deb-plugn deb-setup deb-sshcommand deb-sigil +.PHONY: install-from-deb deb-all deb-herokuish deb-dokku deb-dokku-update deb-plugn deb-setup deb-sshcommand deb-sigil install-from-deb: @echo "--> Initial apt-get update" @@ -68,7 +74,7 @@ install-from-deb: sudo apt-get update -qq > /dev/null sudo DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true apt-get install -yy dokku -deb-all: deb-setup deb-herokuish deb-dokku deb-plugn deb-sshcommand deb-sigil +deb-all: deb-setup deb-herokuish deb-dokku deb-plugn deb-sshcommand deb-sigil deb-dokku-update mv /tmp/*.deb . @echo "Done" @@ -150,6 +156,21 @@ endif dpkg-deb --build /tmp/build "/tmp/dokku_`cat /tmp/build/var/lib/dokku/VERSION`_$(DOKKU_ARCHITECTURE).deb" lintian "/tmp/dokku_`cat /tmp/build/var/lib/dokku/VERSION`_$(DOKKU_ARCHITECTURE).deb" +deb-dokku-update: + rm -rf /tmp/dokku-update*.deb dokku-update*.deb + echo "${DOKKU_UPDATE_VERSION}" > contrib/dokku-update-version + sudo fpm -t deb -s dir -n dokku-update \ + --version $(DOKKU_UPDATE_VERSION) \ + --architecture $(DOKKU_UPDATE_ARCHITECTURE) \ + --package $(DOKKU_UPDATE_PACKAGE_NAME) \ + --depends 'dokku' \ + --url "https://github.com/$(DOKKU_UPDATE_REPO_NAME)" \ + --description $(DOKKU_UPDATE_DESCRIPTION) \ + --license 'MIT License' \ + contrib/dokku-update=/usr/local/bin/dokku-update \ + contrib/dokku-update-version=/var/lib/dokku-update/VERSION + mv *.deb /tmp + deb-plugn: rm -rf /tmp/tmp /tmp/build $(PLUGN_PACKAGE_NAME) mkdir -p /tmp/tmp /tmp/build /tmp/build/usr/bin diff --git a/debian/control b/debian/control index f3ee6d8aa..eee56e279 100644 --- a/debian/control +++ b/debian/control @@ -4,7 +4,7 @@ Section: web Priority: optional Architecture: amd64 Depends: locales, git, make, curl, gcc, man-db, netcat, sshcommand (>= 0.6.0), gliderlabs-sigil, docker-engine-cs (>= 1.9.1) | docker-engine (>= 1.9.1) | docker-io (>= 1.9.1) | docker-ce | docker-ee, software-properties-common, python-software-properties | python3-software-properties, rsyslog -Recommends: herokuish (>= 0.3.4), parallel +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 Maintainer: Jose Diaz-Gonzalez Description: Docker-powered PaaS that helps build and manage the lifecycle of applications diff --git a/docs/getting-started/upgrading.md b/docs/getting-started/upgrading.md index b6516a4e4..76998b794 100644 --- a/docs/getting-started/upgrading.md +++ b/docs/getting-started/upgrading.md @@ -4,7 +4,7 @@ If your version of Dokku is pre 0.3.0 (check with `dokku version`), we recommend ## Security Updates -For any security related updates, please follow our [twitter account](https://twitter.com/savant). As Dokku does not run any daemons, the security risk introduced by our software is minimal. +For any security related updates, please follow our [twitter account](https://twitter.com/dokku). As Dokku does not run any daemons, the security risk introduced by our software is minimal. Your operating system may occasionally provide security updates. We recommend setting unattended upgrades for your operating system. Here are some helpful links: @@ -13,7 +13,15 @@ Your operating system may occasionally provide security updates. We recommend se - [Debian Unattended Upgrades](https://wiki.debian.org/UnattendedUpgrades) - [Ubuntu Unattended Upgrades](https://help.ubuntu.com/community/AutomaticSecurityUpdates) -Finally, Docker releases updates periodically to their engine. We recommend reading their release notes and upgrading accordingly. Please see the [Docker documentation](https://docs.docker.com/) for more details. +Docker releases updates periodically to their engine. We recommend reading their release notes and upgrading accordingly. Please see the [Docker documentation](https://docs.docker.com/) for more details. + +Finally, we provide a helpful binary called `dokku-update`. This is a recommended package that: + +- Can be installed separately, so upgrading Dokku will not affect the running of this package. +- Automates many of the upgrade instructions for you. +- Provides a clean way for us to further enhance the upgrade process in the future. + +When installing from source, this is available from `contrib/dokku-update`, and is also available on Debian and RPM-based systems from our package repositories under the name `dokku-update`. ## Migration Guides diff --git a/rpm.mk b/rpm.mk index ea178a2eb..4226c0d59 100644 --- a/rpm.mk +++ b/rpm.mk @@ -1,4 +1,5 @@ RPM_ARCHITECTURE = x86_64 +DOKKU_UPDATE_RPM_PACKAGE_NAME = dokku-update-$(DOKKU_UPDATE_VERSION)-1.$(RPM_ARCHITECTURE).rpm HEROKUISH_RPM_PACKAGE_NAME = herokuish-$(HEROKUISH_VERSION)-1.$(RPM_ARCHITECTURE).rpm PLUGN_RPM_PACKAGE_NAME = plugn-$(PLUGN_VERSION)-1.$(RPM_ARCHITECTURE).rpm SSHCOMMAND_RPM_PACKAGE_NAME = sshcommand-$(SSHCOMMAND_VERSION)-1.$(RPM_ARCHITECTURE).rpm @@ -6,7 +7,7 @@ SIGIL_RPM_PACKAGE_NAME = gliderlabs-sigil-$(SIGIL_VERSION)-1.$(RPM_ARCHITECTURE) .PHONY: rpm-all -rpm-all: rpm-setup rpm-herokuish rpm-dokku rpm-plugn rpm-sshcommand rpm-sigil +rpm-all: rpm-setup rpm-herokuish rpm-dokku rpm-plugn rpm-sshcommand rpm-sigil rpm-dokku-update mv /tmp/*.rpm . @echo "Done" @@ -111,6 +112,21 @@ endif . mv *.rpm "/tmp/dokku-`cat /tmp/build/var/lib/dokku/VERSION`-1.$(RPM_ARCHITECTURE).rpm" +rpm-dokku-update: + rm -rf /tmp/dokku-update*.rpm dokku-update*.rpm + echo "${DOKKU_UPDATE_VERSION}" > contrib/dokku-update-version + sudo fpm -t rpm -s dir -n dokku-update \ + --version $(DOKKU_UPDATE_VERSION) \ + --architecture $(RPM_ARCHITECTURE) \ + --package $(DOKKU_UPDATE_RPM_PACKAGE_NAME) \ + --depends 'dokku' \ + --url "https://github.com/$(DOKKU_UPDATE_REPO_NAME)" \ + --description $(DOKKU_UPDATE_DESCRIPTION) \ + --license 'MIT License' \ + contrib/dokku-update=/usr/local/bin/dokku-update \ + contrib/dokku-update-version=/var/lib/dokku-update/VERSION + mv *.rpm /tmp + rpm-plugn: rm -rf /tmp/tmp /tmp/build $(PLUGN_RPM_PACKAGE_NAME) mkdir -p /tmp/tmp /tmp/build /tmp/build/usr/bin @@ -124,14 +140,14 @@ rpm-plugn: @echo "-> Creating $(PLUGN_RPM_PACKAGE_NAME)" sudo fpm -t rpm -s dir -C /tmp/build -n plugn \ - --version $(PLUGN_VERSION) \ - -a $(RPM_ARCHITECTURE) \ - --package $(PLUGN_RPM_PACKAGE_NAME) \ - --url "https://github.com/$(PLUGN_REPO_NAME)" \ - --category utils \ - --description "$$PLUGN_DESCRIPTION" \ - --license 'MIT License' \ - . + --version $(PLUGN_VERSION) \ + --architecture $(RPM_ARCHITECTURE) \ + --package $(PLUGN_RPM_PACKAGE_NAME) \ + --url "https://github.com/$(PLUGN_REPO_NAME)" \ + --category utils \ + --description "$$PLUGN_DESCRIPTION" \ + --license 'MIT License' \ + . mv *.rpm /tmp rpm-sshcommand: @@ -148,14 +164,14 @@ rpm-sshcommand: @echo "-> Creating $(SSHCOMMAND_RPM_PACKAGE_NAME)" sudo fpm -t rpm -s dir -C /tmp/build -n sshcommand \ - --version $(SSHCOMMAND_VERSION) \ - -a $(RPM_ARCHITECTURE) \ - --package $(SSHCOMMAND_RPM_PACKAGE_NAME) \ - --url "https://github.com/$(SSHCOMMAND_REPO_NAME)" \ - --category admin \ - --description "$$SSHCOMMAND_DESCRIPTION" \ - --license 'MIT License' \ - . + --version $(SSHCOMMAND_VERSION) \ + -a $(RPM_ARCHITECTURE) \ + --package $(SSHCOMMAND_RPM_PACKAGE_NAME) \ + --url "https://github.com/$(SSHCOMMAND_REPO_NAME)" \ + --category admin \ + --description "$$SSHCOMMAND_DESCRIPTION" \ + --license 'MIT License' \ + . mv *.rpm /tmp rpm-sigil: