vocker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 834fa1d18bf8e23e1faa503aa702833f1bcd4b31
4
+ data.tar.gz: bb7ab7702c172a3288187936928e449a35f0e22a
5
+ SHA512:
6
+ metadata.gz: 7ff4f1feb914ce2a7c664a4773b7459adcdbb5b0a5db8b7758542a3f63281344c1358d2c99c2e1bea44fc525a19edee2d63c23826e4dc474ba8d5179900aed74
7
+ data.tar.gz: 1016810d2ea2364b09b245bfc2ac260fb3ca705b01a82b7ed9792b29834bca931398b47fc6adf4f041bf34ee79a25425284a5cde3e19fc3a4ace90bfd2b38b5f
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ development/.vagrant/
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in vagrant-docker-provisioner.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'vagrant', github: 'mitchellh/vagrant'
8
+ gem 'vagrant-lxc'
9
+ gem 'vagrant-cachier'
10
+ gem 'vagrant-pristine'
11
+ gem 'vagrant-global-status'
12
+
13
+ gem 'rspec'
14
+ gem 'simplecov', require: false
15
+ gem 'bogus'
16
+ gem 'guard-rspec'
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,96 @@
1
+ GIT
2
+ remote: git://github.com/mitchellh/vagrant.git
3
+ revision: e34cdbf86dca4a02f528b52d02cc10ca1c7682c3
4
+ specs:
5
+ vagrant (1.2.8.dev)
6
+ childprocess (~> 0.3.7)
7
+ erubis (~> 2.7.0)
8
+ i18n (~> 0.6.0)
9
+ log4r (~> 1.1.9)
10
+ net-scp (~> 1.1.0)
11
+ net-ssh (~> 2.6.6)
12
+
13
+ PATH
14
+ remote: .
15
+ specs:
16
+ vocker (0.1.0)
17
+
18
+ GEM
19
+ remote: https://rubygems.org/
20
+ specs:
21
+ bogus (0.1.4)
22
+ dependor (>= 0.0.4)
23
+ childprocess (0.3.9)
24
+ ffi (~> 1.0, >= 1.0.11)
25
+ coderay (1.0.9)
26
+ dependor (0.0.6)
27
+ diff-lcs (1.2.4)
28
+ erubis (2.7.0)
29
+ ffi (1.9.0)
30
+ formatador (0.2.4)
31
+ guard (1.8.1)
32
+ formatador (>= 0.2.4)
33
+ listen (>= 1.0.0)
34
+ lumberjack (>= 1.0.2)
35
+ pry (>= 0.9.10)
36
+ thor (>= 0.14.6)
37
+ guard-rspec (3.0.2)
38
+ guard (>= 1.8)
39
+ rspec (~> 2.13)
40
+ i18n (0.6.4)
41
+ listen (1.2.2)
42
+ rb-fsevent (>= 0.9.3)
43
+ rb-inotify (>= 0.9)
44
+ rb-kqueue (>= 0.2)
45
+ log4r (1.1.10)
46
+ lumberjack (1.0.4)
47
+ method_source (0.8.2)
48
+ multi_json (1.7.7)
49
+ net-scp (1.1.2)
50
+ net-ssh (>= 2.6.5)
51
+ net-ssh (2.6.8)
52
+ pry (0.9.12.2)
53
+ coderay (~> 1.0.5)
54
+ method_source (~> 0.8)
55
+ slop (~> 3.4)
56
+ rake (10.1.0)
57
+ rb-fsevent (0.9.3)
58
+ rb-inotify (0.9.0)
59
+ ffi (>= 0.5.0)
60
+ rb-kqueue (0.2.0)
61
+ ffi (>= 0.5.0)
62
+ rspec (2.14.1)
63
+ rspec-core (~> 2.14.0)
64
+ rspec-expectations (~> 2.14.0)
65
+ rspec-mocks (~> 2.14.0)
66
+ rspec-core (2.14.4)
67
+ rspec-expectations (2.14.1)
68
+ diff-lcs (>= 1.1.3, < 2.0)
69
+ rspec-mocks (2.14.3)
70
+ simplecov (0.7.1)
71
+ multi_json (~> 1.0)
72
+ simplecov-html (~> 0.7.1)
73
+ simplecov-html (0.7.1)
74
+ slop (3.4.6)
75
+ thor (0.18.1)
76
+ vagrant-cachier (0.3.0)
77
+ vagrant-global-status (0.1.0)
78
+ vagrant-lxc (0.5.0)
79
+ vagrant-pristine (0.2.0)
80
+
81
+ PLATFORMS
82
+ ruby
83
+
84
+ DEPENDENCIES
85
+ bogus
86
+ bundler (~> 1.3)
87
+ guard-rspec
88
+ rake
89
+ rspec
90
+ simplecov
91
+ vagrant!
92
+ vagrant-cachier
93
+ vagrant-global-status
94
+ vagrant-lxc
95
+ vagrant-pristine
96
+ vocker!
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/vocker/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Fabio Rehm
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # Vocker
2
+
3
+ An experimental plugin that introduces [Docker](http://docker.io) to [Vagrant](http://www.vagrantup.com/)
4
+ as a [provisioner](http://docs.vagrantup.com/v2/plugins/provisioners.html) and
5
+ as a command that allows you to interact with the guest machine Docker
6
+ installation. It can also be used for building other Vagrant plugins that
7
+ needs interaction with a Docker instance.
8
+
9
+
10
+ ## Installation
11
+
12
+ Make sure you have Vagrant 1.2+ and run:
13
+
14
+ ```
15
+ vagrant plugin install vocker
16
+ ```
17
+
18
+
19
+ ## Features
20
+
21
+ * Automatically installs Docker on guest machines
22
+ * Adds a command to interact with guest's Docker from the host machine
23
+ * Allows you to provision VMs with Docker images / containers from within your `Vagrantfile`
24
+ * Can be used to build other plugins (and I'm currently working on one :)
25
+
26
+
27
+ ## Status
28
+
29
+ Early development. It can be useful for trying out Docker and it's growing "ecossystem"
30
+ but the feature set and configuration format might change rapidly.
31
+
32
+ Apart from that I've only used the plugin on the following Ubuntu 13.04 VMs:
33
+
34
+ * http://cloud-images.ubuntu.com/vagrant/raring/current/raring-server-cloudimg-amd64-vagrant-disk1.box
35
+ * http://bit.ly/vagrant-lxc-raring64-2013-07-12 (yes! LXC inception :)
36
+
37
+ _Please note that in order to use the plugin on [vagrant-lxc](https://github.com/fgrehm/vagrant-lxc)
38
+ containers you need some extra steps described below_
39
+
40
+
41
+ ## Usage
42
+
43
+ Currently Vocker can be used in three different ways: as a provisioner, as a command
44
+ and as a foundation for other Vagrant plugins.
45
+
46
+ ### Provisioner
47
+
48
+ On the same spirit as the undocumented [CFEngine](https://github.com/mitchellh/vagrant/tree/master/plugins/provisioners/cfengine)
49
+ provisioner, this plugin will automatically [install](https://github.com/fgrehm/vocker/blob/master/lib/vocker/cap/debian/docker_install.rb)
50
+ Docker on Guest machines if you specify the provisioner on your `Vagrantfile`
51
+ like:
52
+
53
+ ```ruby
54
+ Vagrant.configure("2") do |config|
55
+ config.vm.box = 'your-box'
56
+ config.vm.provision :docker
57
+ end
58
+ ```
59
+
60
+ _Please note that only Ubuntu / Debian guests are currently capable of automatic
61
+ Docker installation. For usage on other guests you'll need to manually install it
62
+ prior to use this plugin._
63
+
64
+ You can also use the provisioner block to specify images to be pulled and / or
65
+ containers to run:
66
+
67
+ ```ruby
68
+ Vagrant.configure("2") do |config|
69
+ config.vm.provision :docker do |docker|
70
+ docker.pull_images 'ubuntu', 'busybox'
71
+
72
+ # Command + image
73
+ docker.run 'echo ls -la --color', 'ubuntu'
74
+
75
+ # Unique container name + other configs
76
+ docker.run 'date', image: 'ubuntu', cmd: '/bin/sh -c "while true; date; do echo hello world; sleep 1; done"'
77
+
78
+ # Base image (requires ENTRYPOINT / CMD) to be configured:
79
+ # * http://docs.docker.io/en/latest/use/builder/#entrypoint
80
+ # * http://docs.docker.io/en/latest/use/builder/#cmd
81
+ docker.run 'mysql'
82
+ end
83
+ end
84
+ ```
85
+
86
+ The provisioner will also ensure that a single instance of the container is
87
+ running at a time and you can run `vagrant provision` as many times as you want
88
+ without leaving lots of unused containers behind. If you are interested on
89
+ understanding how it works, have a look at [_DockerClient#run_](https://github.com/fgrehm/vocker/blob/master/lib/vocker/docker_client.rb#L22)
90
+
91
+
92
+ ### `vagrant docker` command
93
+
94
+ The command is basically a wrapper over `vagrant ssh -c` that allows you
95
+ to run `docker` commands on the guest VM:
96
+
97
+ ```
98
+ Usage: vagrant docker [vm-name] COMMAND [ARGS]
99
+
100
+ COMMAND can be any of attach, build, commit, diff, events, export, history,
101
+ images, import, info, insert, inspect, kill, login, logs, port, top, ps,
102
+ pull, push, restart, rm, rmi, run, search, start, stop, tag, version, wait
103
+
104
+ -h, --help Print this help
105
+ ```
106
+
107
+
108
+ ### _your-awesome-vagrant-plugin™_
109
+
110
+ In case you want to build a Vagrant plugin that needs to interact with Docker you
111
+ can add this plugin as a dependency and use [DockerClient](lib/vocker/docker_client.rb)
112
+ / [DockerInstaller](lib/vocker/docker_installer.rb) classes. An example of usage
113
+ will be provided _"soon"_.
114
+
115
+
116
+ ### Usage with [vagrant-lxc](https://github.com/fgrehm/vagrant-lxc)
117
+
118
+ If you are on a Linux machine, you can use vagrant-lxc to avoid messing up with
119
+ your working environment. While developing this plugin I was able to recreate
120
+ containers that were capable of using Docker without issues multiple times on
121
+ an up to date Ubuntu 13.04 host and guest.
122
+
123
+ In order to allow a vagrant-lxc container to boot nested Docker containers you'll
124
+ just need to `apt-get install apparmor-utils && aa-complain /usr/bin/lxc-start`
125
+ and add the code below to your Vagrantfile:
126
+
127
+ ```ruby
128
+ Vagrant.configure("2") do |config|
129
+ config.vm.provider :lxc do |lxc|
130
+ lxc.customize 'aa_profile', 'unconfined'
131
+ end
132
+
133
+ config.vm.provision :shell, inline: %[
134
+ if ! [ -f /etc/default/lxc ]; then
135
+ cat <<STR > /etc/default/lxc
136
+ LXC_AUTO="true"
137
+ USE_LXC_BRIDGE="true"
138
+ LXC_BRIDGE="lxcbr0"
139
+ LXC_ADDR="10.0.253.1"
140
+ LXC_NETMASK="255.255.255.0"
141
+ LXC_NETWORK="10.0.253.0/24"
142
+ LXC_DHCP_RANGE="10.0.253.2,10.0.253.254"
143
+ LXC_DHCP_MAX="253"
144
+ LXC_SHUTDOWN_TIMEOUT=120
145
+ STR
146
+ fi
147
+ ]
148
+ end
149
+ ```
150
+
151
+ The LXC networking configs are only required if you are on an Ubuntu host as
152
+ it automatically creates the `lxcbr0` bridge for you on the host machine and
153
+ if you don't do that the vagrant-lxc container will end up crashing as it
154
+ will collide with the host's `lxcbr0`.
155
+
156
+
157
+ ## Contributing
158
+
159
+ 1. Fork it
160
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
161
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
162
+ 4. Push to the branch (`git push origin my-new-feature`)
163
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ Dir['./tasks/**/*.rake'].each { |f| load f }
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,51 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ Vagrant.require_plugin 'vagrant-lxc'
5
+ Vagrant.require_plugin 'vagrant-cachier'
6
+ Vagrant.require_plugin 'vagrant-pristine'
7
+ Vagrant.require_plugin 'vagrant-global-status'
8
+ Vagrant.require_plugin 'vocker'
9
+
10
+ Vagrant.configure("2") do |config|
11
+ config.vm.box = "raring64"
12
+ config.vm.synced_folder "../", "/vagrant", id: 'vagrant-root'#, nfs: true
13
+ config.vm.synced_folder "~/projetos/oss/ventriloquist", "/home/vagrant/ventriloquist"
14
+ config.vm.network :private_network, ip: "192.168.123.123"
15
+
16
+ config.cache.auto_detect = true
17
+
18
+ config.vm.provider :lxc do |lxc|
19
+ # Required to boot nested containers
20
+ lxc.customize 'aa_profile', 'unconfined'
21
+ end
22
+
23
+ config.vm.provision :shell, inline: %[
24
+ if ! [ -f /etc/default/lxc ]; then
25
+ cat <<STR > /etc/default/lxc
26
+ LXC_AUTO="true"
27
+ USE_LXC_BRIDGE="true"
28
+ LXC_BRIDGE="lxcbr0"
29
+ LXC_ADDR="10.0.253.1"
30
+ LXC_NETMASK="255.255.255.0"
31
+ LXC_NETWORK="10.0.253.0/24"
32
+ LXC_DHCP_RANGE="10.0.253.2,10.0.253.254"
33
+ LXC_DHCP_MAX="253"
34
+ LXC_SHUTDOWN_TIMEOUT=120
35
+ STR
36
+ fi
37
+ ]
38
+
39
+ config.vm.define :vm1 do |vm1|
40
+ vm1.vm.provision :docker do |docker|
41
+ docker.pull_images 'ubuntu', 'busybox'
42
+ docker.run 'echo ls -la --color', 'ubuntu'
43
+ docker.run 'echo ls -la --color', image: 'ubuntu' # Above is the default
44
+ docker.run 'date', image: 'ubuntu', cmd: '/bin/sh -c "while true; date; do echo hello world; sleep 1; done"'
45
+ end
46
+ end
47
+
48
+ config.vm.define :vm2 do |vm2|
49
+ vm2.vm.provision :docker
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ module VagrantPlugins
2
+ module Vocker
3
+ module Cap
4
+ module Debian
5
+ module DockerInstall
6
+ def self.docker_install(machine)
7
+ # Inspired on https://github.com/progrium/dokku/blob/master/Makefile#L33-L40
8
+ machine.communicate.tap do |comm|
9
+ # TODO: Try to not depend on installing software-properties-common
10
+ comm.sudo("apt-get install -y -q software-properties-common")
11
+ comm.sudo("apt-add-repository -y ppa:dotcloud/lxc-docker")
12
+ comm.sudo("apt-get update")
13
+ comm.sudo("apt-get install -y -q xz-utils lxc-docker -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold'")
14
+ # TODO: Error out if provider is lxc
15
+ # comm.sudo("lsmod | grep aufs || modprobe aufs || apt-get install -y linux-image-extra-`uname -r`")
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module VagrantPlugins
2
+ module Vocker
3
+ module Cap
4
+ module Linux
5
+ module DockerInstalled
6
+ def self.docker_installed(machine)
7
+ machine.communicate.test("test -d /var/lib/docker", sudo: true)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ module VagrantPlugins
2
+ module Vocker
3
+ class Command < Vagrant.plugin("2", :command)
4
+ DOCKER_COMMANDS = %w(
5
+ attach build commit diff events export history images import info
6
+ insert inspect kill login logs port top ps pull push restart rm
7
+ rmi run search start stop tag version wait
8
+ )
9
+ def execute
10
+ opts = OptionParser.new do |o|
11
+ o.banner = "Usage: vagrant docker [vm-name] COMMAND [ARGS]"
12
+ o.separator ""
13
+ o.separator "COMMAND can be any of #{DOCKER_COMMANDS.join(', ')}"
14
+ o.separator ""
15
+ end
16
+
17
+ # Parse out docker commands
18
+ options = {}
19
+ command_index = @argv.index{|cmd| DOCKER_COMMANDS.include? cmd}
20
+ if command_index
21
+ options[:command] = @argv.drop(command_index)
22
+ @argv = @argv.take(command_index)
23
+ end
24
+
25
+ # Parse the options and return if we don't have any target.
26
+ argv = parse_options(opts)
27
+ return if !argv
28
+
29
+ # Execute the actual Docker command
30
+ # TODO: Make it work with multiple VMs
31
+ with_target_vms(argv, :single_target => true) do |vm|
32
+ # FIXME: - Check if docker is running first
33
+ # - Handle empty command
34
+
35
+ @logger.debug("Executing docker command on remote machine: #{options[:command]}")
36
+ env = vm.action(:ssh_run, :ssh_run_command => "sudo docker #{options[:command].join(' ')}")
37
+
38
+ # Exit with the exit status of the command or a 0 if we didn't
39
+ # get one.
40
+ exit_status = env[:ssh_run_exit_status] || 0
41
+ return exit_status
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ require 'set'
2
+
3
+ module VagrantPlugins
4
+ module Vocker
5
+ class Config < Vagrant.plugin("2", :config)
6
+ attr_reader :images, :containers
7
+
8
+ def initialize
9
+ @images = Set.new
10
+ @containers = Hash.new
11
+ end
12
+
13
+ def pull_images(*images)
14
+ @images += images.map(&:to_s)
15
+ end
16
+
17
+ def run(*args)
18
+ container_name = args.shift
19
+ params = {}
20
+
21
+ if args.empty?
22
+ params[:image] = container_name
23
+ elsif args.first.is_a?(String)
24
+ params[:image] = args.shift
25
+ params[:cmd] = container_name
26
+ else
27
+ params = args.shift
28
+ params[:cmd] ||= container_name
29
+ end
30
+
31
+ @containers[container_name.to_s] = params
32
+ end
33
+
34
+ def merge(other)
35
+ super.tap do |result|
36
+ result.pull_images *(other.images + self.images)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,54 @@
1
+ require 'digest/sha1'
2
+
3
+ module VagrantPlugins
4
+ module Vocker
5
+ class DockerClient
6
+ def initialize(machine)
7
+ @machine = machine
8
+ end
9
+
10
+ def pull_images(*images)
11
+ @machine.communicate.tap do |comm|
12
+ images.each do |image|
13
+ comm.sudo("docker images | grep -q #{image} || docker pull #{image}")
14
+ end
15
+ end
16
+ end
17
+
18
+ def daemon_running?
19
+ @machine.communicate.test('test -f /var/run/docker.pid')
20
+ end
21
+
22
+ def run(containers)
23
+ containers.each do |name, config|
24
+ cids_dir = "/var/lib/vocker/cids"
25
+ config[:cidfile] ||= "#{cids_dir}/#{Digest::SHA1.hexdigest name}"
26
+
27
+ id = "$(cat #{config[:cidfile]})"
28
+
29
+ @machine.communicate.sudo("mkdir -p #{cids_dir}")
30
+ if container_exist?(id)
31
+ start_container(id)
32
+ else
33
+ create_container(config)
34
+ end
35
+ end
36
+ end
37
+
38
+ def container_exist?(id)
39
+ @machine.communicate.test("sudo docker ps -a -q | grep -q #{id}")
40
+ end
41
+
42
+ def start_container(id)
43
+ @machine.communicate.sudo("docker start #{id}")
44
+ end
45
+
46
+ def create_container(config)
47
+ @machine.communicate.sudo %[
48
+ rm -f #{config[:cidfile]}
49
+ docker run -cidfile=#{config[:cidfile]} -d #{config[:image]} #{config[:cmd]}
50
+ ]
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ require_relative "errors"
2
+
3
+ module VagrantPlugins
4
+ module Vocker
5
+ class DockerInstaller
6
+ def initialize(machine)
7
+ @machine = machine
8
+ end
9
+
10
+ # This handles verifying the Docker installation, installing it if it was
11
+ # requested, and so on. This method will raise exceptions if things are
12
+ # wrong.
13
+ def ensure_installed
14
+ if !@machine.guest.capability?(:docker_installed)
15
+ @machine.ui.warn(I18n.t("vagrant.docker_cant_detect"))
16
+ return
17
+ end
18
+
19
+ if !@machine.guest.capability(:docker_installed)
20
+ @machine.ui.info(I18n.t("vagrant.docker_installing"))
21
+ @machine.guest.capability(:docker_install)
22
+
23
+ if !@machine.guest.capability(:docker_installed)
24
+ raise Errors::DockerInstallFailed
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ module VagrantPlugins
2
+ module Vocker
3
+ module Errors
4
+ class DockerInstallFailed < ::Vagrant::Errors::VagrantError
5
+ end
6
+
7
+ class DockerNotRunning < ::Vagrant::Errors::VagrantError
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,40 @@
1
+ require "vagrant"
2
+
3
+ I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
4
+ I18n.reload!
5
+
6
+ module VagrantPlugins
7
+ module Vocker
8
+ class Plugin < Vagrant.plugin("2")
9
+ name "Vocker"
10
+ description <<-DESC
11
+ Introduces Docker to Vagrant
12
+ DESC
13
+
14
+ config(:docker, :provisioner) do
15
+ require_relative "config"
16
+ Config
17
+ end
18
+
19
+ guest_capability("debian", "docker_install") do
20
+ require_relative "cap/debian/docker_install"
21
+ Cap::Debian::DockerInstall
22
+ end
23
+
24
+ guest_capability("linux", "docker_installed") do
25
+ require_relative "cap/linux/docker_installed"
26
+ Cap::Linux::DockerInstalled
27
+ end
28
+
29
+ provisioner(:docker) do
30
+ require_relative "provisioner"
31
+ Provisioner
32
+ end
33
+
34
+ command(:docker) do
35
+ require_relative "command"
36
+ Command
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ require_relative "errors"
2
+ require_relative "docker_client"
3
+ require_relative "docker_installer"
4
+
5
+ module VagrantPlugins
6
+ module Vocker
7
+ # TODO: Improve handling of vagrant-lxc specifics (like checking for apparmor
8
+ # profile stuff + autocorrection)
9
+ class Provisioner < Vagrant.plugin("2", :provisioner)
10
+ def initialize(machine, config, installer = nil, client = nil)
11
+ super(machine, config)
12
+ @installer = installer || DockerInstaller.new(@machine)
13
+ @client = client || DockerClient.new(@machine)
14
+ end
15
+
16
+ def provision
17
+ @logger = Log4r::Logger.new("vagrant::plugins::docker-provisioner")
18
+
19
+ @logger.info("Checking for Docker installation...")
20
+ @installer.ensure_installed
21
+
22
+ unless @client.daemon_running?
23
+ raise Errors::DockerNotRunning
24
+ end
25
+
26
+ if config.images.any?
27
+ @machine.ui.info(I18n.t("vagrant.docker_pulling_images"))
28
+ @client.pull_images(*config.images)
29
+ end
30
+
31
+ if config.containers.any?
32
+ @machine.ui.info(I18n.t("vagrant.docker_starting_containers"))
33
+ @client.run(config.containers)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module Vocker
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
data/lib/vocker.rb ADDED
@@ -0,0 +1 @@
1
+ require_relative 'vocker/plugin'
data/locales/en.yml ADDED
@@ -0,0 +1,8 @@
1
+ en:
2
+ vagrant:
3
+ docker_installing: |-
4
+ Installing Docker onto machine...
5
+ docker_pulling_images:
6
+ Pulling Docker images...
7
+ docker_starting_containers:
8
+ Starting Docker containers...
@@ -0,0 +1,20 @@
1
+ if ENV['COVERAGE'] == 'true'
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ end
5
+
6
+ require 'bogus/rspec'
7
+
8
+ require 'vocker'
9
+
10
+ Bogus.configure do |c|
11
+ c.search_modules << VagrantPlugins::Vocker
12
+ c.search_modules << Vagrant
13
+ end
14
+
15
+ RSpec.configure do |config|
16
+ config.treat_symbols_as_metadata_keys_with_true_values = true
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run :focus
19
+ config.order = 'random'
20
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ require 'vocker/config'
4
+
5
+ describe VagrantPlugins::Vocker::Config do
6
+ verify_contract(:config)
7
+
8
+ it 'combines images when merging' do
9
+ config = described_class.new.tap{|c| c.pull_images 'ubuntu', 'basebox' }
10
+ other = described_class.new.tap{|c| c.pull_images 'basebox', 'centos' }
11
+ merged = config.merge(other)
12
+
13
+ expect(merged.images.to_a).to match_array(['basebox', 'centos', 'ubuntu'])
14
+ end
15
+
16
+ it 'merges containers definitions' do
17
+ config = described_class.new.tap{|c| c.run 'ls', cmd: 'ls', image: 'ubuntu' }
18
+ other = described_class.new.tap{|c| c.run 'ls', cmd: 'ls -la', image: 'ubuntu' }
19
+ merged = config.merge(other)
20
+
21
+ expect(merged.containers).to include({'ls' => {cmd: 'ls -la', image: 'ubuntu'}})
22
+ end
23
+
24
+ describe 'containers arguments normalization' do
25
+ it 'maps a single argument as the image name' do
26
+ config = described_class.new.tap{|c| c.run 'mysql' }
27
+ expect(config.containers).to include('mysql' => {image: 'mysql'})
28
+ end
29
+
30
+ context 'when two strings are provided' do
31
+ subject { described_class.new.tap{|c| c.run 'ls -la', 'ubuntu' } }
32
+
33
+ it 'maps the first argument as the command' do
34
+ expect(subject.containers.values.first).to include(cmd: 'ls -la')
35
+ end
36
+
37
+ it 'maps the second argument as the image name' do
38
+ expect(subject.containers.values.first).to include(image: 'ubuntu')
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ require Vagrant.source_root.join('plugins/communicators/ssh/communicator')
4
+
5
+ require 'vocker/docker_client'
6
+
7
+ describe VagrantPlugins::Vocker::DockerClient do
8
+ verify_contract(:docker_client)
9
+
10
+ fake(:communicator, test: true) { VagrantPlugins::CommunicatorSSH::Communicator }
11
+
12
+ let(:machine) { fake(:machine, communicate: communicator) }
13
+
14
+ subject { described_class.new(machine) }
15
+
16
+ it 'pulls configured images' do
17
+ subject.pull_images 'base', 'mysql'
18
+ expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker pull base/})
19
+ expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker pull mysql/})
20
+ end
21
+
22
+ it 'verifies if the docker daemon is running' do
23
+ stub(communicator).test(with{|cmd| cmd == 'test -f /var/run/docker.pid'}) { true }
24
+ expect(subject.daemon_running?).to be_true
25
+
26
+ stub(communicator).test(any_args) { false }
27
+ expect(subject.daemon_running?).to be_false
28
+ end
29
+
30
+ context 'running containers' do
31
+ let(:containers) { {'mysql' => {image: 'mysql'}} }
32
+
33
+ it 'ensures container ids folder exists' do
34
+ subject.run containers
35
+ expect(communicator).to have_received.sudo(with{|cmd| cmd == 'mkdir -p /var/lib/vocker/cids'})
36
+ end
37
+
38
+ it 'automatically assigns a digest of the command as the cidfile if not specified' do
39
+ stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { false }
40
+ stub(Digest::SHA1).hexdigest('mysql') { 'digest' }
41
+ subject.run containers
42
+ expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-cidfile=\/var\/lib\/vocker\/cids\/digest/})
43
+ end
44
+
45
+ it 'allows cidfile to be specified' do
46
+ stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { false }
47
+ containers['mysql'][:cidfile] = '/foo/bla'
48
+ subject.run containers
49
+ expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /-cidfile=\/foo\/bla/})
50
+ end
51
+
52
+ context 'when the container already exists' do
53
+ before do
54
+ stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { true }
55
+ subject.run containers
56
+ end
57
+
58
+ it 'starts the container' do
59
+ expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker start/})
60
+ end
61
+ end
62
+
63
+ context 'when the container does not exist' do
64
+ before do
65
+ stub(communicator).test(with{|cmd| cmd =~ /docker ps/}) { false }
66
+ subject.run containers
67
+ end
68
+
69
+ it 'creates a new container' do
70
+ expect(communicator).to have_received.sudo(with{|cmd| cmd =~ /docker run/})
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ require 'vagrant/ui'
4
+ require Vagrant.source_root.join('plugins/communicators/ssh/communicator')
5
+
6
+ require 'vocker/docker_installer'
7
+
8
+ describe VagrantPlugins::Vocker::DockerInstaller do
9
+ verify_contract(:docker_installer)
10
+
11
+ fake(:guest)
12
+ fake(:ui) { Vagrant::UI::Interface }
13
+ let(:machine) { fake(:machine, guest: guest, ui: ui) }
14
+
15
+ subject { described_class.new(machine) }
16
+
17
+ it 'skips docker installation if guest is not capable' do
18
+ stub(guest).capability?(:docker_installed) { false }
19
+
20
+ subject.ensure_installed
21
+
22
+ expect(guest).to_not have_received.capability(:docker_installed)
23
+ expect(guest).to_not have_received.capability(:docker_install)
24
+ end
25
+
26
+ it 'skips docker installation if already installed' do
27
+ stub(guest).capability(:docker_installed) { true }
28
+
29
+ subject.ensure_installed
30
+
31
+ expect(guest).to have_received.capability(:docker_installed)
32
+ expect(guest).to_not have_received.capability(:docker_install)
33
+ end
34
+
35
+ it 'installs docker if not installed' do
36
+ # XXX: This is kinda hacky I believe
37
+ stub(guest).capability(:docker_installed) {
38
+ stub(guest).capability(:docker_installed) { true }
39
+ false
40
+ }
41
+
42
+ subject.ensure_installed
43
+
44
+ expect(guest).to have_received.capability(:docker_installed)
45
+ expect(guest).to have_received.capability(:docker_install)
46
+ end
47
+
48
+ it 'errors out if docker could not be installed' do
49
+ stub(guest).capability(:docker_installed) { false }
50
+
51
+ expect {
52
+ subject.ensure_installed
53
+ }.to raise_error(VagrantPlugins::Vocker::Errors::DockerInstallFailed)
54
+ end
55
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ require 'vagrant/ui'
4
+
5
+ require 'vocker/config'
6
+ require 'vocker/provisioner'
7
+
8
+ describe VagrantPlugins::Vocker::Provisioner do
9
+ verify_contract(:provisioner)
10
+
11
+ fake(:guest)
12
+ fake(:ui) { Vagrant::UI::Interface }
13
+
14
+ let(:installer) { fake(:docker_installer, ensure_installed: nil) }
15
+ let(:client) { fake(:docker_client, daemon_running?: true) }
16
+ let(:config) { VagrantPlugins::Vocker::Config.new }
17
+ let(:machine) { fake(:machine, guest: guest, ui: ui) }
18
+
19
+ subject { described_class.new(machine, config, installer, client) }
20
+
21
+ before do
22
+ config.pull_images 'base', 'mysql'
23
+ config.run 'mysql'
24
+ end
25
+
26
+ context 'docker can be installed and daemon is running' do
27
+ before { subject.provision }
28
+
29
+ it 'ensures docker gets installed' do
30
+ expect(installer).to have_received.ensure_installed
31
+ end
32
+
33
+ it 'pulls configured images' do
34
+ expect(client).to have_received.pull_images(*config.images)
35
+ end
36
+
37
+ it 'runs configured containers' do
38
+ expect(client).to have_received.run(with{|c| c['mysql'][:image] == 'mysql'})
39
+ end
40
+ end
41
+
42
+ context 'docker daemon is not able to start' do
43
+ before { stub(client).daemon_running? { false } }
44
+
45
+ it 'raises an error' do
46
+ expect{
47
+ subject.provision
48
+ }.to raise_error(VagrantPlugins::Vocker::Errors::DockerNotRunning)
49
+ end
50
+ end
51
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,9 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new do |t|
4
+ ENV['COVERAGE'] = 'true'
5
+ t.pattern = "./spec/**/*_spec.rb"
6
+ end
7
+
8
+ desc 'Default task which runs all specs with code coverage enabled'
9
+ task :default => ['spec']
data/vocker.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vocker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "vocker"
8
+ spec.version = VagrantPlugins::Vocker::VERSION
9
+ spec.authors = ["Fabio Rehm"]
10
+ spec.email = ["fgrehm@gmail.com"]
11
+ spec.description = %q{Introduces Docker to Vagrant}
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/fgrehm/vocker"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vocker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Fabio Rehm
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Introduces Docker to Vagrant
42
+ email:
43
+ - fgrehm@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .rspec
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - Guardfile
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - development/Vagrantfile
57
+ - lib/vocker.rb
58
+ - lib/vocker/cap/debian/docker_install.rb
59
+ - lib/vocker/cap/linux/docker_installed.rb
60
+ - lib/vocker/command.rb
61
+ - lib/vocker/config.rb
62
+ - lib/vocker/docker_client.rb
63
+ - lib/vocker/docker_installer.rb
64
+ - lib/vocker/errors.rb
65
+ - lib/vocker/plugin.rb
66
+ - lib/vocker/provisioner.rb
67
+ - lib/vocker/version.rb
68
+ - locales/en.yml
69
+ - spec/spec_helper.rb
70
+ - spec/unit/config_spec.rb
71
+ - spec/unit/docker_client_spec.rb
72
+ - spec/unit/docker_installer_spec.rb
73
+ - spec/unit/provisioner_spec.rb
74
+ - tasks/spec.rake
75
+ - vocker.gemspec
76
+ homepage: https://github.com/fgrehm/vocker
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.0.0
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Introduces Docker to Vagrant
100
+ test_files:
101
+ - spec/spec_helper.rb
102
+ - spec/unit/config_spec.rb
103
+ - spec/unit/docker_client_spec.rb
104
+ - spec/unit/docker_installer_spec.rb
105
+ - spec/unit/provisioner_spec.rb