docker-provider 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +125 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +134 -0
- data/Rakefile +20 -0
- data/boxes/dummy/README.md +17 -0
- data/boxes/dummy/metadata.json +3 -0
- data/boxes/nginx/.gitignore +1 -0
- data/boxes/nginx/Dockerfile +4 -0
- data/boxes/nginx/README.md +25 -0
- data/boxes/nginx/Vagrantfile.sample +6 -0
- data/boxes/nginx/metadata.json +3 -0
- data/boxes/nginx/start +5 -0
- data/boxes/precise/.gitignore +1 -0
- data/boxes/precise/Dockerfile +42 -0
- data/boxes/precise/README.md +18 -0
- data/boxes/precise/Vagrantfile.sample +6 -0
- data/boxes/precise/metadata.json +3 -0
- data/development/Vagrantfile +91 -0
- data/docker-provider.gemspec +25 -0
- data/example/Vagrantfile +36 -0
- data/lib/docker-provider.rb +1 -0
- data/lib/docker-provider/action.rb +161 -0
- data/lib/docker-provider/action/check_running.rb +25 -0
- data/lib/docker-provider/action/create.rb +56 -0
- data/lib/docker-provider/action/created.rb +18 -0
- data/lib/docker-provider/action/destroy.rb +24 -0
- data/lib/docker-provider/action/forward_ports.rb +54 -0
- data/lib/docker-provider/action/is_running.rb +20 -0
- data/lib/docker-provider/action/message.rb +23 -0
- data/lib/docker-provider/action/share_folders.rb +63 -0
- data/lib/docker-provider/action/start.rb +18 -0
- data/lib/docker-provider/action/stop.rb +21 -0
- data/lib/docker-provider/config.rb +28 -0
- data/lib/docker-provider/driver.rb +114 -0
- data/lib/docker-provider/plugin.rb +24 -0
- data/lib/docker-provider/provider.rb +59 -0
- data/lib/docker-provider/version.rb +5 -0
- data/locales/en.yml +21 -0
- data/spec/acceptance/Vagrantfile +25 -0
- data/spec/acceptance/vagrant_ssh.bats +34 -0
- data/spec/acceptance/vagrant_up.bats +35 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/unit_example_group.rb +39 -0
- data/spec/unit/driver_spec.rb +143 -0
- metadata +142 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class Created
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
machine = env[:machine]
|
11
|
+
driver = machine.provider.driver
|
12
|
+
env[:result] = machine.id && driver.created?(machine.id)
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class Destroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying")
|
11
|
+
|
12
|
+
machine = env[:machine]
|
13
|
+
config = machine.provider_config
|
14
|
+
driver = machine.provider.driver
|
15
|
+
|
16
|
+
driver.rm(machine.id)
|
17
|
+
machine.id = nil
|
18
|
+
|
19
|
+
@app.call env
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class ForwardPorts
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@env = env
|
11
|
+
|
12
|
+
env[:forwarded_ports] = compile_forwarded_ports(env[:machine].config)
|
13
|
+
|
14
|
+
if env[:forwarded_ports].any?
|
15
|
+
env[:ui].info I18n.t("vagrant.actions.vm.forward_ports.forwarding")
|
16
|
+
inform_forwarded_ports(env[:forwarded_ports])
|
17
|
+
end
|
18
|
+
|
19
|
+
# FIXME: Check whether the container has already been created with
|
20
|
+
# different exposed ports and let the user know about it
|
21
|
+
|
22
|
+
@app.call env
|
23
|
+
end
|
24
|
+
|
25
|
+
def inform_forwarded_ports(ports)
|
26
|
+
ports.each do |fp|
|
27
|
+
message_attributes = {
|
28
|
+
:adapter => 'eth0',
|
29
|
+
:guest_port => fp[:guest],
|
30
|
+
:host_port => fp[:host]
|
31
|
+
}
|
32
|
+
|
33
|
+
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.forwarding_entry",
|
34
|
+
message_attributes))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def compile_forwarded_ports(config)
|
41
|
+
mappings = {}
|
42
|
+
|
43
|
+
config.vm.networks.each do |type, options|
|
44
|
+
if type == :forwarded_port && options[:id] != 'ssh'
|
45
|
+
mappings[options[:host]] = options
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
mappings.values
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class IsRunning
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
machine = env[:machine]
|
11
|
+
driver = machine.provider.driver
|
12
|
+
|
13
|
+
env[:result] = driver.running?(machine.id)
|
14
|
+
|
15
|
+
@app.call(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
# XXX: Is this really needed? Should we contribute this back to Vagrant's core?
|
5
|
+
class Message
|
6
|
+
def initialize(app, env, msg_key, type = :info)
|
7
|
+
@app = app
|
8
|
+
@msg_key = msg_key
|
9
|
+
@type = type
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
machine = env[:machine]
|
14
|
+
message = I18n.t("docker_provider.messages.#{@msg_key}", name: machine.name)
|
15
|
+
|
16
|
+
env[:ui].send @type, message
|
17
|
+
|
18
|
+
@app.call env
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class ShareFolders
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
@env = env
|
11
|
+
prepare_folders
|
12
|
+
|
13
|
+
# FIXME: Check whether the container has already been created with
|
14
|
+
# different synced folders and let the user know about it
|
15
|
+
folders = []
|
16
|
+
shared_folders.each do |id, data|
|
17
|
+
folders << {
|
18
|
+
:name => id,
|
19
|
+
:hostpath => File.expand_path(data[:hostpath], @env[:root_path]),
|
20
|
+
:guestpath => data[:guestpath]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
@env[:synced_folders] = folders
|
24
|
+
|
25
|
+
@app.call(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
# This method returns an actual list of synced folders to create and their
|
29
|
+
# proper path.
|
30
|
+
def shared_folders
|
31
|
+
{}.tap do |result|
|
32
|
+
@env[:machine].config.vm.synced_folders.each do |id, data|
|
33
|
+
# Ignore disabled shared folders
|
34
|
+
next if data[:disabled]
|
35
|
+
# This to prevent overwriting the actual shared folders data
|
36
|
+
result[id] = data.dup
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Prepares the shared folders by verifying they exist and creating them
|
42
|
+
# if they don't.
|
43
|
+
def prepare_folders
|
44
|
+
shared_folders.each do |id, options|
|
45
|
+
hostpath = Pathname.new(options[:hostpath]).expand_path(@env[:root_path])
|
46
|
+
|
47
|
+
if !hostpath.directory? && options[:create]
|
48
|
+
# Host path doesn't exist, so let's create it.
|
49
|
+
@logger.debug("Host path doesn't exist, creating: #{hostpath}")
|
50
|
+
|
51
|
+
begin
|
52
|
+
hostpath.mkpath
|
53
|
+
rescue Errno::EACCES
|
54
|
+
raise Vagrant::Errors::SharedFolderCreateFailed,
|
55
|
+
:path => hostpath.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class Start
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
machine = env[:machine]
|
11
|
+
driver = machine.provider.driver
|
12
|
+
driver.start(machine.id)
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
module Action
|
4
|
+
class Stop
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
machine = env[:machine]
|
11
|
+
driver = machine.provider.driver
|
12
|
+
if driver.running?(machine.id)
|
13
|
+
env[:ui].info I18n.t("docker_provider.messages.stopping")
|
14
|
+
driver.stop(machine.id)
|
15
|
+
end
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module DockerProvider
|
3
|
+
class Config < Vagrant.plugin("2", :config)
|
4
|
+
attr_accessor :image, :cmd, :ports
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@image = UNSET_VALUE
|
8
|
+
@cmd = UNSET_VALUE
|
9
|
+
@ports = UNSET_VALUE
|
10
|
+
end
|
11
|
+
|
12
|
+
def finalize!
|
13
|
+
@ports = [] if @ports == UNSET_VALUE
|
14
|
+
@cmd = [] if @cmd == UNSET_VALUE
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate(machine)
|
18
|
+
errors = _detected_errors
|
19
|
+
|
20
|
+
errors << I18n.t("docker_provider.errors.config.image_not_set") if @image == UNSET_VALUE
|
21
|
+
# TODO: Detect if base image has a CMD / ENTRYPOINT set before erroring out
|
22
|
+
errors << I18n.t("docker_provider.errors.config.cmd_not_set") if @cmd == UNSET_VALUE
|
23
|
+
|
24
|
+
{ "docker-provider" => errors }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "vagrant/util/busy"
|
2
|
+
require "vagrant/util/subprocess"
|
3
|
+
require "vagrant/util/retryable"
|
4
|
+
|
5
|
+
require 'log4r'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module DockerProvider
|
10
|
+
class Driver
|
11
|
+
include Vagrant::Util::Retryable
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@logger = Log4r::Logger.new("vagrant::docker::driver")
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(params)
|
18
|
+
image = params.fetch(:image)
|
19
|
+
ports = Array(params[:ports])
|
20
|
+
volumes = Array(params[:volumes])
|
21
|
+
name = params.fetch(:name)
|
22
|
+
cmd = Array(params.fetch(:cmd))
|
23
|
+
|
24
|
+
run_cmd = %W(docker run -name #{name} -d)
|
25
|
+
run_cmd += ports.map { |p| ['-p', p.to_s] }
|
26
|
+
run_cmd += volumes.map { |v| ['-v', v.to_s] }
|
27
|
+
run_cmd += %W(-h #{params[:hostname]}) if params[:hostname]
|
28
|
+
run_cmd += [image, cmd]
|
29
|
+
|
30
|
+
retryable(tries: 10, sleep: 1) do
|
31
|
+
execute(*run_cmd.flatten).chomp
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def state(cid)
|
36
|
+
case
|
37
|
+
when running?(cid)
|
38
|
+
:running
|
39
|
+
when created?(cid)
|
40
|
+
:stopped
|
41
|
+
else
|
42
|
+
:not_created
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def created?(cid)
|
47
|
+
result = execute('docker', 'ps', '-a', '-q').to_s
|
48
|
+
result =~ /^#{Regexp.escape cid}$/
|
49
|
+
end
|
50
|
+
|
51
|
+
def running?(cid)
|
52
|
+
result = execute('docker', 'ps', '-q')
|
53
|
+
result =~ /^#{Regexp.escape cid}$/m
|
54
|
+
end
|
55
|
+
|
56
|
+
def start(cid)
|
57
|
+
unless running?(cid)
|
58
|
+
execute('docker', 'start', cid)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop(cid)
|
63
|
+
if running?(cid)
|
64
|
+
execute('docker', 'stop', cid)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def rm(cid)
|
69
|
+
if created?(cid)
|
70
|
+
execute('docker', 'rm', cid)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect(cid)
|
75
|
+
# DISCUSS: Is there a chance that this will change?
|
76
|
+
@data ||= JSON.parse(execute('docker', 'inspect', cid)).first
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def execute(*cmd, &block)
|
82
|
+
result = raw(*cmd, &block)
|
83
|
+
|
84
|
+
if result.exit_code != 0
|
85
|
+
if @interrupted
|
86
|
+
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
87
|
+
else
|
88
|
+
msg = result.stdout.gsub("\r\n", "\n")
|
89
|
+
msg << result.stderr.gsub("\r\n", "\n")
|
90
|
+
raise "#{cmd.inspect}\n#{msg}" #Errors::ExecuteError, :command => command.inspect
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return the output, making sure to replace any Windows-style
|
95
|
+
# newlines with Unix-style.
|
96
|
+
result.stdout.gsub("\r\n", "\n")
|
97
|
+
end
|
98
|
+
|
99
|
+
def raw(*cmd, &block)
|
100
|
+
int_callback = lambda do
|
101
|
+
@interrupted = true
|
102
|
+
@logger.info("Interrupted.")
|
103
|
+
end
|
104
|
+
|
105
|
+
# Append in the options for subprocess
|
106
|
+
cmd << { :notify => [:stdout, :stderr] }
|
107
|
+
|
108
|
+
Vagrant::Util::Busy.busy(int_callback) do
|
109
|
+
Vagrant::Util::Subprocess.execute(*cmd, &block)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "version"
|
2
|
+
|
3
|
+
require 'vagrant'
|
4
|
+
|
5
|
+
I18n.load_path << File.expand_path(File.dirname(__FILE__) + '/../../locales/en.yml')
|
6
|
+
I18n.reload!
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module DockerProvider
|
10
|
+
class Plugin < Vagrant.plugin("2")
|
11
|
+
name "docker-provider"
|
12
|
+
|
13
|
+
provider(:docker, parallel: true) do
|
14
|
+
require_relative 'provider'
|
15
|
+
Provider
|
16
|
+
end
|
17
|
+
|
18
|
+
config(:docker, :provider) do
|
19
|
+
require_relative 'config'
|
20
|
+
Config
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'driver'
|
2
|
+
require_relative 'action'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module DockerProvider
|
6
|
+
class Provider < Vagrant.plugin("2", :provider)
|
7
|
+
attr_reader :driver
|
8
|
+
|
9
|
+
def initialize(machine)
|
10
|
+
@logger = Log4r::Logger.new("vagrant::provider::docker")
|
11
|
+
@machine = machine
|
12
|
+
@driver = Driver.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# @see Vagrant::Plugin::V2::Provider#action
|
16
|
+
def action(name)
|
17
|
+
action_method = "action_#{name}"
|
18
|
+
return Action.send(action_method) if Action.respond_to?(action_method)
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the SSH info for accessing the Container.
|
23
|
+
def ssh_info
|
24
|
+
# If the Container is not created then we cannot possibly SSH into it, so
|
25
|
+
# we return nil.
|
26
|
+
return nil if state == :not_created
|
27
|
+
|
28
|
+
network = @driver.inspect(@machine.id)['NetworkSettings']
|
29
|
+
ip = network['IPAddress']
|
30
|
+
|
31
|
+
# If we were not able to identify the container's IP, we return nil
|
32
|
+
# here and we let Vagrant core deal with it ;)
|
33
|
+
return nil unless ip
|
34
|
+
|
35
|
+
{
|
36
|
+
:host => ip,
|
37
|
+
:port => @machine.config.ssh.guest_port
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def state
|
42
|
+
state_id = nil
|
43
|
+
state_id = :not_created if !@machine.id || !@driver.created?(@machine.id)
|
44
|
+
state_id = @driver.state(@machine.id) if @machine.id && !state_id
|
45
|
+
state_id = :unknown if !state_id
|
46
|
+
|
47
|
+
short = state_id.to_s.gsub("_", " ")
|
48
|
+
long = I18n.t("vagrant.commands.status.#{state_id}")
|
49
|
+
|
50
|
+
Vagrant::MachineState.new(state_id, short, long)
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
id = @machine.id ? @machine.id : "new container"
|
55
|
+
"Docker (#{id})"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|