vagrant/plugins/providers/docker/driver.rb

139 lines
3.7 KiB
Ruby

require "vagrant/util/busy"
require "vagrant/util/subprocess"
require "vagrant/util/retryable"
require 'log4r'
require 'json'
module VagrantPlugins
module DockerProvider
class Driver
include Vagrant::Util::Retryable
def initialize
@logger = Log4r::Logger.new("vagrant::docker::driver")
end
def create(params)
image = params.fetch(:image)
ports = Array(params[:ports])
volumes = Array(params[:volumes])
name = params.fetch(:name)
cmd = Array(params.fetch(:cmd))
run_cmd = %W(docker run -name #{name} -d)
run_cmd += ports.map { |p| ['-p', p.to_s] }
run_cmd += volumes.map { |v| ['-v', v.to_s] }
run_cmd += %W(-privileged) if params[:privileged]
run_cmd += %W(-h #{params[:hostname]}) if params[:hostname]
run_cmd += [image, cmd]
retryable(tries: 10, sleep: 1) do
execute(*run_cmd.flatten).chomp
end
end
def state(cid)
case
when running?(cid)
:running
when created?(cid)
:stopped
else
:not_created
end
end
def created?(cid)
result = execute('docker', 'ps', '-a', '-q', '-notrunc').to_s
result =~ /^#{Regexp.escape cid}$/
end
def running?(cid)
result = execute('docker', 'ps', '-q', '-notrunc')
result =~ /^#{Regexp.escape cid}$/m
end
def privileged?(cid)
inspect_container(cid)['HostConfig']['Privileged']
end
def start(cid)
unless running?(cid)
execute('docker', 'start', cid)
# This resets the cached information we have around, allowing `vagrant reload`s
# to work properly
# TODO: Add spec to verify this behavior
@data = nil
end
end
def stop(cid)
if running?(cid)
execute('docker', 'stop', '-t', '1', cid)
end
end
def rm(cid)
if created?(cid)
execute('docker', 'rm', '-v', cid)
end
end
def inspect_container(cid)
# DISCUSS: Is there a chance that this json will change after the container
# has been brought up?
@data ||= JSON.parse(execute('docker', 'inspect', cid)).first
end
def all_containers
execute('docker', 'ps', '-a', '-q', '-notrunc').to_s.split
end
def docker_bridge_ip
output = execute('/sbin/ip', '-4', 'addr', 'show', 'scope', 'global', 'docker0')
if output =~ /^\s+inet ([0-9.]+)\/[0-9]+\s+/
return $1.to_s
else
# TODO: Raise an user friendly message
raise 'Unable to fetch docker bridge IP!'
end
end
private
def execute(*cmd, &block)
result = raw(*cmd, &block)
if result.exit_code != 0
if @interrupted
@logger.info("Exit code != 0, but interrupted. Ignoring.")
else
msg = result.stdout.gsub("\r\n", "\n")
msg << result.stderr.gsub("\r\n", "\n")
raise "#{cmd.inspect}\n#{msg}" #Errors::ExecuteError, :command => command.inspect
end
end
# Return the output, making sure to replace any Windows-style
# newlines with Unix-style.
result.stdout.gsub("\r\n", "\n")
end
def raw(*cmd, &block)
int_callback = lambda do
@interrupted = true
@logger.info("Interrupted.")
end
# Append in the options for subprocess
cmd << { :notify => [:stdout, :stderr] }
Vagrant::Util::Busy.busy(int_callback) do
Vagrant::Util::Subprocess.execute(*cmd, &block)
end
end
end
end
end