Only one copy of Vagrant can run at any given time. [closes GH-364]
This is to protect against issues with VirtualBox overwriting each other.
This commit is contained in:
parent
79a2ffbf73
commit
874a9763f5
|
@ -25,6 +25,7 @@
|
||||||
- Multiple Chef provisioners no longer overwrite cookbook folders. [GH-407]
|
- Multiple Chef provisioners no longer overwrite cookbook folders. [GH-407]
|
||||||
- `package` won't delete previously existing file. [GH-408]
|
- `package` won't delete previously existing file. [GH-408]
|
||||||
- Vagrantfile can be lowercase now. [GH-399]
|
- Vagrantfile can be lowercase now. [GH-399]
|
||||||
|
- Only one copy of Vagrant may be running at any given time. [GH-364]
|
||||||
|
|
||||||
## 0.7.6 (July 2, 2011)
|
## 0.7.6 (July 2, 2011)
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,10 @@ module Vagrant
|
||||||
@@reported_interrupt = true
|
@@reported_interrupt = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# We place a process lock around every action that is called
|
||||||
|
env.lock do
|
||||||
Busy.busy(int_callback) { callable.call(action_environment) }
|
Busy.busy(int_callback) { callable.call(action_environment) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,7 +60,8 @@ module Vagrant
|
||||||
:parent => nil,
|
:parent => nil,
|
||||||
:vm => nil,
|
:vm => nil,
|
||||||
:cwd => nil,
|
:cwd => nil,
|
||||||
:vagrantfile_name => nil
|
:vagrantfile_name => nil,
|
||||||
|
:lock_path => nil
|
||||||
}.merge(opts || {})
|
}.merge(opts || {})
|
||||||
|
|
||||||
# Set the default working directory to look for the vagrantfile
|
# Set the default working directory to look for the vagrantfile
|
||||||
|
@ -77,6 +78,7 @@ module Vagrant
|
||||||
end
|
end
|
||||||
|
|
||||||
@loaded = false
|
@loaded = false
|
||||||
|
@lock_acquired = false
|
||||||
end
|
end
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
|
@ -281,6 +283,39 @@ module Vagrant
|
||||||
@root_path = root_finder.call(cwd)
|
@root_path = root_finder.call(cwd)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This returns the path which Vagrant uses to determine the location
|
||||||
|
# of the file lock. This is specific to each operating system.
|
||||||
|
def lock_path
|
||||||
|
@lock_path || tmp_path.join("vagrant.lock")
|
||||||
|
end
|
||||||
|
|
||||||
|
# This locks Vagrant for the duration of the block passed to this
|
||||||
|
# method. During this time, any other environment which attempts
|
||||||
|
# to lock which points to the same lock file will fail.
|
||||||
|
def lock
|
||||||
|
# This allows multiple locks in the same process to be nested
|
||||||
|
return yield if @lock_acquired
|
||||||
|
|
||||||
|
File.open(lock_path, "w+") do |f|
|
||||||
|
# The file locking fails only if it returns "false." If it
|
||||||
|
# succeeds it returns a 0, so we must explicitly check for
|
||||||
|
# the proper error case.
|
||||||
|
raise Errors::EnvironmentLockedError if f.flock(File::LOCK_EX | File::LOCK_NB) === false
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Mark that we have a lock
|
||||||
|
@lock_acquired = true
|
||||||
|
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
# We need to make sure that no matter what this is always
|
||||||
|
# reset to false so we don't think we have a lock when we
|
||||||
|
# actually don't.
|
||||||
|
@lock_acquired = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Config Methods
|
# Config Methods
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
|
|
|
@ -153,6 +153,11 @@ module Vagrant
|
||||||
error_key(:status_error, "vagrant.downloaders.http")
|
error_key(:status_error, "vagrant.downloaders.http")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class EnvironmentLockedError < VagrantError
|
||||||
|
status_code(52)
|
||||||
|
error_key(:environment_locked)
|
||||||
|
end
|
||||||
|
|
||||||
class ForwardPortAutolistEmpty < VagrantError
|
class ForwardPortAutolistEmpty < VagrantError
|
||||||
status_code(27)
|
status_code(27)
|
||||||
error_key(:auto_empty, "vagrant.actions.vm.forward_ports")
|
error_key(:auto_empty, "vagrant.actions.vm.forward_ports")
|
||||||
|
|
|
@ -31,6 +31,11 @@ en:
|
||||||
this command in another directory. If you aren't in a home directory,
|
this command in another directory. If you aren't in a home directory,
|
||||||
then please rename ".vagrant" to something else, or configure Vagrant
|
then please rename ".vagrant" to something else, or configure Vagrant
|
||||||
to use another filename by modifying `config.vagrant.dotfile_name`.
|
to use another filename by modifying `config.vagrant.dotfile_name`.
|
||||||
|
environment_locked: |-
|
||||||
|
An instance of Vagrant is already running. Only one instance of Vagrant
|
||||||
|
may run at any given time to avoid problems with VirtualBox inconsistencies
|
||||||
|
occurring. Please wait for the other instance of Vagrant to end and then
|
||||||
|
try again.
|
||||||
interrupted: "Vagrant exited after cleanup due to external interrupt."
|
interrupted: "Vagrant exited after cleanup due to external interrupt."
|
||||||
multi_vm_required: "A multi-vm environment is required for name specification to this command."
|
multi_vm_required: "A multi-vm environment is required for name specification to this command."
|
||||||
multi_vm_target_required: "`vagrant %{command}` requires a specific VM name to target in a multi-VM environment."
|
multi_vm_target_required: "`vagrant %{command}` requires a specific VM name to target in a multi-VM environment."
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
require "pathname"
|
require "pathname"
|
||||||
|
require "tempfile"
|
||||||
|
|
||||||
class EnvironmentTest < Test::Unit::TestCase
|
class EnvironmentTest < Test::Unit::TestCase
|
||||||
setup do
|
setup do
|
||||||
|
@ -291,6 +292,66 @@ class EnvironmentTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "locking" do
|
||||||
|
setup do
|
||||||
|
@instance = @klass.new(:lock_path => Tempfile.new('vagrant-test').path)
|
||||||
|
end
|
||||||
|
|
||||||
|
should "allow nesting locks" do
|
||||||
|
assert_nothing_raised do
|
||||||
|
@instance.lock do
|
||||||
|
@instance.lock do
|
||||||
|
# Nothing
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
should "raise an exception if an environment already has a lock" do
|
||||||
|
@another = @klass.new(:lock_path => @instance.lock_path)
|
||||||
|
|
||||||
|
# Create first locked thread which should succeed
|
||||||
|
first = Thread.new do
|
||||||
|
begin
|
||||||
|
@instance.lock do
|
||||||
|
Thread.current[:locked] = true
|
||||||
|
loop { sleep 1000 }
|
||||||
|
end
|
||||||
|
rescue Vagrant::Errors::EnvironmentLockedError
|
||||||
|
Thread.current[:locked] = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Wait until the first thread has acquired the lock
|
||||||
|
loop do
|
||||||
|
break if first[:locked] || !first.alive?
|
||||||
|
Thread.pass
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verify that the fist got the lock
|
||||||
|
assert first[:locked]
|
||||||
|
|
||||||
|
# Create second locked thread which should fail
|
||||||
|
second = Thread.new do
|
||||||
|
begin
|
||||||
|
@another.lock do
|
||||||
|
Thread.current[:error] = false
|
||||||
|
end
|
||||||
|
rescue Vagrant::Errors::EnvironmentLockedError
|
||||||
|
Thread.current[:error] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Wait for the second to end and verify it failed
|
||||||
|
second.join
|
||||||
|
assert second[:error]
|
||||||
|
|
||||||
|
# Make sure both threads are killed
|
||||||
|
first.kill
|
||||||
|
second.kill
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "accessing the configuration" do
|
context "accessing the configuration" do
|
||||||
should "load the environment if its not already loaded" do
|
should "load the environment if its not already loaded" do
|
||||||
env = @klass.new(:cwd => vagrantfile)
|
env = @klass.new(:cwd => vagrantfile)
|
||||||
|
|
Loading…
Reference in New Issue