provisioners: Import Docker provisioner code from Vocker

This commit is contained in:
Fabio Rehm 2013-11-26 19:48:51 -02:00
parent cfb258a55b
commit 0536817e90
11 changed files with 367 additions and 0 deletions

View File

@ -0,0 +1,15 @@
module VagrantPlugins
module Docker
module Cap
module Debian
module DockerConfigureAutoStart
def self.docker_configure_auto_start(machine)
if ! machine.communicate.test('grep -q \'\-r=true\' /etc/init/docker.conf')
machine.communicate.sudo("sed -i.bak 's/docker -d/docker -d -r=true/' /etc/init/docker.conf ")
end
end
end
end
end
end
end

View File

@ -0,0 +1,13 @@
module VagrantPlugins
module Docker
module Cap
module Debian
module DockerConfigureVagrantUser
def self.docker_configure_vagrant_user(machine)
machine.communicate.sudo("usermod -a -G docker #{machine.config.ssh.username || "vagrant"}")
end
end
end
end
end
end

View File

@ -0,0 +1,26 @@
module VagrantPlugins
module Docker
module Cap
module Debian
module DockerInstall
def self.docker_install(machine, version)
package = 'lxc-docker'
package << "-#{version}" if version != :latest
machine.communicate.tap do |comm|
# TODO: Perform check on the host machine if aufs is installed and using LXC
if machine.provider_name != :lxc
comm.sudo("lsmod | grep aufs || modprobe aufs || apt-get install -y linux-image-extra-`uname -r`")
end
comm.sudo("apt-get install -y --force-yes -q curl")
comm.sudo("curl http://get.docker.io/gpg | apt-key add -")
comm.sudo("echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list")
comm.sudo("apt-get update")
comm.sudo("apt-get install -y --force-yes -q xz-utils #{package} -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'")
end
end
end
end
end
end
end

View File

@ -0,0 +1,13 @@
module VagrantPlugins
module Docker
module Cap
module Debian
module DockerStartService
def self.docker_start_service(machine)
machine.communicate.sudo("service docker start")
end
end
end
end
end
end

View File

@ -0,0 +1,13 @@
module VagrantPlugins
module Docker
module Cap
module Linux
module DockerInstalled
def self.docker_installed(machine)
machine.communicate.test("test -f /usr/bin/docker", sudo: true)
end
end
end
end
end
end

View File

@ -0,0 +1,44 @@
require 'set'
module VagrantPlugins
module Docker
class Config < Vagrant.plugin("2", :config)
attr_reader :images, :containers
attr_accessor :version
def initialize
@images = Set.new
@containers = Hash.new
@version = :latest
end
def pull_images(*images)
@images += images.map(&:to_s)
end
def run(*args)
container_name = args.shift
params = {}
if args.empty?
params[:image] = container_name
elsif args.first.is_a?(String)
params[:image] = args.shift
params[:cmd] = container_name
else
params = args.shift
params[:cmd] ||= container_name
end
# TODO: Validate provided parameters before assignment
@containers[container_name.to_s] = params
end
def merge(other)
super.tap do |result|
result.pull_images *(other.images + self.images)
end
end
end
end
end

View File

@ -0,0 +1,102 @@
require 'digest/sha1'
module VagrantPlugins
module Docker
class DockerClient
def initialize(machine)
@machine = machine
end
def pull_images(*images)
@machine.communicate.tap do |comm|
images.each do |image|
comm.sudo("docker images | grep -q #{image} || docker pull #{image}")
end
end
end
def start_service
if !daemon_running? && @machine.guest.capability?(:docker_start_service)
@machine.guest.capability(:docker_start_service)
end
end
def daemon_running?
@machine.communicate.test('test -f /var/run/docker.pid')
end
def run(containers)
containers.each do |name, config|
cids_dir = "/var/lib/vocker/cids"
config[:cidfile] ||= "#{cids_dir}/#{Digest::SHA1.hexdigest name}"
@machine.communicate.sudo("mkdir -p #{cids_dir}")
run_container({name: name}.merge config)
end
end
def run_container(config)
raise "Container's cidfile was not provided!" unless config[:cidfile]
id = "$(cat #{config[:cidfile]})"
if container_exist?(id)
start_container(id)
else
create_container(config)
end
end
def container_exist?(id)
@machine.communicate.test("sudo docker ps -a -q | grep -q #{id}")
end
def start_container(id)
unless container_running?(id)
@machine.communicate.sudo("docker start #{id}")
end
end
def container_running?(id)
@machine.communicate.test("sudo docker ps -q | grep #{id}")
end
def create_container(config)
# DISCUSS: Does this really belong here?
ensure_bind_mounts_exist(config)
args = "-cidfile=#{config[:cidfile]} -d "
args << prepare_run_arguments(config)
@machine.communicate.sudo %[
rm -f #{config[:cidfile]}
docker run #{args} #{config[:image]} #{config[:cmd]}
]
end
private
def ensure_bind_mounts_exist(config)
Array(config[:volumes]).each do |volume|
if volume =~ /(.+):.+/
guest_vm_path = $1
@machine.communicate.sudo "mkdir -p #{guest_vm_path}"
end
end
end
def prepare_run_arguments(config)
args = []
args << "-dns=#{config[:dns]}" if config[:dns]
args << "-name=#{config[:name]}" if config[:name]
args << "#{config[:additional_run_args]}" if config[:additional_run_args]
args += Array(config[:volumes]).map { |volume| "-v #{volume}" }
args += Array(config[:ports]).map { |port| "-p #{port}" }
args += Array(config[:links]).map { |link| "-link #{link}" }
args.compact.flatten.join ' '
end
end
end
end

View File

@ -0,0 +1,41 @@
require_relative "errors"
module VagrantPlugins
module Docker
class DockerInstaller
def initialize(machine, version)
@machine = machine
@version = version
end
# This handles verifying the Docker installation, installing it if it was
# requested, and so on. This method will raise exceptions if things are
# wrong.
def ensure_installed
if !@machine.guest.capability?(:docker_installed)
@machine.ui.warn(I18n.t("vagrant.docker_cant_detect"))
return
end
if !@machine.guest.capability(:docker_installed)
@machine.ui.info(I18n.t("vagrant.docker_installing"))
@machine.guest.capability(:docker_install, @version)
if !@machine.guest.capability(:docker_installed)
raise Errors::DockerInstallFailed
end
end
if @machine.guest.capability?(:docker_configure_auto_start)
@machine.guest.capability(:docker_configure_auto_start)
else
@machine.env.ui.warn I18n.t('vagrant.docker_auto_start_not_available')
end
if @machine.guest.capability?(:docker_configure_vagrant_user)
@machine.guest.capability(:docker_configure_vagrant_user)
end
end
end
end
end

View File

@ -0,0 +1,11 @@
module VagrantPlugins
module Docker
module Errors
class DockerInstallFailed < ::Vagrant::Errors::VagrantError
end
class DockerNotRunning < ::Vagrant::Errors::VagrantError
end
end
end
end

View File

@ -0,0 +1,48 @@
require "vagrant"
module VagrantPlugins
module Docker
class Plugin < Vagrant.plugin("2")
name "docker"
description <<-DESC
Provides support for provisioning your virtual machines with
Docker images and containers.
DESC
config(:docker, :provisioner) do
require_relative "config"
Config
end
guest_capability("debian", "docker_install") do
require_relative "cap/debian/docker_install"
Cap::Debian::DockerInstall
end
guest_capability("debian", "docker_configure_auto_start") do
require_relative "cap/debian/docker_configure_auto_start"
Cap::Debian::DockerConfigureAutoStart
end
guest_capability("debian", "docker_configure_vagrant_user") do
require_relative "cap/debian/docker_configure_vagrant_user"
Cap::Debian::DockerConfigureVagrantUser
end
guest_capability("debian", "docker_start_service") do
require_relative "cap/debian/docker_start_service"
Cap::Debian::DockerStartService
end
guest_capability("linux", "docker_installed") do
require_relative "cap/linux/docker_installed"
Cap::Linux::DockerInstalled
end
provisioner(:docker) do
require_relative "provisioner"
Provisioner
end
end
end
end

View File

@ -0,0 +1,41 @@
require_relative "errors"
require_relative "docker_client"
require_relative "docker_installer"
module VagrantPlugins
module Docker
# TODO: Improve handling of vagrant-lxc specifics (like checking for apparmor
# profile stuff + autocorrection)
class Provisioner < Vagrant.plugin("2", :provisioner)
def initialize(machine, config, installer = nil, client = nil)
super(machine, config)
# TODO: Rename to installer / client (drop docker suffix)
@installer = installer || DockerInstaller.new(@machine, config.version)
@client = client || DockerClient.new(@machine)
end
def provision
@logger = Log4r::Logger.new("vagrant::provisioners::vocker")
@logger.info("Checking for Docker installation...")
@installer.ensure_installed
# Attempt to start service if not running
@client.start_service
unless @client.daemon_running?
raise Errors::DockerNotRunning
end
if config.images.any?
@machine.ui.info(I18n.t("vagrant.docker_pulling_images"))
@client.pull_images(*config.images)
end
if config.containers.any?
@machine.ui.info(I18n.t("vagrant.docker_starting_containers"))
@client.run(config.containers)
end
end
end
end
end