`vagrant up`!

This commit is contained in:
Mitchell Hashimoto 2012-08-14 22:38:41 -07:00
parent aaeb060f33
commit b659191a02
12 changed files with 300 additions and 40 deletions

View File

@ -184,6 +184,10 @@ module Vagrant
# Store the ID locally
@id = value
# Notify the provider that the ID changed in case it needs to do
# any accounting from it.
@provider.machine_id_changed
end
# This returns a clean inspect value so that printing the value via

View File

@ -21,6 +21,15 @@ module Vagrant
nil
end
# This method is called if the underying machine ID changes. Providers
# can use this method to load in new data for the actual backing
# machine or to realize that the machine is now gone (the ID can
# become `nil`). No parameters are given, since the underlying machine
# is simply the machine instance given to this object. And no
# return value is necessary.
def machine_id_changed
end
# This should return a hash of information that explains how to
# SSH into the machine. If the machine is not at a point where
# SSH is even possible, then `nil` should be returned.

View File

@ -11,10 +11,10 @@ module VagrantPlugins
def execute
options = {}
opts = OptionParser.new do |opts|
opts.banner = "Usage: vagrant up [vm-name] [--[no-]provision] [-h]"
opts.separator ""
build_start_options(opts, options)
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant up [vm-name] [--[no-]provision] [-h]"
o.separator ""
build_start_options(o, options)
end
# Parse the options
@ -23,20 +23,13 @@ module VagrantPlugins
# Go over each VM and bring it up
@logger.debug("'Up' each target VM...")
with_target_vms(argv) do |vm|
if vm.created?
@logger.info("Booting: #{vm.name}")
vm.ui.info I18n.t("vagrant.commands.up.vm_created")
vm.start(options)
else
@logger.info("Creating: #{vm.name}")
vm.up(options)
end
with_target_vms(argv) do |machine|
machine.action(:up)
end
# Success, exit status 0
0
end
end
end
end
end

View File

@ -5,7 +5,9 @@ module VagrantPlugins
module Action
autoload :Boot, File.expand_path("../action/boot", __FILE__)
autoload :CheckAccessible, File.expand_path("../action/check_accessible", __FILE__)
autoload :CheckBox, File.expand_path("../action/check_box", __FILE__)
autoload :CheckCreated, File.expand_path("../action/check_created", __FILE__)
autoload :CheckGuestAdditions, File.expand_path("../action/check_guest_additions", __FILE__)
autoload :CheckPortCollisions, File.expand_path("../action/check_port_collisions", __FILE__)
autoload :CheckRunning, File.expand_path("../action/check_running", __FILE__)
autoload :CheckVirtualbox, File.expand_path("../action/check_virtualbox", __FILE__)
@ -15,6 +17,7 @@ module VagrantPlugins
autoload :ClearSharedFolders, File.expand_path("../action/clear_shared_folders", __FILE__)
autoload :Created, File.expand_path("../action/created", __FILE__)
autoload :Customize, File.expand_path("../action/customize", __FILE__)
autoload :DefaultName, File.expand_path("../action/default_name", __FILE__)
autoload :Destroy, File.expand_path("../action/destroy", __FILE__)
autoload :DestroyConfirm, File.expand_path("../action/destroy_confirm", __FILE__)
autoload :DestroyUnusedNetworkInterfaces, File.expand_path("../action/destroy_unused_network_interfaces", __FILE__)
@ -22,7 +25,10 @@ module VagrantPlugins
autoload :ForwardPorts, File.expand_path("../action/forward_ports", __FILE__)
autoload :Halt, File.expand_path("../action/halt", __FILE__)
autoload :HostName, File.expand_path("../action/host_name", __FILE__)
autoload :Import, File.expand_path("../action/import", __FILE__)
autoload :IsRunning, File.expand_path("../action/is_running", __FILE__)
autoload :IsSaved, File.expand_path("../action/is_saved", __FILE__)
autoload :MatchMACAddress, File.expand_path("../action/match_mac_address", __FILE__)
autoload :MessageNotCreated, File.expand_path("../action/message_not_created", __FILE__)
autoload :MessageNotRunning, File.expand_path("../action/message_not_running", __FILE__)
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
@ -40,6 +46,29 @@ module VagrantPlugins
# things.
include Vagrant::Action::Builtin
# This action boots the VM, assuming the VM is in a state that requires
# a bootup (i.e. not saved).
def self.action_boot
Vagrant::Action::Builder.new.tap do |b|
b.use CheckAccessible
b.use CleanMachineFolder
b.use ClearForwardedPorts
b.use EnvSet, :port_collision_handler => :correct
b.use ForwardPorts
b.use Provision
b.use PruneNFSExports
b.use NFS
b.use ClearSharedFolders
b.use ShareFolders
b.use ClearNetworkInterfaces
b.use Network
b.use HostName
b.use SaneDefaults
b.use Customize
b.use Boot
end
end
# This is the action that is primarily responsible for completely
# freeing the resources of the underlying virtual machine.
def self.action_destroy
@ -175,22 +204,21 @@ module VagrantPlugins
Vagrant::Action::Builder.new.tap do |b|
b.use CheckVirtualbox
b.use Vagrant::Action::General::Validate
b.use CheckAccessible
b.use CleanMachineFolder
b.use ClearForwardedPorts
b.use EnvSet, :port_collision_handler => :correct
b.use ForwardPorts
b.use Provision
b.use PruneNFSExports
b.use NFS
b.use ClearSharedFolders
b.use ShareFolders
b.use ClearNetworkInterfaces
b.use Network
b.use HostName
b.use SaneDefaults
b.use Customize
b.use Boot
b.use Call, IsRunning do |env, b2|
# If the VM is running, then our work here is done, exit
next if env[:result]
b2.use Call, IsSaved do |env2, b3|
if env2[:result]
# The VM is saved, so just resume it
b3.use action_resume
else
# The VM is not saved, so we must have to boot it up
# like normal. Boot!
b3.use action_boot
end
end
end
end
end
@ -209,6 +237,27 @@ module VagrantPlugins
end
end
end
# This action brings the machine up from nothing, including importing
# the box, configuring metadata, and booting.
def self.action_up
Vagrant::Action::Builder.new.tap do |b|
b.use CheckVirtualbox
b.use Vagrant::Action::General::Validate
b.use Call, Created do |env, b2|
# If the VM is NOT created yet, then do the setup steps
if !env[:result]
b2.use CheckAccessible
b2.use CheckBox
b2.use Import
b2.use CheckGuestAdditions
b2.use DefaultName
b2.use MatchMACAddress
end
end
b.use action_start
end
end
end
end
end

View File

@ -0,0 +1,33 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class CheckBox
def initialize(app, env)
@app = app
end
def call(env)
box_name = env[:machine].config.vm.box
raise Vagrant::Errors::BoxNotSpecified if !box_name
if !env[:box_collection].find(box_name, :virtualbox)
box_url = env[:machine].config.vm.box_url
raise Vagrant::Errors::BoxSpecifiedDoesntExist, :name => box_name if !box_url
# Add the box then reload the box collection so that it becomes
# aware of it.
env[:ui].info I18n.t("vagrant.actions.vm.check_box.not_found", :name => box_name)
env[:box_collection].add(box_name, box_url)
env[:box_collection].reload!
# Reload the environment and set the VM to be the new loaded VM.
env[:machine].env.reload!
env[:machine] = env[:machine].env.vms[env[:machine].name]
end
@app.call(env)
end
end
end
end
end

View File

@ -0,0 +1,36 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class CheckGuestAdditions
def initialize(app, env)
@app = app
end
def call(env)
# Use the raw interface for now, while the virtualbox gem
# doesn't support guest properties (due to cross platform issues)
version = env[:machine].provider.driver.read_guest_additions_version
if !version
env[:ui].warn I18n.t("vagrant.actions.vm.check_guest_additions.not_detected")
else
# Strip the -OSE/_OSE off from the guest additions and the virtual box
# version since all the matters are that the version _numbers_ match up.
guest_version, vb_version = [version, env[:machine].provider.driver.version].map do |v|
v.gsub(/[-_]ose/i, '')
end
if guest_version != vb_version
env[:ui].warn(I18n.t("vagrant.actions.vm.check_guest_additions.version_mismatch",
:guest_version => version,
:virtualbox_version => vb_version))
end
end
# Continue
@app.call(env)
end
end
end
end
end

View File

@ -0,0 +1,22 @@
require "log4r"
module VagrantPlugins
module ProviderVirtualBox
module Action
class DefaultName
def initialize(app, env)
@logger = Log4r::Logger.new("vagrant::action::vm::defaultname")
@app = app
end
def call(env)
@logger.info("Setting the default name of the VM")
name = env[:root_path].basename.to_s + "_#{Time.now.to_i}"
env[:machine].provider.driver.set_name(name)
@app.call(env)
end
end
end
end
end

View File

@ -0,0 +1,49 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class Import
def initialize(app, env)
@app = app
end
def call(env)
env[:ui].info I18n.t("vagrant.actions.vm.import.importing",
:name => env[:machine].box.name)
# Import the virtual machine
ovf_file = env[:machine].box.directory.join("box.ovf").to_s
env[:machine].id = env[:machine].provider.driver.import(ovf_file) do |progress|
env[:ui].clear_line
env[:ui].report_progress(progress, 100, false)
end
# Clear the line one last time since the progress meter doesn't disappear
# immediately.
env[:ui].clear_line
# If we got interrupted, then the import could have been
# interrupted and its not a big deal. Just return out.
return if env[:interrupted]
# Flag as erroneous and return if import failed
raise Vagrant::Errors::VMImportFailure if !env[:machine].id
# Import completed successfully. Continue the chain
@app.call(env)
end
def recover(env)
if env[:machine].provider.state != :not_created
return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
# Interrupted, destroy the VM. We note that we don't want to
# validate the configuration here.
destroy_env = env.clone
destroy_env[:validate] = false
env[:action_runner].run(Action.action_destroy, destroy_env)
end
end
end
end
end
end

View File

@ -0,0 +1,20 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class IsSaved
def initialize(app, env)
@app = app
end
def call(env)
# Set the result to be true if the machine is saved.
env[:result] = env[:machine].state == :saved
# Call the next if we have one (but we shouldn't, since this
# middleware is built to run with the Call-type middlewares)
@app.call(env)
end
end
end
end
end

View File

@ -0,0 +1,21 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class MatchMACAddress
def initialize(app, env)
@app = app
end
def call(env)
raise Vagrant::Errors::VMBaseMacNotSpecified if !env[:machine].config.vm.base_mac
# Create the proc which we want to use to modify the virtual machine
env[:ui].info I18n.t("vagrant.actions.vm.match_mac.matching")
env[:machine].provider.driver.set_mac_address(env[:machine].config.vm.base_mac)
@app.call(env)
end
end
end
end
end

View File

@ -9,16 +9,9 @@ module VagrantPlugins
@logger = Log4r::Logger.new("vagrant::provider::virtualbox")
@machine = machine
begin
@logger.debug("Instantiating the driver for machine ID: #{@machine.id.inspect}")
@driver = Driver::Meta.new(@machine.id)
rescue Driver::Meta::VMNotFound
# The virtual machine doesn't exist, so we probably have a stale
# ID. Just clear the id out of the machine and reload it.
@logger.debug("VM not found! Clearing saved machine ID and reloading.")
@machine.id = nil
retry
end
# This method will load in our driver, so we call it now to
# initialize it.
machine_id_changed
end
# @see Vagrant::Plugin::V1::Provider#action
@ -31,6 +24,23 @@ module VagrantPlugins
nil
end
# If the machine ID changed, then we need to rebuild our underlying
# driver.
def machine_id_changed
id = @machine.id
begin
@logger.debug("Instantiating the driver for machine ID: #{@machine.id.inspect}")
@driver = Driver::Meta.new(id)
rescue Driver::Meta::VMNotFound
# The virtual machine doesn't exist, so we probably have a stale
# ID. Just clear the id out of the machine and reload it.
@logger.debug("VM not found! Clearing saved machine ID and reloading.")
id = nil
retry
end
end
# Returns the SSH info for accessing the VirtualBox VM.
def ssh_info
# If the VM is not created then we cannot possibly SSH into it, so

View File

@ -90,6 +90,10 @@ describe Vagrant::Machine do
end
it "should have access to the ID" do
# Stub this because #id= calls it.
provider.stub(:machine_id_changed)
# Set the ID on the previous instance so that it is persisted
instance.id = "foo"
provider_init_test do |machine|
@ -270,6 +274,10 @@ describe Vagrant::Machine do
end
describe "setting the ID" do
before(:each) do
provider.stub(:machine_id_changed)
end
it "should not have an ID by default" do
instance.id.should be_nil
end
@ -279,6 +287,12 @@ describe Vagrant::Machine do
instance.id.should == "bar"
end
it "should notify the machine that the ID changed" do
provider.should_receive(:machine_id_changed).once
instance.id = "bar"
end
it "should persist the ID" do
instance.id = "foo"
new_instance.id.should == "foo"