Squash the f-docker-hostmachine branch.
Initial work commands/up: make sure all names to with_target_vms are strings providers/docker: create a docker host VM if needed providers/docker: executor abstraction for driver to eventually support remote providers/docker: vagrant executor providers/docker: support creating the machine providers/docker: status works if host VM is gone providers/docker: use start fence to get real docker output core: Call preserves stack ordering core: support Message post option providers/docker: Guard some features with HasSSH checks providers/docker: much better messaging around create/destroy providers/docker: output the container ID on create providers/docker: copy the hostmachine Vagrantfile to the data dir providers/docker: should make host machine before any up action providers/docker: HandleBox before the host machine providers/virtualbox: functional_vboxsf to disable vboxsf providers/virtualbox: synced folder usable method should take 2 args providers/docker: default machine name to :default
This commit is contained in:
parent
d42d62ead1
commit
8c7ab333a0
|
@ -46,15 +46,14 @@ module Vagrant
|
|||
builder = Builder.new
|
||||
@block.call(new_env, builder)
|
||||
|
||||
# Run the result with our new environment
|
||||
# Append our own app onto the builder so we slide the new
|
||||
# stack into our own chain...
|
||||
builder.use @app
|
||||
@child_app = builder.to_app(new_env)
|
||||
final_env = runner.run(@child_app, new_env)
|
||||
final_env = runner.run(@child_app, new_env)
|
||||
|
||||
# Merge the environment into our original environment
|
||||
env.merge!(final_env)
|
||||
|
||||
# Call the next step using our final environment
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def recover(env)
|
||||
|
|
|
@ -6,11 +6,19 @@ module Vagrant
|
|||
def initialize(app, env, message, **opts)
|
||||
@app = app
|
||||
@message = message
|
||||
@opts = opts
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:ui].output(@message)
|
||||
if !@opts[:post]
|
||||
env[:ui].output(@message)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
|
||||
if @opts[:post]
|
||||
env[:ui].output(@message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -293,9 +293,12 @@ module Vagrant
|
|||
# Fast-path if there is no prefix
|
||||
return message if prefix.empty?
|
||||
|
||||
target = @prefix
|
||||
target = opts[:target] if opts.has_key?(:target)
|
||||
|
||||
# Otherwise, make sure to prefix every line properly
|
||||
message.split("\n").map do |line|
|
||||
"#{prefix}#{@prefix}: #{line}"
|
||||
"#{prefix}#{target}: #{line}"
|
||||
end.join("\n")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ module VagrantPlugins
|
|||
if names.empty?
|
||||
@env.vagrantfile.machine_names_and_options.each do |n, o|
|
||||
o[:autostart] = true if !o.has_key?(:autostart)
|
||||
names << n if o[:autostart]
|
||||
names << n.to_s if o[:autostart]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,13 +9,30 @@ module VagrantPlugins
|
|||
def self.action_up
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use ConfigValidate
|
||||
b.use HandleBox
|
||||
|
||||
b.use Call, IsState, :host_state_unknown do |env, b2|
|
||||
if env[:result]
|
||||
b2.use HostMachine
|
||||
end
|
||||
end
|
||||
|
||||
b.use Call, IsState, :not_created do |env, b2|
|
||||
# If the VM is NOT created yet, then do the setup steps
|
||||
if env[:result]
|
||||
b2.use HandleBox
|
||||
b2.use EnvSet, :port_collision_repair => true
|
||||
b2.use HandleForwardedPortCollisions
|
||||
b2.use Provision
|
||||
|
||||
b2.use Call, HasSSH do |env2, b3|
|
||||
if env2[:result]
|
||||
b3.use Provision
|
||||
else
|
||||
b3.use Message,
|
||||
I18n.t("docker_provider.messages.provision_no_ssh"),
|
||||
post: true
|
||||
end
|
||||
end
|
||||
|
||||
b2.use PrepareNFSValidIds
|
||||
b2.use SyncedFolderCleanup
|
||||
b2.use SyncedFolders
|
||||
|
@ -61,6 +78,12 @@ module VagrantPlugins
|
|||
# the virtual machine, gracefully or by force.
|
||||
def self.action_halt
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use Call, IsState, :host_state_unknown do |env, b2|
|
||||
if env[:result]
|
||||
b2.use HostMachine
|
||||
end
|
||||
end
|
||||
|
||||
b.use Call, IsState, :not_created do |env, b2|
|
||||
if env[:result]
|
||||
b2.use Message, I18n.t("docker_provider.messages.not_created")
|
||||
|
@ -98,6 +121,12 @@ module VagrantPlugins
|
|||
# freeing the resources of the underlying virtual machine.
|
||||
def self.action_destroy
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use Call, IsState, :host_state_unknown do |env, b2|
|
||||
if env[:result]
|
||||
b2.use HostMachine
|
||||
end
|
||||
end
|
||||
|
||||
b.use Call, IsState, :not_created do |env, b2|
|
||||
if env[:result]
|
||||
b2.use Message, I18n.t("docker_provider.messages.not_created")
|
||||
|
@ -177,7 +206,12 @@ module VagrantPlugins
|
|||
Vagrant::Action::Builder.new.tap do |b|
|
||||
# TODO: b.use SetHostname
|
||||
b.use Start
|
||||
b.use WaitForCommunicator
|
||||
|
||||
b.use Call, HasSSH do |env, b2|
|
||||
if env[:result]
|
||||
b2.use WaitForCommunicator
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -186,6 +220,8 @@ module VagrantPlugins
|
|||
autoload :Create, action_root.join("create")
|
||||
autoload :Destroy, action_root.join("destroy")
|
||||
autoload :ForwardPorts, action_root.join("forward_ports")
|
||||
autoload :HasSSH, action_root.join("has_ssh")
|
||||
autoload :HostMachine, action_root.join("host_machine")
|
||||
autoload :Stop, action_root.join("stop")
|
||||
autoload :PrepareNFSValidIds, action_root.join("prepare_nfs_valid_ids")
|
||||
autoload :PrepareNFSSettings, action_root.join("prepare_nfs_settings")
|
||||
|
|
|
@ -16,11 +16,19 @@ module VagrantPlugins
|
|||
|
||||
guard_cmd_configured!
|
||||
|
||||
params = create_params
|
||||
|
||||
cid = ''
|
||||
@@mutex.synchronize do
|
||||
cid = @driver.create(create_params)
|
||||
env[:ui].output(I18n.t("docker_provider.creating"))
|
||||
env[:ui].detail(" Name: #{params[:name]}")
|
||||
env[:ui].detail("Image: #{params[:image]}")
|
||||
|
||||
cid = @driver.create(params)
|
||||
end
|
||||
|
||||
env[:ui].detail(" \n"+I18n.t(
|
||||
"docker_provider.created", id: cid[0...16]))
|
||||
@machine.id = cid
|
||||
@app.call(env)
|
||||
end
|
||||
|
@ -31,13 +39,14 @@ module VagrantPlugins
|
|||
container_name << "_#{Time.now.to_i}"
|
||||
|
||||
{
|
||||
image: @provider_config.image,
|
||||
cmd: @provider_config.cmd,
|
||||
ports: forwarded_ports,
|
||||
name: container_name,
|
||||
extra_args: @provider_config.create_args,
|
||||
hostname: @machine_config.vm.hostname,
|
||||
image: @provider_config.image,
|
||||
name: container_name,
|
||||
ports: forwarded_ports,
|
||||
privileged: @provider_config.privileged,
|
||||
volumes: @provider_config.volumes,
|
||||
privileged: @provider_config.privileged
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -7,10 +7,9 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def call(env)
|
||||
env[:ui].info I18n.t("vagrant.actions.vm.destroy.destroying")
|
||||
env[:ui].info I18n.t("docker_provider.messages.destroying")
|
||||
|
||||
machine = env[:machine]
|
||||
config = machine.provider_config
|
||||
driver = machine.provider.driver
|
||||
|
||||
driver.rm(machine.id)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Action
|
||||
# This middleware is used with Call to test if this machine supports
|
||||
# SSH.
|
||||
class HasSSH
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env[:result] = env[:machine].provider_config.has_ssh
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
require "log4r"
|
||||
|
||||
require "vagrant/util/platform"
|
||||
require "vagrant/util/silence_warnings"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Action
|
||||
# This action is responsible for creating the host machine if
|
||||
# we need to. The host machine is where Docker containers will
|
||||
# live.
|
||||
class HostMachine
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::docker::hostmachine")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if !env[:machine].provider.host_vm?
|
||||
@logger.info("No host machine needed.")
|
||||
return @app.call(env)
|
||||
end
|
||||
|
||||
env[:machine].ui.output(I18n.t(
|
||||
"docker_provider.host_machine_needed"))
|
||||
|
||||
# TODO(mitchellh): process-level lock so that we don't
|
||||
# step on parallel Vagrant's toes.
|
||||
|
||||
host_machine = env[:machine].provider.host_vm
|
||||
|
||||
# See if the machine is ready already.
|
||||
if host_machine.communicate.ready?
|
||||
env[:machine].ui.detail(I18n.t("docker_provider.host_machine_ready"))
|
||||
return @app.call(env)
|
||||
end
|
||||
|
||||
# Create a UI for this machine that stays at the detail level
|
||||
proxy_ui = host_machine.ui.dup
|
||||
proxy_ui.opts[:bold] = false
|
||||
proxy_ui.opts[:prefix_spaces] = true
|
||||
proxy_ui.opts[:target] = env[:machine].name.to_s
|
||||
|
||||
env[:machine].ui.detail(
|
||||
I18n.t("docker_provider.host_machine_starting"))
|
||||
env[:machine].ui.detail(" ")
|
||||
host_machine.with_ui(proxy_ui) do
|
||||
host_machine.action(:up)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,25 +3,66 @@ module VagrantPlugins
|
|||
class Config < Vagrant.plugin("2", :config)
|
||||
attr_accessor :image, :cmd, :ports, :volumes, :privileged
|
||||
|
||||
# Additional arguments to pass to `docker run` when creating
|
||||
# the container for the first time. This is an array of args.
|
||||
#
|
||||
# @return [Array<String>]
|
||||
attr_accessor :create_args
|
||||
|
||||
# True if the Docker container exposes SSH access. If this is true,
|
||||
# then Vagrant can do a bunch more things like setting the hostname,
|
||||
# provisioning, etc.
|
||||
attr_accessor :has_ssh
|
||||
|
||||
# The name of the machine in the Vagrantfile set with
|
||||
# "vagrant_vagrantfile" that will be the docker host. Defaults
|
||||
# to "default"
|
||||
#
|
||||
# See the "vagrant_vagrantfile" docs for more info.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :vagrant_machine
|
||||
|
||||
# The path to the Vagrantfile that contains a VM that will be
|
||||
# started as the Docker host if needed (Windows, OS X, Linux
|
||||
# without container support).
|
||||
#
|
||||
# Defaults to a built-in Vagrantfile that will load boot2docker.
|
||||
#
|
||||
# NOTE: This only has an effect if Vagrant needs a Docker host.
|
||||
# Vagrant determines this automatically based on the environment
|
||||
# it is running in.
|
||||
#
|
||||
# @return [String]
|
||||
attr_accessor :vagrant_vagrantfile
|
||||
|
||||
def initialize
|
||||
@cmd = UNSET_VALUE
|
||||
@create_args = []
|
||||
@has_ssh = UNSET_VALUE
|
||||
@image = UNSET_VALUE
|
||||
@ports = []
|
||||
@privileged = UNSET_VALUE
|
||||
@volumes = []
|
||||
@vagrant_machine = UNSET_VALUE
|
||||
@vagrant_vagrantfile = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
@cmd = [] if @cmd == UNSET_VALUE
|
||||
@create_args = [] if @create_args == UNSET_VALUE
|
||||
@has_ssh = false if @has_ssh == UNSET_VALUE
|
||||
@image = nil if @image == UNSET_VALUE
|
||||
@privileged = false if @privileged == UNSET_VALUE
|
||||
@vagrant_machine = nil if @vagrant_machine == UNSET_VALUE
|
||||
@vagrant_vagrantfile = nil if @vagrant_vagrantfile == UNSET_VALUE
|
||||
end
|
||||
|
||||
def validate(machine)
|
||||
errors = _detected_errors
|
||||
|
||||
# TODO: Detect if base image has a CMD / ENTRYPOINT set before erroring out
|
||||
errors << I18n.t("docker_provider.errors.config.cmd_not_set") if @cmd == UNSET_VALUE
|
||||
errors << I18n.t("docker_provider.errors.config.cmd_not_set") if @cmd == UNSET_VALUE
|
||||
|
||||
{ "docker provider" => errors }
|
||||
end
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
require "vagrant/util/busy"
|
||||
require "vagrant/util/subprocess"
|
||||
require "vagrant/util/retryable"
|
||||
require "json"
|
||||
|
||||
require 'log4r'
|
||||
require 'json'
|
||||
require "log4r"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
class Driver
|
||||
include Vagrant::Util::Retryable
|
||||
# The executor is responsible for actually executing Docker commands.
|
||||
# This is set by the provider, but defaults to local execution.
|
||||
attr_accessor :executor
|
||||
|
||||
def initialize
|
||||
@logger = Log4r::Logger.new("vagrant::docker::driver")
|
||||
@logger = Log4r::Logger.new("vagrant::docker::driver")
|
||||
@executor = Executor::Local.new
|
||||
end
|
||||
|
||||
def create(params)
|
||||
|
@ -26,6 +26,7 @@ module VagrantPlugins
|
|||
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 += params[:extra_args] if params[:extra_args]
|
||||
run_cmd += [image, cmd]
|
||||
|
||||
execute(*run_cmd.flatten).chomp
|
||||
|
@ -101,35 +102,7 @@ module VagrantPlugins
|
|||
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
|
||||
@executor.execute(*cmd, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,10 @@ module VagrantPlugins
|
|||
error_namespace("docker_provider.errors")
|
||||
end
|
||||
|
||||
class ExecuteError < DockerError
|
||||
error_key(:execute_error)
|
||||
end
|
||||
|
||||
class ImageNotConfiguredError < DockerError
|
||||
error_key(:docker_provider_image_not_configured)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
require "vagrant/util/busy"
|
||||
require "vagrant/util/subprocess"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Executor
|
||||
# The Local executor executes a Docker client that is running
|
||||
# locally.
|
||||
class Local
|
||||
def execute(*cmd, &block)
|
||||
# Append in the options for subprocess
|
||||
cmd << { :notify => [:stdout, :stderr] }
|
||||
|
||||
interrupted = false
|
||||
int_callback = ->{ interrupted = true }
|
||||
result = Vagrant::Util::Busy.busy(int_callback) do
|
||||
Vagrant::Util::Subprocess.execute(*cmd, &block)
|
||||
end
|
||||
|
||||
if result.exit_code != 0 && !interrupted
|
||||
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
|
||||
|
||||
# Return the output, making sure to replace any Windows-style
|
||||
# newlines with Unix-style.
|
||||
result.stdout.gsub("\r\n", "\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
require "vagrant/util/shell_quote"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Executor
|
||||
# The Vagrant executor runs Docker over SSH against the given
|
||||
# Vagrant-managed machine.
|
||||
class Vagrant
|
||||
def initialize(host_machine)
|
||||
@host_machine = host_machine
|
||||
end
|
||||
|
||||
def execute(*cmd, &block)
|
||||
quote = '"'
|
||||
cmd = cmd.map do |a|
|
||||
"#{quote}#{::Vagrant::Util::ShellQuote.escape(a, quote)}#{quote}"
|
||||
end.join(" ")
|
||||
|
||||
# Add a start fence so we know when to start reading output.
|
||||
# We have to do this because boot2docker outputs a login shell
|
||||
# boot2docker version that we get otherwise and messes up output.
|
||||
start_fence = "========== VAGRANT DOCKER BEGIN =========="
|
||||
ssh_cmd = "echo \"#{start_fence}\"; #{cmd}"
|
||||
|
||||
stderr = ""
|
||||
stdout = ""
|
||||
fenced = false
|
||||
comm = @host_machine.communicate
|
||||
code = comm.execute(ssh_cmd, error_check: false) do |type, data|
|
||||
next if ![:stdout, :stderr].include?(type)
|
||||
stderr << data if type == :stderr
|
||||
stdout << data if type == :stdout
|
||||
|
||||
if !fenced
|
||||
index = stdout.index(start_fence)
|
||||
if index
|
||||
index += start_fence.length
|
||||
stdout = stdout[index..-1]
|
||||
stdout.chomp!
|
||||
end
|
||||
end
|
||||
|
||||
block.call(type, data) if block && fenced
|
||||
end
|
||||
|
||||
if code != 0
|
||||
raise Errors::ExecuteError,
|
||||
command: cmd,
|
||||
stderr: stderr.chomp,
|
||||
stdout: stdout.chomp
|
||||
end
|
||||
|
||||
stdout.chomp
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "mitchellh/boot2docker"
|
||||
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.check_guest_additions = false
|
||||
v.functional_vboxsf = false
|
||||
end
|
||||
end
|
|
@ -4,6 +4,11 @@ module VagrantPlugins
|
|||
autoload :Driver, File.expand_path("../driver", __FILE__)
|
||||
autoload :Errors, File.expand_path("../errors", __FILE__)
|
||||
|
||||
module Executor
|
||||
autoload :Local, File.expand_path("../executor/local", __FILE__)
|
||||
autoload :Vagrant, File.expand_path("../executor/vagrant", __FILE__)
|
||||
end
|
||||
|
||||
class Plugin < Vagrant.plugin("2")
|
||||
name "docker-provider"
|
||||
description <<-EOF
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
require "fileutils"
|
||||
|
||||
require "log4r"
|
||||
|
||||
require "vagrant/action/builtin/mixin_synced_folders"
|
||||
require "vagrant/util/silence_warnings"
|
||||
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
class Provider < Vagrant.plugin("2", :provider)
|
||||
attr_reader :driver
|
||||
|
||||
def initialize(machine)
|
||||
@logger = Log4r::Logger.new("vagrant::provider::docker")
|
||||
@machine = machine
|
||||
@driver = Driver.new
|
||||
end
|
||||
|
||||
# @see Vagrant::Plugin::V2::Provider#action
|
||||
|
@ -18,13 +20,107 @@ module VagrantPlugins
|
|||
nil
|
||||
end
|
||||
|
||||
# Returns the driver instance for this provider.
|
||||
def driver
|
||||
return @driver if @driver
|
||||
@driver = Driver.new
|
||||
|
||||
# If we are running on a host machine, then we set the executor
|
||||
# to execute remotely.
|
||||
if host_vm?
|
||||
@driver.executor = Executor::Vagrant.new(host_vm)
|
||||
end
|
||||
|
||||
@driver
|
||||
end
|
||||
|
||||
# This returns the {Vagrant::Machine} that is our host machine.
|
||||
# It does not perform any action on the machine or verify it is
|
||||
# running.
|
||||
#
|
||||
# @return [Vagrant::Machine]
|
||||
def host_vm
|
||||
return @host_vm if @host_vm
|
||||
|
||||
# TODO(mitchellh): process-wide lock
|
||||
|
||||
vf_path = @machine.provider_config.vagrant_vagrantfile
|
||||
host_machine_name = @machine.provider_config.vagrant_machine || :default
|
||||
if !vf_path
|
||||
# We don't have a Vagrantfile path set, so we're going to use
|
||||
# the default but we need to copy it into the data dir so that
|
||||
# we don't write into our installation dir (we can't).
|
||||
default_path = File.expand_path("../hostmachine/Vagrantfile", __FILE__)
|
||||
vf_path = @machine.env.data_dir.join("docker-host", "Vagrantfile")
|
||||
vf_path.dirname.mkpath
|
||||
FileUtils.cp(default_path, vf_path)
|
||||
|
||||
# Set the machine name since we hardcode that for the default
|
||||
host_machine_name = :default
|
||||
end
|
||||
|
||||
vf_file = File.basename(vf_path)
|
||||
vf_path = File.dirname(vf_path)
|
||||
|
||||
# Create the env to manage this machine
|
||||
@host_vm = Vagrant::Util::SilenceWarnings.silence! do
|
||||
host_env = Vagrant::Environment.new(
|
||||
cwd: vf_path,
|
||||
home_path: @machine.env.home_path,
|
||||
ui_class: @machine.env.ui_class,
|
||||
vagrantfile_name: vf_file,
|
||||
)
|
||||
|
||||
# TODO(mitchellh): configure the provider of this machine somehow
|
||||
host_env.machine(host_machine_name, :virtualbox)
|
||||
end
|
||||
|
||||
# Make sure we swap all the synced folders out from our
|
||||
# machine so that we do a double synced folder: normal synced
|
||||
# folders to the host machine, then Docker volumes within that host.
|
||||
sf_helper_klass = Class.new do
|
||||
include Vagrant::Action::Builtin::MixinSyncedFolders
|
||||
end
|
||||
sf_helper = sf_helper_klass.new
|
||||
our_folders = sf_helper.synced_folders(@machine)
|
||||
if our_folders[:docker]
|
||||
our_folders[:docker].each do |id, data|
|
||||
data = data.dup
|
||||
data.delete(:type)
|
||||
|
||||
# Add them to the host machine
|
||||
=begin
|
||||
@host_vm.config.vm.synced_folder(
|
||||
data[:hostpath],
|
||||
data[:guestpath],
|
||||
data)
|
||||
=end
|
||||
|
||||
# Remove from our machine
|
||||
@machine.config.vm.synced_folders.delete(id)
|
||||
end
|
||||
end
|
||||
|
||||
@host_vm
|
||||
end
|
||||
|
||||
# This says whether or not Docker will be running within a VM
|
||||
# rather than directly on our system. Docker needs to run in a VM
|
||||
# when we're not on Linux, or not on a Linux that supports Docker.
|
||||
def host_vm?
|
||||
# TODO: It'd be nice to also check if Docker supports the version
|
||||
# of Linux that Vagrant is running on so that we can spin up a VM
|
||||
# on old versions of Linux as well.
|
||||
!Vagrant::Util::Platform.linux?
|
||||
end
|
||||
|
||||
# Returns the SSH info for accessing the Container.
|
||||
def ssh_info
|
||||
# If the Container is not created then we cannot possibly SSH into it, so
|
||||
# we return nil.
|
||||
return nil if state == :not_created
|
||||
|
||||
network = @driver.inspect_container(@machine.id)['NetworkSettings']
|
||||
network = driver.inspect_container(@machine.id)['NetworkSettings']
|
||||
ip = network['IPAddress']
|
||||
|
||||
# If we were not able to identify the container's IP, we return nil
|
||||
|
@ -39,12 +135,14 @@ module VagrantPlugins
|
|||
|
||||
def state
|
||||
state_id = nil
|
||||
state_id = :not_created if !@machine.id || !@driver.created?(@machine.id)
|
||||
state_id = @driver.state(@machine.id) if @machine.id && !state_id
|
||||
state_id = :host_state_unknown if host_vm? && !host_vm.communicate.ready?
|
||||
state_id = :not_created if !state_id && \
|
||||
(!@machine.id || !driver.created?(@machine.id))
|
||||
state_id = driver.state(@machine.id) if @machine.id && !state_id
|
||||
state_id = :unknown if !state_id
|
||||
|
||||
short = state_id.to_s.gsub("_", " ")
|
||||
long = I18n.t("vagrant.commands.status.#{state_id}")
|
||||
long = I18n.t("docker_provider.status.#{state_id}")
|
||||
|
||||
Vagrant::MachineState.new(state_id, short, long)
|
||||
end
|
||||
|
|
|
@ -38,6 +38,13 @@ module VagrantPlugins
|
|||
# @return [String]
|
||||
attr_accessor :name
|
||||
|
||||
# Whether or not this VM has a functional vboxsf filesystem module.
|
||||
# This defaults to true. If you set this to false, then the "virtualbox"
|
||||
# synced folder type won't be valid.
|
||||
#
|
||||
# @return [Boolean]
|
||||
attr_accessor :functional_vboxsf
|
||||
|
||||
# The defined network adapters.
|
||||
#
|
||||
# @return [Hash]
|
||||
|
@ -48,6 +55,7 @@ module VagrantPlugins
|
|||
@check_guest_additions = UNSET_VALUE
|
||||
@customizations = []
|
||||
@destroy_unused_network_interfaces = UNSET_VALUE
|
||||
@functional_vboxsf = UNSET_VALUE
|
||||
@name = UNSET_VALUE
|
||||
@network_adapters = {}
|
||||
@gui = UNSET_VALUE
|
||||
|
@ -113,6 +121,10 @@ module VagrantPlugins
|
|||
@destroy_unused_network_interfaces = false
|
||||
end
|
||||
|
||||
if @functional_vboxsf == UNSET_VALUE
|
||||
@functional_vboxsf = true
|
||||
end
|
||||
|
||||
# Default is to not show a GUI
|
||||
@gui = false if @gui == UNSET_VALUE
|
||||
|
||||
|
|
|
@ -3,9 +3,10 @@ require "vagrant/util/platform"
|
|||
module VagrantPlugins
|
||||
module ProviderVirtualBox
|
||||
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
|
||||
def usable?(machine)
|
||||
def usable?(machine, raise_errors=false)
|
||||
# These synced folders only work if the provider if VirtualBox
|
||||
machine.provider_name == :virtualbox
|
||||
machine.provider_name == :virtualbox &&
|
||||
machine.provider_config.functional_vboxsf
|
||||
end
|
||||
|
||||
def prepare(machine, folders, _opts)
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
en:
|
||||
docker_provider:
|
||||
creating: |-
|
||||
Creating the container...
|
||||
created: |-
|
||||
Container created: %{id}
|
||||
host_machine_needed: |-
|
||||
Docker host is required. One will be created if necessary...
|
||||
host_machine_ready: |-
|
||||
Docker host VM is already ready.
|
||||
host_machine_starting: |-
|
||||
Vagrant will now create or start a local VM to act as the Docker
|
||||
host. You'll see the output of the `vagrant up` for this VM below.
|
||||
|
||||
messages:
|
||||
destroying: |-
|
||||
Deleting the container...
|
||||
not_created: |-
|
||||
The container hasn't been created yet.
|
||||
not_running: |-
|
||||
The container is not currently running.
|
||||
provision_no_ssh: |-
|
||||
Provisioners will not be run since container doesn't support SSH.
|
||||
will_not_destroy: |-
|
||||
The container will not be destroyed, since the confirmation was declined.
|
||||
starting: |-
|
||||
|
@ -14,6 +30,23 @@ en:
|
|||
container_ready: |-
|
||||
Container started and ready for use!
|
||||
|
||||
status:
|
||||
host_state_unknown: |-
|
||||
The host VM for the Docker containers appears to not be running
|
||||
or is currently inaccessible. Because of this, we can't determine
|
||||
the state of the containers on that host. Run `vagrant up` to
|
||||
bring up the host VM again.
|
||||
not_created: |-
|
||||
The environment has not yet been created. Run `vagrant up` to
|
||||
create the environment. If a machine is not created, only the
|
||||
default provider will be shown. So if a provider is not listed,
|
||||
then the machine is not created for that environment.
|
||||
stopped: |-
|
||||
The container is created but not running. You can run it again
|
||||
with `vagrant up`. If the container always goes to "stopped"
|
||||
right away after being started, it is because the command being
|
||||
run exits and doesn't keep running.
|
||||
|
||||
errors:
|
||||
config:
|
||||
cmd_not_set: |-
|
||||
|
@ -25,6 +58,16 @@ en:
|
|||
and try again.
|
||||
docker_provider_image_not_configured: |-
|
||||
The base Docker image has not been set for the '%{name}' VM!
|
||||
execute_error: |-
|
||||
A Docker command executed by Vagrant didn't complete successfully!
|
||||
The command run along with the output from the command is shown
|
||||
below.
|
||||
|
||||
Command: %{command}
|
||||
|
||||
Stderr: %{stderr}
|
||||
|
||||
Stdout: %{stdout}
|
||||
synced_folder_non_docker: |-
|
||||
The "docker" synced folder type can't be used because the provider
|
||||
in use is not Docker. This synced folder type only works with the
|
||||
|
|
|
@ -1,6 +1,43 @@
|
|||
require_relative "../../../base"
|
||||
|
||||
require "vagrant/util/platform"
|
||||
|
||||
require Vagrant.source_root.join("plugins/providers/docker/config")
|
||||
|
||||
describe VagrantPlugins::DockerProvider::Config do
|
||||
let(:machine) { double("machine") }
|
||||
|
||||
def assert_invalid
|
||||
errors = subject.validate(machine)
|
||||
if !errors.values.any? { |v| !v.empty? }
|
||||
raise "No errors: #{errors.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def assert_valid
|
||||
errors = subject.validate(machine)
|
||||
if !errors.values.all? { |v| v.empty? }
|
||||
raise "Errors: #{errors.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
describe "defaults" do
|
||||
before { subject.finalize! }
|
||||
|
||||
its(:cmd) { should eq([]) }
|
||||
its(:image) { should be_nil }
|
||||
its(:privileged) { should be_false }
|
||||
its(:vagrant_machine) { should be_nil }
|
||||
its(:vagrant_vagrantfile) { should be_nil }
|
||||
end
|
||||
|
||||
before do
|
||||
# By default lets be Linux for validations
|
||||
Vagrant::Util::Platform.stub(linux: true)
|
||||
end
|
||||
|
||||
it "should be valid by default" do
|
||||
subject.finalize!
|
||||
assert_valid
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,6 +11,7 @@ describe VagrantPlugins::ProviderVirtualBox::Config do
|
|||
it { expect(subject.check_guest_additions).to be_true }
|
||||
it { expect(subject.gui).to be_false }
|
||||
it { expect(subject.name).to be_nil }
|
||||
it { expect(subject.functional_vboxsf).to be_true }
|
||||
|
||||
it "should have one NAT adapter" do
|
||||
expect(subject.network_adapters).to eql({
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
require "vagrant"
|
||||
require Vagrant.source_root.join("test/unit/base")
|
||||
|
||||
require Vagrant.source_root.join("plugins/providers/virtualbox/config")
|
||||
require Vagrant.source_root.join("plugins/providers/virtualbox/synced_folder")
|
||||
|
||||
describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do
|
||||
let(:machine) do
|
||||
double("machine").tap do |m|
|
||||
m.stub(provider_config: VagrantPlugins::ProviderVirtualBox::Config.new)
|
||||
m.stub(provider_name: :virtualbox)
|
||||
end
|
||||
end
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
before do
|
||||
machine.provider_config.finalize!
|
||||
end
|
||||
|
||||
describe "usable" do
|
||||
it "should be with virtualbox provider" do
|
||||
machine.stub(provider_name: :virtualbox)
|
||||
|
@ -21,6 +28,11 @@ describe VagrantPlugins::ProviderVirtualBox::SyncedFolder do
|
|||
machine.stub(provider_name: :vmware_fusion)
|
||||
expect(subject).not_to be_usable(machine)
|
||||
end
|
||||
|
||||
it "should not be usable if not functional vboxsf" do
|
||||
machine.provider_config.functional_vboxsf = false
|
||||
expect(subject).to_not be_usable(machine)
|
||||
end
|
||||
end
|
||||
|
||||
describe "prepare" do
|
||||
|
|
|
@ -16,6 +16,20 @@ describe Vagrant::Action::Builder do
|
|||
result
|
||||
end
|
||||
|
||||
def wrapper_proc(data)
|
||||
Class.new do
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
define_method(:call) do |env|
|
||||
env[:data] << "#{data}_in"
|
||||
@app.call(env)
|
||||
env[:data] << "#{data}_out"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "copying" do
|
||||
it "should copy the stack" do
|
||||
copy = subject.dup
|
||||
|
@ -239,4 +253,34 @@ describe Vagrant::Action::Builder do
|
|||
subject.call(data)
|
||||
end
|
||||
end
|
||||
|
||||
describe "calling another app later" do
|
||||
it "calls in the proper order" do
|
||||
# We have to do this because inside the Class.new, it can't see these
|
||||
# rspec methods...
|
||||
described_klass = described_class
|
||||
wrapper_proc = self.method(:wrapper_proc)
|
||||
|
||||
wrapper = Class.new do
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
define_method(:call) do |env|
|
||||
inner = described_klass.new
|
||||
inner.use wrapper_proc[2]
|
||||
inner.use @app
|
||||
inner.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
subject.use wrapper_proc(1)
|
||||
subject.use wrapper
|
||||
subject.use wrapper_proc(3)
|
||||
subject.call(data)
|
||||
|
||||
expect(data[:data]).to eq([
|
||||
"1_in", "2_in", "3_in", "3_out", "2_out", "1_out"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,20 @@ describe Vagrant::Action::Builtin::Call do
|
|||
let(:app) { lambda { |env| } }
|
||||
let(:env) { {} }
|
||||
|
||||
def wrapper_proc(data)
|
||||
Class.new do
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
define_method(:call) do |env|
|
||||
env[:data] << "#{data}_in"
|
||||
@app.call(env)
|
||||
env[:data] << "#{data}_out"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "should yield the env to the block" do
|
||||
received = nil
|
||||
|
||||
|
@ -64,6 +78,23 @@ describe Vagrant::Action::Builtin::Call do
|
|||
expect(received).to eq(:bar)
|
||||
end
|
||||
|
||||
it "should call the next builder inserted in our own stack" do
|
||||
callable = lambda { |env| }
|
||||
|
||||
builder = Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use wrapper_proc(1)
|
||||
b.use described_class, callable do |_env, b2|
|
||||
b2.use wrapper_proc(2)
|
||||
end
|
||||
b.use wrapper_proc(3)
|
||||
end
|
||||
|
||||
env = { data: [] }
|
||||
builder.call(env)
|
||||
expect(env[:data]).to eq([
|
||||
"1_in", "2_in", "3_in", "3_out", "2_out", "1_out"])
|
||||
end
|
||||
|
||||
it "should instantiate the callable with the extra args" do
|
||||
env = {}
|
||||
|
||||
|
|
|
@ -13,8 +13,17 @@ describe Vagrant::Action::Builtin::Message do
|
|||
it "outputs the given message" do
|
||||
subject = described_class.new(app, env, "foo")
|
||||
|
||||
expect(ui).to receive(:output).with("foo")
|
||||
expect(app).to receive(:call).with(env)
|
||||
expect(ui).to receive(:output).with("foo").ordered
|
||||
expect(app).to receive(:call).with(env).ordered
|
||||
|
||||
subject.call(env)
|
||||
end
|
||||
|
||||
it "outputs the given message after the call" do
|
||||
subject = described_class.new(app, env, "foo", post: true)
|
||||
|
||||
expect(app).to receive(:call).with(env).ordered
|
||||
expect(ui).to receive(:output).with("foo").ordered
|
||||
|
||||
subject.call(env)
|
||||
end
|
||||
|
|
|
@ -341,5 +341,10 @@ describe Vagrant::UI::Prefixed do
|
|||
expect(ui).to receive(:output).with("==> #{prefix}: foo", {})
|
||||
subject.output("foo")
|
||||
end
|
||||
|
||||
it "prefixes with another prefix if requested" do
|
||||
expect(ui).to receive(:output).with("==> bar: foo", anything)
|
||||
subject.output("foo", target: "bar")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue