core: commands can use the IDs from anywhere to control

This commit is contained in:
Mitchell Hashimoto 2014-03-14 17:35:56 -07:00
parent 9a16af10ad
commit a0e9f46251
5 changed files with 125 additions and 28 deletions

View File

@ -108,9 +108,11 @@ module Vagrant
@lock.synchronize do
with_index_lock do
return nil if !@machines[uuid]
data = find_by_prefix(uuid)
return nil if !data
uuid = data["id"]
entry = Entry.new(uuid, @machines[uuid].merge("id" => uuid))
entry = Entry.new(uuid, data)
# Lock this machine
lock_file = lock_machine(uuid)
@ -127,6 +129,14 @@ module Vagrant
entry
end
# Tests if the index has the given UUID.
#
# @param [String] uuid
# @return [Boolean]
def include?(uuid)
!!find_by_prefix(uuid)
end
# Releases an entry, unlocking it.
#
# This is an idempotent operation. It is safe to call this even if you're
@ -192,6 +202,17 @@ module Vagrant
protected
# Finds a machine where the UUID is prefixed by the given string.
#
# @return [Hash]
def find_by_prefix(prefix)
@machines.each do |uuid, data|
return data.merge("id" => uuid) if uuid.start_with?(prefix)
end
nil
end
# Locks a machine exclusively to us, returning the file handle
# that holds the lock.
#

View File

@ -82,9 +82,6 @@ module Vagrant
@logger.debug(" -- names: #{names.inspect}")
@logger.debug(" -- options: #{options.inspect}")
# Using VMs requires a Vagrant environment to be properly setup
raise Errors::NoEnvironmentError if !@env.root_path
# Setup the options hash
options ||= {}
@ -92,6 +89,21 @@ module Vagrant
names ||= []
names = [names] if !names.is_a?(Array)
# Determine if we require a local Vagrant environment. There are
# two cases that we require a local environment:
#
# * We're asking for ANY/EVERY VM (no names given).
#
# * We're asking for specific VMs, at least once of which
# is NOT in the local machine index.
#
requires_local_env = false
requires_local_env = true if names.empty?
requires_local_env ||= names.any? { |n|
!@env.machine_index.include?(n)
}
raise Errors::NoEnvironmentError if requires_local_env && !@env.root_path
# Cache the active machines outside the loop
active_machines = @env.active_machines
@ -112,6 +124,20 @@ module Vagrant
provider_to_use = options[:provider]
provider_to_use = provider_to_use.to_sym if provider_to_use
# If we have this machine in our index, load that.
entry = @env.machine_index.get(name.to_s)
if entry
@env.machine_index.release(entry)
# Create an environment for this location and yield the
# machine in that environment.
env = Vagrant::Environment.new(
cwd: entry.vagrantfile_path,
home_path: @env.home_path,
)
next env.machine(entry.name.to_sym, entry.provider.to_sym)
end
active_machines.each do |active_name, active_provider|
if name == active_name
# We found an active machine with the same name

View File

@ -800,9 +800,11 @@ en:
%{types}
no_env: |-
A Vagrant environment is required to run this command. Run `vagrant init`
to set one up in this directory, or change to a directory with a
Vagrantfile and try again.
A Vagrant environment or target machine is required to run this
command. Run `vagrant init` to create a new Vagrant environment. Or,
get an ID of a target machine from `vagrant global-status` to run
this command on. A final option is to change to a directory with a
Vagrantfile and to try again.
plugin_gem_not_found: |-
The plugin '%{name}' could not be installed because it could not
be found. Please double check the name and try again.

View File

@ -12,6 +12,13 @@ describe Vagrant::MachineIndex do
let(:data_dir) { temporary_dir }
let(:entry_klass) { Vagrant::MachineIndex::Entry }
let(:new_entry) do
entry_klass.new.tap do |e|
e.name = "foo"
e.vagrantfile_path = "/bar"
end
end
subject { described_class.new(data_dir) }
it "raises an exception if the data file is corrupt" do
@ -96,6 +103,17 @@ describe Vagrant::MachineIndex do
expect(result.updated_at).to eq("foo")
end
it "returns a valid entry by unique prefix" do
result = subject.get("b")
expect(result).to_not be_nil
expect(result.id).to eq("bar")
end
it "should include? by prefix" do
expect(subject.include?("b")).to be_true
end
it "locks the entry so subsequent gets fail" do
result = subject.get("bar")
expect(result).to_not be_nil
@ -114,14 +132,22 @@ describe Vagrant::MachineIndex do
end
end
describe "#set and #get and #delete" do
let(:new_entry) do
entry_klass.new.tap do |e|
e.name = "foo"
e.vagrantfile_path = "/bar"
end
describe "#include" do
it "should not include non-existent things" do
expect(subject.include?("foo")).to be_false
end
it "should include created entries" do
result = subject.set(new_entry)
expect(result.id).to_not be_empty
subject.release(result)
subject = described_class.new(data_dir)
expect(subject.include?(result.id)).to be_true
end
end
describe "#set and #get and #delete" do
it "adds a new entry" do
result = subject.set(new_entry)
expect(result.id).to_not be_empty

View File

@ -2,6 +2,8 @@ require File.expand_path("../../../../base", __FILE__)
require 'optparse'
describe Vagrant::Plugin::V2::Command do
include_context "unit"
describe "parsing options" do
let(:klass) do
Class.new(described_class) do
@ -53,18 +55,17 @@ describe Vagrant::Plugin::V2::Command do
end
end
let(:default_provider) { :virtualbox }
let(:environment) do
env = double("environment")
env.stub(:active_machines => [])
env.stub(:default_provider => default_provider)
env.stub(:root_path => "foo")
env
# We have to create a Vagrantfile so there is a root path
test_iso_env.vagrantfile("")
test_iso_env.create_vagrant_env
end
let(:test_iso_env) { isolated_environment }
let(:instance) { klass.new([], environment) }
subject { instance }
it "should raise an exception if a root_path is not available" do
environment.stub(:root_path => nil)
@ -82,8 +83,8 @@ describe Vagrant::Plugin::V2::Command do
bar_vm.stub(ui: Vagrant::UI::Silent.new)
environment.stub(:machine_names => [:foo, :bar])
allow(environment).to receive(:machine).with(:foo, default_provider).and_return(foo_vm)
allow(environment).to receive(:machine).with(:bar, default_provider).and_return(bar_vm)
allow(environment).to receive(:machine).with(:foo, environment.default_provider).and_return(foo_vm)
allow(environment).to receive(:machine).with(:bar, environment.default_provider).and_return(bar_vm)
vms = []
instance.with_target_vms do |vm|
@ -106,7 +107,7 @@ describe Vagrant::Plugin::V2::Command do
foo_vm.stub(:name => "foo", :provider => :foobarbaz)
foo_vm.stub(ui: Vagrant::UI::Silent.new)
allow(environment).to receive(:machine).with(:foo, default_provider).and_return(foo_vm)
allow(environment).to receive(:machine).with(:foo, environment.default_provider).and_return(foo_vm)
vms = []
instance.with_target_vms("foo") { |vm| vms << vm }
@ -167,8 +168,8 @@ describe Vagrant::Plugin::V2::Command do
name = :foo
machine = double("machine")
allow(environment).to receive(:machine).with(name, default_provider).and_return(machine)
machine.stub(:name => name, :provider => default_provider)
allow(environment).to receive(:machine).with(name, environment.default_provider).and_return(machine)
machine.stub(:name => name, :provider => environment.default_provider)
machine.stub(ui: Vagrant::UI::Silent.new)
results = []
@ -198,16 +199,37 @@ describe Vagrant::Plugin::V2::Command do
machine = double("machine")
environment.stub(:active_machines => [])
allow(environment).to receive(:machine).with(name, default_provider).and_return(machine)
allow(environment).to receive(:machine).with(name, environment.default_provider).and_return(machine)
environment.stub(:machine_names => [])
environment.stub(:primary_machine_name => name)
machine.stub(:name => name, :provider => default_provider)
machine.stub(:name => name, :provider => environment.default_provider)
machine.stub(ui: Vagrant::UI::Silent.new)
vms = []
instance.with_target_vms(nil, :single_target => true) { |vm| vms << machine }
expect(vms).to eq([machine])
end
it "should yield machines from another environment" do
iso_env = isolated_environment
iso_env.vagrantfile("")
other_env = iso_env.create_vagrant_env(
home_path: environment.home_path)
other_machine = other_env.machine(
other_env.machine_names[0], other_env.default_provider)
# Set an ID on it so that it is "created" in the index
other_machine.id = "foo"
# Make sure we don't have a root path, to test
environment.stub(root_path: nil)
results = []
subject.with_target_vms(other_machine.index_uuid) { |m| results << m }
expect(results.length).to eq(1)
expect(results[0].id).to eq(other_machine.id)
end
end
describe "splitting the main and subcommand args" do