diff --git a/bootstrapvz/plugins/docker_daemon/__init__.py b/bootstrapvz/plugins/docker_daemon/__init__.py new file mode 100644 index 0000000..c952878 --- /dev/null +++ b/bootstrapvz/plugins/docker_daemon/__init__.py @@ -0,0 +1,23 @@ +import tasks +import os.path +from bootstrapvz.common.exceptions import ManifestError + + +def validate_manifest(data, validator, error): + schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.json')) + try: + validator(data, schema_path) + except ManifestError, e: + error('docker_daemon manifest validation failed: "%s"' % e.message, e.json_path) + if data.get('system', {}).get('release', None) in ['wheezy', 'stable']: + # prefs is a generator of apt preferences across files in the manifest + prefs = (item for vals in data.get('packages', {}).get('preferences', {}).values() for item in vals) + if not any('linux-image' in item['package'] and 'wheezy-backports' in item['pin'] for item in prefs): + msg = 'The backports kernel is required for the docker daemon to function properly' + error(msg, ['packages', 'preferences']) + + +def resolve_tasks(taskset, manifest): + taskset.add(tasks.AddDockerDeps) + taskset.add(tasks.AddDockerBinary) + taskset.add(tasks.AddDockerInit) diff --git a/bootstrapvz/plugins/docker_daemon/assets/default/docker b/bootstrapvz/plugins/docker_daemon/assets/default/docker new file mode 100644 index 0000000..14e6601 --- /dev/null +++ b/bootstrapvz/plugins/docker_daemon/assets/default/docker @@ -0,0 +1,13 @@ +# Docker Upstart and SysVinit configuration file + +# Customize location of Docker binary (especially for development testing). +#DOCKER="/usr/local/bin/docker" + +# Use DOCKER_OPTS to modify the daemon startup options. +#DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" + +# If you need Docker to use an HTTP proxy, it can also be specified here. +#export http_proxy="http://127.0.0.1:3128/" + +# This is also a handy place to tweak where Docker's temporary files go. +#export TMPDIR="/mnt/bigdrive/docker-tmp" diff --git a/bootstrapvz/plugins/docker_daemon/assets/init.d/docker b/bootstrapvz/plugins/docker_daemon/assets/init.d/docker new file mode 100644 index 0000000..67f0d28 --- /dev/null +++ b/bootstrapvz/plugins/docker_daemon/assets/init.d/docker @@ -0,0 +1,129 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: docker +# Required-Start: $syslog $remote_fs +# Required-Stop: $syslog $remote_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Create lightweight, portable, self-sufficient containers. +# Description: +# Docker is an open-source project to easily create lightweight, portable, +# self-sufficient containers from any application. The same container that a +# developer builds and tests on a laptop can run at scale, in production, on +# VMs, bare metal, OpenStack clusters, public clouds and more. +### END INIT INFO + +export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin + +BASE=$(basename $0) + +# modify these in /etc/default/$BASE (/etc/default/docker) +DOCKER=/usr/bin/$BASE +DOCKER_PIDFILE=/var/run/$BASE.pid +DOCKER_LOGFILE=/var/log/$BASE.log +DOCKER_OPTS= +DOCKER_DESC="Docker" + +# Get lsb functions +. /lib/lsb/init-functions + +if [ -f /etc/default/$BASE ]; then + . /etc/default/$BASE +fi + +# see also init_is_upstart in /lib/lsb/init-functions (which isn't available in Ubuntu 12.04, or we'd use it) +if [ -x /sbin/initctl ] && /sbin/initctl version 2>/dev/null | grep -q upstart; then + log_failure_msg "$DOCKER_DESC is managed via upstart, try using service $BASE $1" + exit 1 +fi + +# Check docker is present +if [ ! -x $DOCKER ]; then + log_failure_msg "$DOCKER not present or not executable" + exit 1 +fi + +fail_unless_root() { + if [ "$(id -u)" != '0' ]; then + log_failure_msg "$DOCKER_DESC must be run as root" + exit 1 + fi +} + +cgroupfs_mount() { + # see also https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount + if grep -v '^#' /etc/fstab | grep -q cgroup \ + || [ ! -e /proc/cgroups ] \ + || [ ! -d /sys/fs/cgroup ]; then + return + fi + if ! mountpoint -q /sys/fs/cgroup; then + mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup + fi + ( + cd /sys/fs/cgroup + for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do + mkdir -p $sys + if ! mountpoint -q $sys; then + if ! mount -n -t cgroup -o $sys cgroup $sys; then + rmdir $sys || true + fi + fi + done + ) +} + +case "$1" in + start) + fail_unless_root + + cgroupfs_mount + + touch "$DOCKER_LOGFILE" + chgrp docker "$DOCKER_LOGFILE" + + log_begin_msg "Starting $DOCKER_DESC: $BASE" + start-stop-daemon --start --background \ + --no-close \ + --exec "$DOCKER" \ + --pidfile "$DOCKER_PIDFILE" \ + -- \ + -d -p "$DOCKER_PIDFILE" \ + $DOCKER_OPTS \ + >> "$DOCKER_LOGFILE" 2>&1 + log_end_msg $? + ;; + + stop) + fail_unless_root + log_begin_msg "Stopping $DOCKER_DESC: $BASE" + start-stop-daemon --stop --pidfile "$DOCKER_PIDFILE" + log_end_msg $? + ;; + + restart) + fail_unless_root + docker_pid=`cat "$DOCKER_PIDFILE" 2>/dev/null` + [ -n "$docker_pid" ] \ + && ps -p $docker_pid > /dev/null 2>&1 \ + && $0 stop + $0 start + ;; + + force-reload) + fail_unless_root + $0 restart + ;; + + status) + status_of_proc -p "$DOCKER_PIDFILE" "$DOCKER" docker + ;; + + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/bootstrapvz/plugins/docker_daemon/manifest-schema.json b/bootstrapvz/plugins/docker_daemon/manifest-schema.json new file mode 100644 index 0000000..365ccfa --- /dev/null +++ b/bootstrapvz/plugins/docker_daemon/manifest-schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Install Docker plugin manifest", + "type": "object", + "properties": { + "system": { + "type": "object", + "properties": { + "architecture": { + "type": "string", + "enum": ["amd64"] + // Docker runs on x86_64 only + }, + "release": { + "not": { + "type": "string", + "enum": ["squeeze", "oldstable"] + // Docker needs at least wheezy + backports. + } + } + } + } + } +} diff --git a/bootstrapvz/plugins/docker_daemon/tasks.py b/bootstrapvz/plugins/docker_daemon/tasks.py new file mode 100644 index 0000000..b2b1bbe --- /dev/null +++ b/bootstrapvz/plugins/docker_daemon/tasks.py @@ -0,0 +1,47 @@ +from bootstrapvz.base import Task +from bootstrapvz.common import phases +from bootstrapvz.common.tasks import initd +import os +import os.path +import shutil + +ASSETS_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), 'assets')) + + +class AddDockerDeps(Task): + description = 'Add packages for docker deps' + phase = phases.package_installation + DOCKER_DEPS = ['aufs-tools', 'btrfs-tools', 'git', 'iptables', + 'procps', 'xz-utils', 'ca-certificates'] + + @classmethod + def run(cls, info): + for pkg in cls.DOCKER_DEPS: + info.packages.add(pkg) + + +class AddDockerBinary(Task): + description = 'Add docker binary' + phase = phases.system_modification + DOCKER_URL = 'https://get.docker.io/builds/Linux/x86_64/docker-latest' + + @classmethod + def run(cls, info): + import urllib + bin_docker = os.path.join(info.root, 'usr/bin/docker') + urllib.urlretrieve(cls.DOCKER_URL, bin_docker) + os.chmod(bin_docker, 0755) + + +class AddDockerInit(Task): + description = 'Add docker init script' + phase = phases.system_modification + successors = [initd.InstallInitScripts] + + @classmethod + def run(cls, info): + init_src = os.path.join(ASSETS_DIR, 'init.d/docker') + info.initd['install']['docker'] = init_src + default_src = os.path.join(ASSETS_DIR, 'default/docker') + default_dest = os.path.join(info.root, 'etc/default/docker') + shutil.copy(default_src, default_dest)