Merge pull request #3560 from mitchellh/f-docker-run
docker-run command
This commit is contained in:
commit
ee7d2aa059
|
@ -390,6 +390,7 @@ module Vagrant
|
||||||
# reset to false so we don't think we have a lock when we
|
# reset to false so we don't think we have a lock when we
|
||||||
# actually don't.
|
# actually don't.
|
||||||
@locks.delete(name)
|
@locks.delete(name)
|
||||||
|
@logger.info("Released process lock: #{name}")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Clean up the lock file, this requires another lock
|
# Clean up the lock file, this requires another lock
|
||||||
|
|
|
@ -296,8 +296,13 @@ module Vagrant
|
||||||
target = @prefix
|
target = @prefix
|
||||||
target = opts[:target] if opts.has_key?(:target)
|
target = opts[:target] if opts.has_key?(:target)
|
||||||
|
|
||||||
|
# Get the lines. The first default is because if the message
|
||||||
|
# is an empty string, then we want to still use the empty string.
|
||||||
|
lines = [message]
|
||||||
|
lines = message.split("\n") if message != ""
|
||||||
|
|
||||||
# Otherwise, make sure to prefix every line properly
|
# Otherwise, make sure to prefix every line properly
|
||||||
message.split("\n").map do |line|
|
lines.map do |line|
|
||||||
"#{prefix}#{target}: #{line}"
|
"#{prefix}#{target}: #{line}"
|
||||||
end.join("\n")
|
end.join("\n")
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,32 @@ module VagrantPlugins
|
||||||
# Include the built-in modules so we can use them as top-level things.
|
# Include the built-in modules so we can use them as top-level things.
|
||||||
include Vagrant::Action::Builtin
|
include Vagrant::Action::Builtin
|
||||||
|
|
||||||
|
# This action starts another container just like the real one running
|
||||||
|
# but only for the purpose of running a single command rather than
|
||||||
|
# to exist long-running.
|
||||||
|
def self.action_run_command
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use ConfigValidate
|
||||||
|
|
||||||
|
b.use Call, IsState, :host_state_unknown do |env, b2|
|
||||||
|
if env[:result]
|
||||||
|
raise "Invalid usage"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
b.use Call, IsState, :not_created do |env, b2|
|
||||||
|
if env[:result]
|
||||||
|
b2.use Message,
|
||||||
|
I18n.t("docker_provider.messages.not_created_original")
|
||||||
|
next
|
||||||
|
else
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
b.use action_start
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This action brings the "machine" up from nothing, including creating the
|
# This action brings the "machine" up from nothing, including creating the
|
||||||
# container, configuring metadata, and booting.
|
# container, configuring metadata, and booting.
|
||||||
def self.action_up
|
def self.action_up
|
||||||
|
@ -198,16 +224,18 @@ module VagrantPlugins
|
||||||
def self.action_start
|
def self.action_start
|
||||||
Vagrant::Action::Builder.new.tap do |b|
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
b.use Call, IsState, :running do |env, b2|
|
b.use Call, IsState, :running do |env, b2|
|
||||||
# If the container is running, then our work here is done, exit
|
# If the container is running and we're doing a run, we're done
|
||||||
next if env[:result]
|
next if env[:result] && env[:machine_action] != :run_command
|
||||||
|
|
||||||
b2.use Call, HasSSH do |env2, b3|
|
if env[:machine_action] != :run_command
|
||||||
if env2[:result]
|
b2.use Call, HasSSH do |env2, b3|
|
||||||
b3.use Provision
|
if env2[:result]
|
||||||
else
|
b3.use Provision
|
||||||
b3.use Message,
|
else
|
||||||
I18n.t("docker_provider.messages.provision_no_ssh"),
|
b3.use Message,
|
||||||
post: true
|
I18n.t("docker_provider.messages.provision_no_ssh"),
|
||||||
|
post: true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -224,7 +252,7 @@ module VagrantPlugins
|
||||||
b2.use PrepareNFSSettings
|
b2.use PrepareNFSSettings
|
||||||
b2.use Build
|
b2.use Build
|
||||||
|
|
||||||
# If the VM is NOT created yet, then do some setup steps
|
# If the container is NOT created yet, then do some setup steps
|
||||||
# necessary for creating it.
|
# necessary for creating it.
|
||||||
b2.use Call, IsState, :not_created do |env2, b3|
|
b2.use Call, IsState, :not_created do |env2, b3|
|
||||||
if env2[:result]
|
if env2[:result]
|
||||||
|
@ -240,12 +268,18 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
b2.use Start
|
# If we're doing a one-off command, then we create
|
||||||
b2.use WaitForRunning
|
if env[:machine_action] == :run_command
|
||||||
|
b2.use SyncedFolders
|
||||||
|
b2.use Create
|
||||||
|
else
|
||||||
|
b2.use Start
|
||||||
|
b2.use WaitForRunning
|
||||||
|
|
||||||
b2.use Call, HasSSH do |env2, b3|
|
b2.use Call, HasSSH do |env2, b3|
|
||||||
if env2[:result]
|
if env2[:result]
|
||||||
b3.use WaitForCommunicator
|
b3.use WaitForCommunicator
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,9 +15,27 @@ module VagrantPlugins
|
||||||
|
|
||||||
params = create_params
|
params = create_params
|
||||||
|
|
||||||
|
# If we're running a single command, we modify the params a bit
|
||||||
|
if env[:machine_action] == :run_command
|
||||||
|
# Use the command that is given to us
|
||||||
|
params[:cmd] = env[:run_command]
|
||||||
|
|
||||||
|
# Don't detach, we want to watch the command run
|
||||||
|
params[:detach] = false
|
||||||
|
|
||||||
|
# No ports should be shared to the host
|
||||||
|
params[:ports] = []
|
||||||
|
|
||||||
|
# We link to our original container
|
||||||
|
# TODO
|
||||||
|
end
|
||||||
|
|
||||||
env[:ui].output(I18n.t("docker_provider.creating"))
|
env[:ui].output(I18n.t("docker_provider.creating"))
|
||||||
env[:ui].detail(" Name: #{params[:name]}")
|
env[:ui].detail(" Name: #{params[:name]}")
|
||||||
env[:ui].detail(" Image: #{params[:image]}")
|
env[:ui].detail(" Image: #{params[:image]}")
|
||||||
|
if params[:cmd]
|
||||||
|
env[:ui].detail(" Cmd: #{params[:cmd].join(" ")}")
|
||||||
|
end
|
||||||
params[:volumes].each do |volume|
|
params[:volumes].each do |volume|
|
||||||
env[:ui].detail("Volume: #{volume}")
|
env[:ui].detail("Volume: #{volume}")
|
||||||
end
|
end
|
||||||
|
@ -28,12 +46,23 @@ module VagrantPlugins
|
||||||
env[:ui].detail(" Link: #{name}:#{other}")
|
env[:ui].detail(" Link: #{name}:#{other}")
|
||||||
end
|
end
|
||||||
|
|
||||||
cid = @driver.create(params)
|
if env[:machine_action] != :run_command
|
||||||
|
# For regular "ups" create it and get the CID
|
||||||
|
cid = @driver.create(params)
|
||||||
|
env[:ui].detail(" \n"+I18n.t(
|
||||||
|
"docker_provider.created", id: cid[0...16]))
|
||||||
|
@machine.id = cid
|
||||||
|
elsif params[:detach]
|
||||||
|
env[:ui].detail(" \n"+I18n.t("docker_provider.running_detached"))
|
||||||
|
else
|
||||||
|
# For run commands, we run it and stream back the output
|
||||||
|
env[:ui].detail(" \n"+I18n.t("docker_provider.running")+"\n ")
|
||||||
|
@driver.create(params) do |type, data|
|
||||||
|
env[:ui].detail(data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
env[:ui].detail(" \n"+I18n.t(
|
@app.call(env)
|
||||||
"docker_provider.created", id: cid[0...16]))
|
|
||||||
@machine.id = cid
|
|
||||||
@app.call(env)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_params
|
def create_params
|
||||||
|
@ -55,7 +84,9 @@ module VagrantPlugins
|
||||||
|
|
||||||
{
|
{
|
||||||
cmd: @provider_config.cmd,
|
cmd: @provider_config.cmd,
|
||||||
|
detach: true,
|
||||||
env: @provider_config.env,
|
env: @provider_config.env,
|
||||||
|
expose: @provider_config.expose,
|
||||||
extra_args: @provider_config.create_args,
|
extra_args: @provider_config.create_args,
|
||||||
hostname: @machine_config.vm.hostname,
|
hostname: @machine_config.vm.hostname,
|
||||||
image: image,
|
image: image,
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module DockerProvider
|
||||||
|
module Command
|
||||||
|
class Run < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"run a one-off command in the context of a container"
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
options[:detach] = false
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant docker-run [command...]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Options:"
|
||||||
|
o.separator ""
|
||||||
|
|
||||||
|
o.on("--[no-]detach", "Run in the background") do |d|
|
||||||
|
options[:detach] = d
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse out the extra args to send to SSH, which is everything
|
||||||
|
# after the "--"
|
||||||
|
split_index = @argv.index("--")
|
||||||
|
if !split_index
|
||||||
|
@env.ui.error(I18n.t("docker_provider.run_command_required"))
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
command = @argv.drop(split_index + 1)
|
||||||
|
@argv = @argv.take(split_index)
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
any_success = false
|
||||||
|
with_target_vms(argv) do |machine|
|
||||||
|
if machine.provider_name != :docker
|
||||||
|
machine.ui.output(I18n.t("docker_provider.not_docker_provider"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
state = machine.state
|
||||||
|
if state == :host_state_unknown
|
||||||
|
machine.ui.output(I18n.t("docker_provider.logs_host_state_unknown"))
|
||||||
|
next
|
||||||
|
elsif state == :not_created
|
||||||
|
machine.ui.output(I18n.t("docker_provider.not_created_skip"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
# At least one was run!
|
||||||
|
any_success = true
|
||||||
|
|
||||||
|
# Run it!
|
||||||
|
machine.action(
|
||||||
|
:run_command,
|
||||||
|
run_command: command,
|
||||||
|
run_detach: options[:detach])
|
||||||
|
end
|
||||||
|
|
||||||
|
return any_success ? 0 : 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -22,6 +22,12 @@ module VagrantPlugins
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
attr_accessor :env
|
attr_accessor :env
|
||||||
|
|
||||||
|
# Ports to expose from the container but not to the host machine.
|
||||||
|
# This is useful for links.
|
||||||
|
#
|
||||||
|
# @return [Array<Integer>]
|
||||||
|
attr_accessor :expose
|
||||||
|
|
||||||
# Force using a proxy VM, even on Linux hosts.
|
# Force using a proxy VM, even on Linux hosts.
|
||||||
#
|
#
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
|
@ -71,6 +77,7 @@ module VagrantPlugins
|
||||||
@cmd = UNSET_VALUE
|
@cmd = UNSET_VALUE
|
||||||
@create_args = []
|
@create_args = []
|
||||||
@env = {}
|
@env = {}
|
||||||
|
@expose = []
|
||||||
@force_host_vm = UNSET_VALUE
|
@force_host_vm = UNSET_VALUE
|
||||||
@has_ssh = UNSET_VALUE
|
@has_ssh = UNSET_VALUE
|
||||||
@image = UNSET_VALUE
|
@image = UNSET_VALUE
|
||||||
|
@ -108,6 +115,10 @@ module VagrantPlugins
|
||||||
env.merge!(other.env) if other.env
|
env.merge!(other.env) if other.env
|
||||||
result.env = env
|
result.env = env
|
||||||
|
|
||||||
|
expose = self.expose.dup
|
||||||
|
expose += other.expose
|
||||||
|
result.instance_variable_set(:@expose, expose)
|
||||||
|
|
||||||
links = _links.dup
|
links = _links.dup
|
||||||
links += other._links
|
links += other._links
|
||||||
result.instance_variable_set(:@links, links)
|
result.instance_variable_set(:@links, links)
|
||||||
|
@ -127,6 +138,8 @@ module VagrantPlugins
|
||||||
@remains_running = true if @remains_running == UNSET_VALUE
|
@remains_running = true if @remains_running == UNSET_VALUE
|
||||||
@vagrant_machine = nil if @vagrant_machine == UNSET_VALUE
|
@vagrant_machine = nil if @vagrant_machine == UNSET_VALUE
|
||||||
@vagrant_vagrantfile = nil if @vagrant_vagrantfile == UNSET_VALUE
|
@vagrant_vagrantfile = nil if @vagrant_vagrantfile == UNSET_VALUE
|
||||||
|
|
||||||
|
@expose.uniq!
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate(machine)
|
def validate(machine)
|
||||||
|
|
|
@ -25,7 +25,7 @@ module VagrantPlugins
|
||||||
match[1]
|
match[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
def create(params)
|
def create(params, &block)
|
||||||
image = params.fetch(:image)
|
image = params.fetch(:image)
|
||||||
links = params.fetch(:links)
|
links = params.fetch(:links)
|
||||||
ports = Array(params[:ports])
|
ports = Array(params[:ports])
|
||||||
|
@ -33,9 +33,12 @@ module VagrantPlugins
|
||||||
name = params.fetch(:name)
|
name = params.fetch(:name)
|
||||||
cmd = Array(params.fetch(:cmd))
|
cmd = Array(params.fetch(:cmd))
|
||||||
env = params.fetch(:env)
|
env = params.fetch(:env)
|
||||||
|
expose = Array(params[:expose])
|
||||||
|
|
||||||
run_cmd = %W(docker run --name #{name} -d)
|
run_cmd = %W(docker run --name #{name})
|
||||||
|
run_cmd << "-d" if params[:detach]
|
||||||
run_cmd += env.map { |k,v| ['-e', "#{k}=#{v}"] }
|
run_cmd += env.map { |k,v| ['-e', "#{k}=#{v}"] }
|
||||||
|
run_cmd += expose.map { |p| ['--expose', "#{p}"] }
|
||||||
run_cmd += links.map { |k, v| ['--link', "#{k}:#{v}"] }
|
run_cmd += links.map { |k, v| ['--link', "#{k}:#{v}"] }
|
||||||
run_cmd += ports.map { |p| ['-p', p.to_s] }
|
run_cmd += ports.map { |p| ['-p', p.to_s] }
|
||||||
run_cmd += volumes.map { |v| ['-v', v.to_s] }
|
run_cmd += volumes.map { |v| ['-v', v.to_s] }
|
||||||
|
@ -44,7 +47,7 @@ module VagrantPlugins
|
||||||
run_cmd += params[:extra_args] if params[:extra_args]
|
run_cmd += params[:extra_args] if params[:extra_args]
|
||||||
run_cmd += [image, cmd]
|
run_cmd += [image, cmd]
|
||||||
|
|
||||||
execute(*run_cmd.flatten).chomp
|
execute(*run_cmd.flatten, &block).chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
def state(cid)
|
def state(cid)
|
||||||
|
|
|
@ -20,7 +20,7 @@ module VagrantPlugins
|
||||||
# We have to do this because boot2docker outputs a login shell
|
# We have to do this because boot2docker outputs a login shell
|
||||||
# boot2docker version that we get otherwise and messes up output.
|
# boot2docker version that we get otherwise and messes up output.
|
||||||
start_fence = "========== VAGRANT DOCKER BEGIN =========="
|
start_fence = "========== VAGRANT DOCKER BEGIN =========="
|
||||||
ssh_cmd = "echo \"#{start_fence}\"; #{cmd}"
|
ssh_cmd = "echo -n \"#{start_fence}\"; #{cmd}"
|
||||||
|
|
||||||
stderr = ""
|
stderr = ""
|
||||||
stdout = ""
|
stdout = ""
|
||||||
|
@ -42,8 +42,8 @@ module VagrantPlugins
|
||||||
|
|
||||||
# We're now fenced, send all the data through
|
# We're now fenced, send all the data through
|
||||||
if block
|
if block
|
||||||
block.call(:stdout, stdout)
|
block.call(:stdout, stdout) if stdout != ""
|
||||||
block.call(:stderr, stderr)
|
block.call(:stderr, stderr) if stderr != ""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -28,6 +28,12 @@ module VagrantPlugins
|
||||||
Command::Logs
|
Command::Logs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
command("docker-run", primary: false) do
|
||||||
|
require_relative "command/run"
|
||||||
|
init!
|
||||||
|
Command::Run
|
||||||
|
end
|
||||||
|
|
||||||
communicator(:docker_hostvm) do
|
communicator(:docker_hostvm) do
|
||||||
require_relative "communicator"
|
require_relative "communicator"
|
||||||
init!
|
init!
|
||||||
|
|
|
@ -56,9 +56,8 @@ module VagrantPlugins
|
||||||
|
|
||||||
# Returns the SSH info for accessing the VirtualBox VM.
|
# Returns the SSH info for accessing the VirtualBox VM.
|
||||||
def ssh_info
|
def ssh_info
|
||||||
# If the VM is not created then we cannot possibly SSH into it, so
|
# If the VM is not running that we can't possibly SSH into it
|
||||||
# we return nil.
|
return nil if state.id != :running
|
||||||
return nil if state.id == :not_created
|
|
||||||
|
|
||||||
# Return what we know. The host is always "127.0.0.1" because
|
# Return what we know. The host is always "127.0.0.1" because
|
||||||
# VirtualBox VMs are always local. The port we try to discover
|
# VirtualBox VMs are always local. The port we try to discover
|
||||||
|
|
|
@ -37,6 +37,18 @@ en:
|
||||||
Container not created. Skipping.
|
Container not created. Skipping.
|
||||||
not_docker_provider: |-
|
not_docker_provider: |-
|
||||||
Not backed by Docker provider. Skipping.
|
Not backed by Docker provider. Skipping.
|
||||||
|
run_command_required: |-
|
||||||
|
`vagrant docker-run` requires a command to execute. This command
|
||||||
|
must be specified after a `--` in the command line. This is used
|
||||||
|
to separate possible machine names and options from the actual
|
||||||
|
command to execute. An example is shown below:
|
||||||
|
|
||||||
|
vagrant docker-run web -- rails new .
|
||||||
|
|
||||||
|
running: |-
|
||||||
|
Container is starting. Output will stream in below...
|
||||||
|
running_detached: |-
|
||||||
|
Container is started detached.
|
||||||
ssh_through_host_vm: |-
|
ssh_through_host_vm: |-
|
||||||
SSH will be proxied through the Docker virtual machine since we're
|
SSH will be proxied through the Docker virtual machine since we're
|
||||||
not running Docker natively. This is just a notice, and not an error.
|
not running Docker natively. This is just a notice, and not an error.
|
||||||
|
@ -52,6 +64,9 @@ en:
|
||||||
Deleting the container...
|
Deleting the container...
|
||||||
not_created: |-
|
not_created: |-
|
||||||
The container hasn't been created yet.
|
The container hasn't been created yet.
|
||||||
|
not_created_original: |-
|
||||||
|
The original container hasn't been created yet. Run `vagrant up`
|
||||||
|
for this machine first.
|
||||||
not_running: |-
|
not_running: |-
|
||||||
The container is not currently running.
|
The container is not currently running.
|
||||||
provision_no_ssh: |-
|
provision_no_ssh: |-
|
||||||
|
|
|
@ -39,6 +39,7 @@ describe VagrantPlugins::DockerProvider::Config do
|
||||||
before { subject.finalize! }
|
before { subject.finalize! }
|
||||||
|
|
||||||
its(:build_dir) { should be_nil }
|
its(:build_dir) { should be_nil }
|
||||||
|
its(:expose) { should eq([]) }
|
||||||
its(:cmd) { should eq([]) }
|
its(:cmd) { should eq([]) }
|
||||||
its(:env) { should eq({}) }
|
its(:env) { should eq({}) }
|
||||||
its(:force_host_vm) { should be_false }
|
its(:force_host_vm) { should be_false }
|
||||||
|
@ -82,6 +83,20 @@ describe VagrantPlugins::DockerProvider::Config do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#expose" do
|
||||||
|
before do
|
||||||
|
valid_defaults
|
||||||
|
end
|
||||||
|
|
||||||
|
it "uniqs the ports" do
|
||||||
|
subject.expose = [1, 1, 4, 5]
|
||||||
|
subject.finalize!
|
||||||
|
assert_valid
|
||||||
|
|
||||||
|
expect(subject.expose).to eq([1, 4, 5])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "#image" do
|
describe "#image" do
|
||||||
it "should be valid if set" do
|
it "should be valid if set" do
|
||||||
subject.image = "foo"
|
subject.image = "foo"
|
||||||
|
@ -166,6 +181,16 @@ describe VagrantPlugins::DockerProvider::Config do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "exposed ports" do
|
||||||
|
it "merges the exposed ports" do
|
||||||
|
one.expose << 1234
|
||||||
|
two.expose = [42, 54]
|
||||||
|
|
||||||
|
expect(subject.expose).to eq([
|
||||||
|
1234, 42, 54])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "links" do
|
context "links" do
|
||||||
it "should merge the links" do
|
it "should merge the links" do
|
||||||
one.link "foo"
|
one.link "foo"
|
||||||
|
|
Loading…
Reference in New Issue