providers/docker: use a custom communicator to go through host VM

This commit is contained in:
Mitchell Hashimoto 2014-04-15 20:52:06 -07:00
parent bdade7d5a6
commit e947960c09
6 changed files with 106 additions and 1 deletions

View File

@ -23,7 +23,7 @@ module Vagrant
#
# @return [Boolean]
def self.match?(machine)
false
true
end
# Initializes the communicator with the machine that we will be

View File

@ -0,0 +1,83 @@
module VagrantPlugins
module DockerProvider
# This communicator uses the host VM as proxy to communicate to the
# actual Docker container via SSH.
class Communicator < Vagrant.plugin("2", :communicator)
def initialize(machine)
@machine = machine
@host_vm = machine.provider.host_vm
# We only work on the Docker provider
if machine.provider_name != :docker
raise Errors::CommunicatorNotDocker
end
end
#-------------------------------------------------------------------
# Communicator Methods
#-------------------------------------------------------------------
def ready?
# We can't be ready if we can't talk to the host VM
return false if !@host_vm.communicate.ready?
# We're ready if we can establish an SSH connection to the container
@host_vm.communicate.test("#{container_ssh_command} exit")
end
def download(from, to)
raise "NOT IMPLEMENTED YET"
end
def execute(command, opts=nil, &block)
@host_vm.communicate.execute(
"#{container_ssh_command} #{command}", opts, &block)
end
def sudo(command, opts=nil)
end
def test(command, **opts)
opts = { error_check: false }.merge(opts)
execute(command, opts) == 0
end
def upload(from, to)
# First, we upload this to the host VM to some temporary directory.
to_temp = "/tmp/docker_#{Time.now.to_i}_#{rand(100000)}"
@host_vm.communicate.upload(from, to_temp)
# Then, we use `cat` to get that file into the Docker container.
@host_vm.communicate.execute(
"#{container_ssh_command} 'cat >#{to}' <#{to_temp}")
# Remove the temporary file
@host_vm.communicate.execute("rm #{to_temp}", error_check: false)
end
#-------------------------------------------------------------------
# Other Methods
#-------------------------------------------------------------------
# This returns the raw SSH command string that can be used to
# connect via SSH to the container if you're on the same machine
# as the container.
#
# @return [String]
def container_ssh_command
# Get the container's SSH info
info = @machine.ssh_info
info[:port] ||= 22
# Build the SSH command
"ssh -i /home/vagrant/insecure " +
"-o Compression=yes " +
"-o ConnectTimeout=5 " +
"-o StrictHostKeyChecking=no " +
"-o UserKnownHostsFile=/dev/null " +
"-p#{info[:port]} " +
"#{info[:username]}@#{info[:host]}"
end
end
end
end

View File

@ -5,6 +5,10 @@ module VagrantPlugins
error_namespace("docker_provider.errors")
end
class CommunicatorNonDocker < DockerError
error_key(:communicator_non_docker)
end
class ExecuteError < DockerError
error_key(:execute_error)
end

View File

@ -28,6 +28,12 @@ module VagrantPlugins
Command::Logs
end
communicator(:docker_hostvm) do
require_relative "communicator"
init!
Communicator
end
config(:docker, :provider) do
require_relative 'config'
init!

View File

@ -11,6 +11,12 @@ module VagrantPlugins
def initialize(machine)
@logger = Log4r::Logger.new("vagrant::provider::docker")
@machine = machine
if host_vm?
# We need to use a special communicator that proxies our
# SSH requests over our host VM to the container itself.
@machine.config.vm.communicator = :docker_hostvm
end
end
# @see Vagrant::Plugin::V2::Provider#action

View File

@ -63,6 +63,12 @@ en:
run exits and doesn't keep running.
errors:
communicator_non_docker: |-
The "docker_hostvm" communicator was specified on a machine that
is not provided by the Docker provider. This is a bug with your
Vagrantfile. Please contact the creator of your Vagrant environment
and notify them to not use this communicator for anything except the
"docker" provider.
config:
cmd_not_set: |-
The Docker command has not been set!