Merge branch 'middleware'
This commit is contained in:
commit
8f0d6c8304
|
@ -12,5 +12,8 @@ require File.expand_path("util/glob_loader", libdir)
|
|||
|
||||
# Load them up
|
||||
Vagrant::GlobLoader.glob_require(libdir, %w{util/stacked_proc_runner
|
||||
actions/base downloaders/base actions/collection actions/runner config
|
||||
provisioners/base provisioners/chef systems/base commands/base commands/box})
|
||||
downloaders/base config provisioners/base provisioners/chef systems/base
|
||||
commands/base commands/box action/exception_catcher})
|
||||
|
||||
# Initialize the built-in actions
|
||||
Vagrant::Action.builtin!
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
module Vagrant
|
||||
# Manages action running and registration. Every Vagrant environment
|
||||
# has an instance of {Action} to allow for running in the context of
|
||||
# the environment.
|
||||
class Action
|
||||
include Util
|
||||
|
||||
class << self
|
||||
# Returns the list of registered actions.
|
||||
def actions
|
||||
@actions ||= {}
|
||||
end
|
||||
|
||||
# Registers an action and associates it with a symbol. This
|
||||
# symbol can then be referenced in other action builds and
|
||||
# callbacks can be registered on that symbol.
|
||||
#
|
||||
# @param [Symbol] key
|
||||
def register(key, callable)
|
||||
actions[key] = callable
|
||||
end
|
||||
|
||||
# Retrieves a registered action by key.
|
||||
def [](key)
|
||||
actions[key]
|
||||
end
|
||||
end
|
||||
|
||||
# The environment to run the actions in.
|
||||
attr_reader :env
|
||||
|
||||
# Initializes the action with the given environment which the actions
|
||||
# will be run in.
|
||||
#
|
||||
# @param [Environment] env
|
||||
def initialize(env)
|
||||
@env = env
|
||||
end
|
||||
|
||||
# Runs the given callable object in the context of the environment.
|
||||
# If a symbol is given as the `callable` parameter, then it is looked
|
||||
# up in the registered actions list which are registered with {register}.
|
||||
#
|
||||
# @param [Object] callable An object which responds to `call`.
|
||||
def run(callable, options=nil)
|
||||
callable = Builder.new.use(callable) if callable.kind_of?(Class)
|
||||
callable = self.class.actions[callable] if callable.kind_of?(Symbol)
|
||||
|
||||
action_environment = Action::Environment.new(env)
|
||||
action_environment.merge!(options || {})
|
||||
callable.call(action_environment)
|
||||
|
||||
if action_environment.error?
|
||||
# Erroneous environment resulted. Properly display error
|
||||
# message.
|
||||
key, options = action_environment.error
|
||||
error_and_exit(key, options)
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
class ActionException < Exception
|
||||
attr_reader :key
|
||||
attr_reader :data
|
||||
|
||||
def initialize(key, data = {})
|
||||
@key = key
|
||||
@data = data
|
||||
|
||||
message = Vagrant::Util::Translator.t(key, data)
|
||||
super(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module Box
|
||||
class Destroy
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env.logger.info "Deleting box directory..."
|
||||
FileUtils.rm_rf(env["box"].directory)
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,82 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module Box
|
||||
class Download
|
||||
BASENAME = "box"
|
||||
|
||||
include Util
|
||||
include ExceptionCatcher
|
||||
|
||||
attr_reader :temp_path
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
@env["download.classes"] ||= []
|
||||
@env["download.classes"] << [Downloaders::HTTP, Downloaders::File]
|
||||
@env["download.classes"].flatten!
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
catch_action_exception(env) do
|
||||
download if instantiate_downloader
|
||||
end
|
||||
|
||||
return if env.error?
|
||||
@app.call(@env)
|
||||
|
||||
cleanup
|
||||
end
|
||||
|
||||
def instantiate_downloader
|
||||
@env["download.classes"].each do |klass|
|
||||
if klass.match?(@env["box"].uri)
|
||||
@env.logger.info "Downloading with #{klass}..."
|
||||
@downloader = klass.new(@env["box"].uri)
|
||||
end
|
||||
end
|
||||
|
||||
if !@downloader
|
||||
@env.error!(:box_download_unknown_type)
|
||||
return false
|
||||
end
|
||||
|
||||
@downloader.prepare(@env["box"].uri)
|
||||
true
|
||||
end
|
||||
|
||||
def download
|
||||
with_tempfile do |tempfile|
|
||||
download_to(tempfile)
|
||||
@temp_path = @env["download.temp_path"] = tempfile.path
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
if temp_path && File.exist?(temp_path)
|
||||
@env.logger.info "Cleaning up downloaded box..."
|
||||
File.unlink(temp_path)
|
||||
end
|
||||
end
|
||||
|
||||
def with_tempfile
|
||||
@env.logger.info "Creating tempfile for storing box file..."
|
||||
File.open(box_temp_path, Platform.tar_file_options) do |tempfile|
|
||||
yield tempfile
|
||||
end
|
||||
end
|
||||
|
||||
def box_temp_path
|
||||
File.join(@env.env.tmp_path, BASENAME + Time.now.to_i.to_s)
|
||||
end
|
||||
|
||||
def download_to(f)
|
||||
@env.logger.info "Copying box to temporary location..."
|
||||
@downloader.download!(@env["box"].uri, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module Box
|
||||
# Unpackages a downloaded box to a given directory with a given
|
||||
# name.
|
||||
#
|
||||
# # Required Variables
|
||||
#
|
||||
# * `download.temp_path` - A location for the downloaded box. This is
|
||||
# set by the {Download} action.
|
||||
# * `box` - A {Vagrant::Box} object.
|
||||
#
|
||||
class Unpackage
|
||||
attr_reader :box_directory
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
return if !setup_box_directory
|
||||
decompress
|
||||
|
||||
@app.call(@env)
|
||||
|
||||
cleanup if @env.error?
|
||||
end
|
||||
|
||||
def cleanup
|
||||
if File.directory?(box_directory)
|
||||
FileUtils.rm_rf(box_directory)
|
||||
end
|
||||
end
|
||||
|
||||
def setup_box_directory
|
||||
if File.directory?(@env["box"].directory)
|
||||
@env.error!(:box_already_exists, :box_name => @env["box"].name)
|
||||
return false
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(@env["box"].directory)
|
||||
@box_directory = @env["box"].directory
|
||||
true
|
||||
end
|
||||
|
||||
def decompress
|
||||
Dir.chdir(@env["box"].directory) do
|
||||
@env.logger.info "Extracting box to #{@env["box"].directory}..."
|
||||
Archive::Tar::Minitar.unpack(@env["download.temp_path"], @env["box"].directory)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module Box
|
||||
class Verify
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
end
|
||||
|
||||
def call(env)
|
||||
begin
|
||||
env.logger.info "Verifying box..."
|
||||
VirtualBox::Appliance.new(env["box"].ovf_file)
|
||||
rescue Exception
|
||||
return env.error!(:box_verification_failed)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,148 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
# Action builder which provides a nice DSL for building up
|
||||
# a middleware sequence for Vagrant actions. This code is based
|
||||
# heavily off of `Rack::Builder` and `ActionDispatch::MiddlewareStack`
|
||||
# in Rack and Rails, respectively.
|
||||
#
|
||||
# Usage
|
||||
#
|
||||
# Building an action sequence is very easy:
|
||||
#
|
||||
# app = Vagrant::Action::Builder.new do
|
||||
# use MiddlewareA
|
||||
# use MiddlewareB
|
||||
# end
|
||||
#
|
||||
# Vagrant::Action.run(app)
|
||||
#
|
||||
class Builder
|
||||
# Initializes the builder. An optional block can be passed which
|
||||
# will be evaluated in the context of the instance.
|
||||
def initialize(&block)
|
||||
instance_eval(&block) if block_given?
|
||||
end
|
||||
|
||||
# Returns the current stack of middlewares. You probably won't
|
||||
# need to use this directly, and its recommended that you don't.
|
||||
#
|
||||
# @return [Array]
|
||||
def stack
|
||||
@stack ||= []
|
||||
end
|
||||
|
||||
# Returns a mergeable version of the builder. If `use` is called with
|
||||
# the return value of this method, then the stack will merge, instead
|
||||
# of being treated as a separate single middleware.
|
||||
def flatten
|
||||
lambda do |env|
|
||||
self.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
# Adds a middleware class to the middleware stack. Any additional
|
||||
# args and a block, if given, are saved and passed to the initializer
|
||||
# of the middleware.
|
||||
#
|
||||
# @param [Class] middleware The middleware class
|
||||
def use(middleware, *args, &block)
|
||||
if middleware.kind_of?(Builder)
|
||||
# Merge in the other builder's stack into our own
|
||||
self.stack.concat(middleware.stack)
|
||||
else
|
||||
self.stack << [middleware, args, block]
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
# Inserts a middleware at the given index or directly before the
|
||||
# given middleware object.
|
||||
def insert(index, middleware, *args, &block)
|
||||
index = self.index(index) unless index.is_a?(Integer)
|
||||
stack.insert(index, [middleware, args, block])
|
||||
end
|
||||
|
||||
alias_method :insert_before, :insert
|
||||
|
||||
# Inserts a middleware after the given index or middleware object.
|
||||
def insert_after(index, middleware, *args, &block)
|
||||
index = self.index(index) unless index.is_a?(Integer)
|
||||
raise "no such middleware to insert after: #{index.inspect}" unless index
|
||||
insert(index + 1, middleware, *args, &block)
|
||||
end
|
||||
|
||||
# Swaps out the given middlware object or index with the new
|
||||
# middleware.
|
||||
def swap(index, middleware, *args, &block)
|
||||
if index.is_a?(Integer)
|
||||
delete(index)
|
||||
insert(index, middleware, *args, &block)
|
||||
else
|
||||
insert_before(index, middleware, *args, &block)
|
||||
delete(index)
|
||||
end
|
||||
end
|
||||
|
||||
# Deletes the given middleware object or index
|
||||
def delete(index)
|
||||
index = self.index(index) unless index.is_a?(Integer)
|
||||
stack.delete_at(index)
|
||||
end
|
||||
|
||||
# Returns the numeric index for the given middleware object.
|
||||
#
|
||||
# @param [Object] object The item to find the index for
|
||||
# @return [Integer]
|
||||
def index(object)
|
||||
stack.each_with_index do |item, i|
|
||||
return i if item[0] == object
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Converts the builder stack to a runnable action sequence.
|
||||
#
|
||||
# @param [Vagrant::Action::Environment] env The action environment
|
||||
# @return [Object] A callable object
|
||||
def to_app(env)
|
||||
# Prepend the error halt task so errneous environments are halted
|
||||
# before the chain even begins.
|
||||
items = stack.dup.unshift([ErrorHalt, [], nil])
|
||||
|
||||
# Convert each middleware into a lambda which takes the next
|
||||
# middleware.
|
||||
items = items.collect do |item|
|
||||
klass, args, block = item
|
||||
|
||||
lambda do |app|
|
||||
if klass.is_a?(Class)
|
||||
# A middleware klass which is to be instantiated with the
|
||||
# app, env, and any arguments given
|
||||
klass.new(app, env, *args, &block)
|
||||
elsif klass.respond_to?(:call)
|
||||
# Make it a lambda which calls the item then forwards
|
||||
# up the chain
|
||||
lambda do |e|
|
||||
klass.call(e)
|
||||
app.call(e)
|
||||
end
|
||||
else
|
||||
raise "Invalid middleware: #{item.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Append the final step and convert into flattened call chain.
|
||||
items << lambda { |env| }
|
||||
items[0...-1].reverse.inject(items.last) { |a,e| e.call(a) }
|
||||
end
|
||||
|
||||
# Runs the builder stack with the given environment.
|
||||
def call(env)
|
||||
to_app(env).call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,104 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
# Registers the builtin actions. These are locked away in a
|
||||
# method so that their definition can be deferred until after
|
||||
# all the necessary Vagrant libraries are loaded. Hopefully
|
||||
# in the future this will no longer be necessary with autoloading.
|
||||
def self.builtin!
|
||||
# provision - Provisions a running VM
|
||||
provision = Builder.new do
|
||||
use VM::Provision
|
||||
end
|
||||
|
||||
register :provision, provision
|
||||
|
||||
# start - Starts a VM, assuming it already exists on the
|
||||
# environment.
|
||||
start = Builder.new do
|
||||
use VM::Customize
|
||||
use VM::ForwardPorts
|
||||
use VM::Provision
|
||||
use VM::ShareFolders
|
||||
use VM::Network
|
||||
use VM::Boot
|
||||
end
|
||||
|
||||
register :start, start
|
||||
|
||||
# halt - Halts the VM, attempting gracefully but then forcing
|
||||
# a restart if fails.
|
||||
halt = Builder.new do
|
||||
use VM::Halt
|
||||
end
|
||||
|
||||
register :halt, halt
|
||||
|
||||
# suspend - Suspends the VM
|
||||
suspend = Builder.new do
|
||||
use VM::Suspend
|
||||
end
|
||||
|
||||
register :suspend, suspend
|
||||
|
||||
# resume - Resume a VM
|
||||
resume = Builder.new do
|
||||
use VM::Resume
|
||||
end
|
||||
|
||||
register :resume, resume
|
||||
|
||||
# reload - Halts then restarts the VM
|
||||
reload = Builder.new do
|
||||
use Action[:halt]
|
||||
use Action[:start]
|
||||
end
|
||||
|
||||
register :reload, reload
|
||||
|
||||
# up - Imports, prepares, then starts a fresh VM.
|
||||
up = Builder.new do
|
||||
use VM::Import
|
||||
use VM::Persist
|
||||
use VM::MatchMACAddress
|
||||
use VM::CheckGuestAdditions
|
||||
use Action[:start]
|
||||
end
|
||||
|
||||
register :up, up
|
||||
|
||||
# destroy - Halts, cleans up, and destroys an existing VM
|
||||
destroy = Builder.new do
|
||||
use Action[:halt]
|
||||
use VM::DestroyUnusedNetworkInterfaces
|
||||
use VM::Destroy
|
||||
end
|
||||
|
||||
register :destroy, destroy
|
||||
|
||||
# package - Export and package the VM
|
||||
package = Builder.new do
|
||||
use Action[:halt]
|
||||
use VM::Export
|
||||
use VM::Package
|
||||
end
|
||||
|
||||
register :package, package
|
||||
|
||||
# box_add - Download and add a box.
|
||||
box_add = Builder.new do
|
||||
use Box::Download
|
||||
use Box::Unpackage
|
||||
use Box::Verify
|
||||
end
|
||||
|
||||
register :box_add, box_add
|
||||
|
||||
# box_remove - Removes/deletes a box.
|
||||
box_remove = Builder.new do
|
||||
use Box::Destroy
|
||||
end
|
||||
|
||||
register :box_remove, box_remove
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,54 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
# Represents an action environment which is what is passed
|
||||
# to the `call` method of each action. This environment contains
|
||||
# some helper methods for accessing the environment as well
|
||||
# as being a hash, to store any additional options.
|
||||
class Environment < Hash
|
||||
# The {Vagrant::Environment} object represented by this
|
||||
# action environment.
|
||||
attr_reader :env
|
||||
|
||||
# If nonnil, the error associated with this environment. Set
|
||||
# using {#error!}
|
||||
attr_reader :error
|
||||
|
||||
def initialize(env)
|
||||
super() do |h,k|
|
||||
# By default, try to find the key as a method on the
|
||||
# environment. Gross eval use here.
|
||||
begin
|
||||
value = eval("h.env.#{k}")
|
||||
h[k] = value
|
||||
rescue Exception
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@env = env
|
||||
@error = nil
|
||||
end
|
||||
|
||||
# Returns a logger associated with the environment.
|
||||
def logger
|
||||
env.logger
|
||||
end
|
||||
|
||||
# Flags the environment as erroneous. Stores the given key
|
||||
# and options until the end of the action sequence.
|
||||
#
|
||||
# @param [Symbol] key Key to translation to display error message.
|
||||
# @param [Hash] options Variables to pass to the translation
|
||||
def error!(key, options=nil)
|
||||
@error = [key, (options || {})]
|
||||
end
|
||||
|
||||
# Returns boolean denoting if environment is in erroneous state.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def error?
|
||||
!error.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
# A middleware which simply halts if the environment is erroneous.
|
||||
class ErrorHalt
|
||||
def initialize(app,env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env) if !env.error?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
# A helper to catch any ActionExceptions raised and to
|
||||
# apply the error to the environment.
|
||||
module ExceptionCatcher
|
||||
def catch_action_exception(env)
|
||||
yield env
|
||||
rescue ActionException => e
|
||||
env.error!(e.key, e.data)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,46 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Boot
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
# Start up the VM and wait for it to boot.
|
||||
boot
|
||||
return env.error!(:vm_failed_to_boot) if !wait_for_boot
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def boot
|
||||
@env.logger.info "Booting VM..."
|
||||
@env["vm"].vm.start(@env.env.config.vm.boot_mode)
|
||||
end
|
||||
|
||||
def wait_for_boot(sleeptime=5)
|
||||
@env.logger.info "Waiting for VM to boot..."
|
||||
|
||||
@env.env.config.ssh.max_tries.to_i.times do |i|
|
||||
@env.logger.info "Trying to connect (attempt ##{i+1} of #{@env.env.config[:ssh][:max_tries]})..."
|
||||
|
||||
if @env["vm"].ssh.up?
|
||||
@env.logger.info "VM booted and ready for use!"
|
||||
return true
|
||||
end
|
||||
|
||||
sleep sleeptime
|
||||
end
|
||||
|
||||
@env.logger.info "Failed to connect to VM! Failed to boot?"
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
# Middleware which verifies that the VM has the proper guest additions
|
||||
# installed and prints a warning if they're not detected or if the
|
||||
# version does not match the installed VirtualBox version.
|
||||
class CheckGuestAdditions
|
||||
include Util
|
||||
|
||||
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["vm"].vm.interface.get_guest_property_value("/VirtualBox/GuestAdd/Version")
|
||||
if version.empty?
|
||||
env.logger.error Translator.t(:vm_additions_not_detected)
|
||||
elsif version != VirtualBox.version
|
||||
env.logger.error Translator.t(:vm_additions_version_mismatch,
|
||||
:guest_additions_version => version,
|
||||
:virtualbox_version => VirtualBox.version)
|
||||
end
|
||||
|
||||
# Continue
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Customize
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if !env.env.config.vm.proc_stack.empty?
|
||||
env.logger.info "Running any VM customizations..."
|
||||
env.env.config.vm.run_procs!(env["vm"].vm)
|
||||
env["vm"].vm.save
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Destroy
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env.logger.info "Destroying VM and associated drives..."
|
||||
env["vm"].vm.destroy(:destroy_medium => :delete)
|
||||
env["vm"].vm = nil
|
||||
env.env.update_dotfile
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
# Destroys the unused host only interfaces. This middleware cleans
|
||||
# up any created host only networks.
|
||||
class DestroyUnusedNetworkInterfaces
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
# We need to check if the host only network specified by any
|
||||
# of the adapters would not have any more clients if it was
|
||||
# destroyed. And if so, then destroy the host only network
|
||||
# itself.
|
||||
interfaces = env["vm"].vm.network_adapters.collect do |adapter|
|
||||
adapter.host_interface_object
|
||||
end
|
||||
|
||||
interfaces.compact.uniq.each do |interface|
|
||||
# Destroy the network interface if there is only one
|
||||
# attached VM (which must be this VM)
|
||||
if interface.attached_vms.length == 1
|
||||
env.logger.info "Destroying unused network interface..."
|
||||
interface.destroy
|
||||
end
|
||||
end
|
||||
|
||||
# Continue along
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Export
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
return env.error!(:vm_power_off_to_package) if !@env["vm"].vm.powered_off?
|
||||
|
||||
setup_temp_dir
|
||||
export
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def setup_temp_dir
|
||||
@env.logger.info "Creating temporary directory for export..."
|
||||
@env["export.temp_dir"] = File.join(@env.env.tmp_path, Time.now.to_i.to_s)
|
||||
FileUtils.mkpath(@env["export.temp_dir"])
|
||||
end
|
||||
|
||||
def export
|
||||
@env.logger.info "Exporting VM to #{ovf_path}..."
|
||||
@env["vm"].vm.export(ovf_path) do |progress|
|
||||
@env.logger.report_progress(progress.percent, 100, false)
|
||||
end
|
||||
ensure
|
||||
@env.logger.clear_progress
|
||||
end
|
||||
|
||||
def ovf_path
|
||||
File.join(@env["export.temp_dir"], @env.env.config.vm.box_ovf)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,18 +1,26 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Action
|
||||
module VM
|
||||
class ForwardPorts < Base
|
||||
def prepare
|
||||
class ForwardPorts
|
||||
def initialize(app,env)
|
||||
@app = app
|
||||
@env = env
|
||||
|
||||
external_collision_check
|
||||
end
|
||||
|
||||
#--------------------------------------------------------------
|
||||
# Prepare Helpers - These functions are not involved in actually
|
||||
# executing the action
|
||||
#--------------------------------------------------------------
|
||||
|
||||
# This method checks for any port collisions with any VMs
|
||||
# which are already created (by Vagrant or otherwise).
|
||||
# report the collisions detected or will attempt to fix them
|
||||
# automatically if the port is configured to do so.
|
||||
def external_collision_check
|
||||
existing = used_ports
|
||||
runner.env.config.vm.forwarded_ports.each do |name, options|
|
||||
@env.env.config.vm.forwarded_ports.each do |name, options|
|
||||
if existing.include?(options[:hostport].to_s)
|
||||
handle_collision(name, options, existing)
|
||||
end
|
||||
|
@ -26,18 +34,18 @@ module Vagrant
|
|||
if !options[:auto]
|
||||
# Auto fixing is disabled for this port forward, so we
|
||||
# must throw an error so the user can fix it.
|
||||
raise ActionException.new(:vm_port_collision, :name => name, :hostport => options[:hostport].to_s, :guestport => options[:guestport].to_s, :adapter => options[:adapter])
|
||||
return @env.error!(:vm_port_collision, :name => name, :hostport => options[:hostport].to_s, :guestport => options[:guestport].to_s, :adapter => options[:adapter])
|
||||
end
|
||||
|
||||
# Get the auto port range and get rid of the used ports and
|
||||
# ports which are being used in other forwards so we're just
|
||||
# left with available ports.
|
||||
range = runner.env.config.vm.auto_port_range.to_a
|
||||
range -= runner.env.config.vm.forwarded_ports.collect { |n, o| o[:hostport].to_i }
|
||||
range = @env.env.config.vm.auto_port_range.to_a
|
||||
range -= @env.env.config.vm.forwarded_ports.collect { |n, o| o[:hostport].to_i }
|
||||
range -= existing_ports
|
||||
|
||||
if range.empty?
|
||||
raise ActionException.new(:vm_port_auto_empty, :vm_name => @runner.name, :name => name, :options => options)
|
||||
return @env.error!(:vm_port_auto_empty, :vm_name => @env["vm"].name, :name => name, :options => options)
|
||||
end
|
||||
|
||||
# Set the port up to be the first one and add that port to
|
||||
|
@ -46,51 +54,54 @@ module Vagrant
|
|||
existing_ports << options[:hostport]
|
||||
|
||||
# Notify the user
|
||||
logger.info "Fixed port collision: #{name} now on port #{options[:hostport]}"
|
||||
@env.logger.info "Fixed port collision: #{name} now on port #{options[:hostport]}"
|
||||
end
|
||||
|
||||
def execute!
|
||||
#--------------------------------------------------------------
|
||||
# Execution
|
||||
#--------------------------------------------------------------
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
clear
|
||||
forward_ports
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def clear
|
||||
if used_ports.length > 0
|
||||
logger.info "Deleting any previously set forwarded ports..."
|
||||
@env.logger.info "Deleting any previously set forwarded ports..."
|
||||
clear_ports
|
||||
runner.reload!
|
||||
@env["vm"].reload!
|
||||
end
|
||||
end
|
||||
|
||||
def forward_ports
|
||||
logger.info "Forwarding ports..."
|
||||
@env.logger.info "Forwarding ports..."
|
||||
|
||||
runner.env.config.vm.forwarded_ports.each do |name, options|
|
||||
@env.env.config.vm.forwarded_ports.each do |name, options|
|
||||
adapter = options[:adapter]
|
||||
|
||||
# Assuming the only reason to establish port forwarding is because the VM is using Virtualbox NAT networking.
|
||||
# Host-only or Bridged networking don't require port-forwarding and establishing forwarded ports on these
|
||||
# attachment types has uncertain behaviour.
|
||||
if @runner.vm.network_adapters[adapter].attachment_type == :nat
|
||||
logger.info "Forwarding \"#{name}\": #{options[:guestport]} on adapter \##{adapter+1} => #{options[:hostport]}"
|
||||
if @env["vm"].vm.network_adapters[adapter].attachment_type == :nat
|
||||
@env.logger.info "Forwarding \"#{name}\": #{options[:guestport]} on adapter \##{adapter+1} => #{options[:hostport]}"
|
||||
forward_port(name, options)
|
||||
else
|
||||
logger.info "VirtualBox adapter \##{adapter+1} not configured as \"NAT\"."
|
||||
logger.info "Skipped port forwarding \"#{name}\": #{options[:guestport]} on adapter\##{adapter+1} => #{options[:hostport]}"
|
||||
@env.logger.info "VirtualBox adapter \##{adapter+1} not configured as \"NAT\"."
|
||||
@env.logger.info "Skipped port forwarding \"#{name}\": #{options[:guestport]} on adapter\##{adapter+1} => #{options[:hostport]}"
|
||||
end
|
||||
end
|
||||
|
||||
runner.vm.save
|
||||
runner.reload!
|
||||
@env["vm"].vm.save
|
||||
@env["vm"].reload!
|
||||
end
|
||||
|
||||
#------------------------------------------------------------
|
||||
# VirtualBox version-specific helpers below. VirtualBox 3.2
|
||||
# introduced a breaking change into the way that forwarded
|
||||
# ports are handled. For backwards compatability with 3.1, we
|
||||
# need this trickery.
|
||||
#------------------------------------------------------------
|
||||
# TODO In a future version, fix this.
|
||||
#--------------------------------------------------------------
|
||||
# General Helpers
|
||||
#--------------------------------------------------------------
|
||||
|
||||
# Returns an array of used ports. This method is implemented
|
||||
# differently depending on the VirtualBox version, but the
|
||||
|
@ -99,7 +110,7 @@ module Vagrant
|
|||
# @return [Array<String>]
|
||||
def used_ports
|
||||
result = VirtualBox::VM.all.collect do |vm|
|
||||
if vm.running? && vm.uuid != runner.uuid
|
||||
if vm.running? && vm.uuid != @env["vm"].uuid
|
||||
vm.network_adapters.collect do |na|
|
||||
na.nat_driver.forwarded_ports.collect do |fp|
|
||||
fp.hostport.to_s
|
||||
|
@ -113,7 +124,7 @@ module Vagrant
|
|||
|
||||
# Deletes existing forwarded ports.
|
||||
def clear_ports
|
||||
runner.vm.network_adapters.each do |na|
|
||||
@env["vm"].vm.network_adapters.each do |na|
|
||||
na.nat_driver.forwarded_ports.dup.each do |fp|
|
||||
fp.destroy
|
||||
end
|
||||
|
@ -126,7 +137,7 @@ module Vagrant
|
|||
port.name = name
|
||||
port.guestport = options[:guestport]
|
||||
port.hostport = options[:hostport]
|
||||
runner.vm.network_adapters[options[:adapter]].nat_driver.forwarded_ports << port
|
||||
@env["vm"].vm.network_adapters[options[:adapter]].nat_driver.forwarded_ports << port
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Halt
|
||||
include ExceptionCatcher
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if env["vm"].vm.running?
|
||||
if !env["force"]
|
||||
catch_action_exception(env) { env["vm"].system.halt }
|
||||
return if env.error?
|
||||
end
|
||||
|
||||
if env["vm"].vm.state(true) != :powered_off
|
||||
env.logger.info "Forcing shutdown of VM..."
|
||||
env["vm"].vm.stop
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Import
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env.logger.info "Importing base VM (#{env.env.box.ovf_file})"
|
||||
|
||||
begin
|
||||
# Import the virtual machine
|
||||
env.env.vm.vm = VirtualBox::VM.import(env.env.box.ovf_file) do |progress|
|
||||
env.logger.report_progress(progress.percent, 100, false)
|
||||
end
|
||||
|
||||
# Flag as erroneous and return if import failed
|
||||
return env.error!(:virtualbox_import_failure) if !env['vm'].vm
|
||||
ensure
|
||||
env.logger.clear_progress
|
||||
end
|
||||
|
||||
# Import completed successfully. Continue the chain
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class MatchMACAddress
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env.logger.info "Matching MAC addresses..."
|
||||
env["vm"].vm.network_adapters.first.mac_address = env.env.config.vm.base_mac
|
||||
env["vm"].vm.save
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,71 +1,43 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Action
|
||||
module VM
|
||||
class Network < Base
|
||||
def prepare
|
||||
# Verify that the given network options are valid
|
||||
runner.env.config.vm.network_options.compact.each do |network_options|
|
||||
verify_no_bridge_collision(network_options)
|
||||
end
|
||||
end
|
||||
# Networking middleware for Vagrant. This enables host only
|
||||
# networking on VMs if configured as such.
|
||||
class Network
|
||||
include ExceptionCatcher
|
||||
|
||||
def before_destroy
|
||||
# We need to check if the host only network specified by any
|
||||
# of the adapters would not have any more clients if it was
|
||||
# destroyed. And if so, then destroy the host only network
|
||||
# itself.
|
||||
interfaces = runner.vm.network_adapters.collect do |adapter|
|
||||
adapter.host_interface_object
|
||||
end
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
|
||||
interfaces.compact.uniq.each do |interface|
|
||||
# Destroy the network interface if there is only one
|
||||
# attached VM (which must be this VM)
|
||||
if interface.attached_vms.length == 1
|
||||
logger.info "Destroying unused network interface..."
|
||||
interface.destroy
|
||||
env["config"].vm.network_options.compact.each do |network_options|
|
||||
if !verify_no_bridge_collision(network_options)
|
||||
env.error!(:network_collides)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def before_boot
|
||||
def call(env)
|
||||
@env = env
|
||||
assign_network if enable_network?
|
||||
end
|
||||
|
||||
def after_boot
|
||||
if enable_network?
|
||||
logger.info "Enabling host only network..."
|
||||
@app.call(env)
|
||||
|
||||
runner.system.prepare_host_only_network
|
||||
|
||||
runner.env.config.vm.network_options.compact.each do |network_options|
|
||||
runner.system.enable_host_only_network(network_options)
|
||||
if !env.error? && enable_network?
|
||||
catch_action_exception(env) do
|
||||
@env.logger.info "Enabling host only network..."
|
||||
@env["vm"].system.prepare_host_only_network
|
||||
@env.env.config.vm.network_options.compact.each do |network_options|
|
||||
@env["vm"].system.enable_host_only_network(network_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def enable_network?
|
||||
!runner.env.config.vm.network_options.compact.empty?
|
||||
end
|
||||
|
||||
# Enables and assigns the host only network to the proper
|
||||
# adapter on the VM, and saves the adapter.
|
||||
def assign_network
|
||||
logger.info "Preparing host only network..."
|
||||
|
||||
runner.env.config.vm.network_options.compact.each do |network_options|
|
||||
adapter = runner.vm.network_adapters[network_options[:adapter]]
|
||||
adapter.enabled = true
|
||||
adapter.attachment_type = :host_only
|
||||
adapter.host_interface = network_name(network_options)
|
||||
adapter.save
|
||||
end
|
||||
end
|
||||
|
||||
# Verifies that there is no collision with a bridged network interface
|
||||
# for the given network options.
|
||||
def verify_no_bridge_collision(net_options)
|
||||
# First try to find a matching network
|
||||
interfaces = VirtualBox::Global.global.host.network_interfaces
|
||||
interfaces.each do |ni|
|
||||
next if ni.interface_type == :host_only
|
||||
|
@ -76,7 +48,27 @@ module Vagrant
|
|||
true if matching_network?(ni, net_options)
|
||||
end
|
||||
|
||||
raise ActionException.new(:network_collides) if result
|
||||
return false if result
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def enable_network?
|
||||
!@env.env.config.vm.network_options.compact.empty?
|
||||
end
|
||||
|
||||
# Enables and assigns the host only network to the proper
|
||||
# adapter on the VM, and saves the adapter.
|
||||
def assign_network
|
||||
@env.logger.info "Preparing host only network..."
|
||||
|
||||
@env.env.config.vm.network_options.compact.each do |network_options|
|
||||
adapter = @env["vm"].vm.network_adapters[network_options[:adapter]]
|
||||
adapter.enabled = true
|
||||
adapter.attachment_type = :host_only
|
||||
adapter.host_interface = network_name(network_options)
|
||||
adapter.save
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,10 +90,10 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
raise ActionException.new(:network_not_found, :name => net_options[:name]) if net_options[:name]
|
||||
return @env.error!(:network_not_found, :name => net_options[:name]) if net_options[:name]
|
||||
|
||||
# One doesn't exist, create it.
|
||||
logger.info "Creating new host only network for environment..."
|
||||
@env.logger.info "Creating new host only network for environment..."
|
||||
|
||||
ni = interfaces.create
|
||||
ni.enable_static(network_ip(net_options[:ip], net_options[:netmask]),
|
|
@ -0,0 +1,92 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Package
|
||||
include Util
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
@env["package.output"] ||= "package"
|
||||
@env["package.include"] ||= []
|
||||
|
||||
env.error!(:box_file_exists, :output_file => tar_path) if File.exist?(tar_path)
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
return env.error!(:package_requires_export) if !@env["export.temp_dir"]
|
||||
return if !verify_included_files
|
||||
compress
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
def verify_included_files
|
||||
@env["package.include"].each do |file|
|
||||
if !File.exist?(file)
|
||||
@env.error!(:package_include_file_doesnt_exist, :filename => file)
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# This method copies the include files (passed in via command line)
|
||||
# to the temporary directory so they are included in a sub-folder within
|
||||
# the actual box
|
||||
def copy_include_files
|
||||
if @env["package.include"].length > 0
|
||||
include_dir = File.join(@env["export.temp_dir"], "include")
|
||||
FileUtils.mkdir_p(include_dir)
|
||||
|
||||
@env["package.include"].each do |f|
|
||||
@env.logger.info "Packaging additional file: #{f}"
|
||||
FileUtils.cp(f, include_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This method creates the auto-generated Vagrantfile at the root of the
|
||||
# box. This Vagrantfile contains the MAC address so that the user doesn't
|
||||
# have to worry about it.
|
||||
def create_vagrantfile
|
||||
File.open(File.join(@env["export.temp_dir"], "Vagrantfile"), "w") do |f|
|
||||
f.write(TemplateRenderer.render("package_Vagrantfile", {
|
||||
:base_mac => @env["vm"].vm.network_adapters.first.mac_address
|
||||
}))
|
||||
end
|
||||
end
|
||||
|
||||
# Compress the exported file into a package
|
||||
def compress
|
||||
@env.logger.info "Packaging VM into #{tar_path}..."
|
||||
File.open(tar_path, Platform.tar_file_options) do |tar|
|
||||
Archive::Tar::Minitar::Output.open(tar) do |output|
|
||||
begin
|
||||
current_dir = FileUtils.pwd
|
||||
|
||||
copy_include_files
|
||||
create_vagrantfile
|
||||
|
||||
FileUtils.cd(@env["export.temp_dir"])
|
||||
Dir.glob(File.join(".", "**", "*")).each do |entry|
|
||||
Archive::Tar::Minitar.pack_file(entry, output)
|
||||
end
|
||||
ensure
|
||||
FileUtils.cd(current_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Path to the final box output file
|
||||
def tar_path
|
||||
File.join(FileUtils.pwd, "#{@env["package.output"]}#{@env.env.config.package.extension}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Persist
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
|
||||
# Error the environment if the dotfile is not valid
|
||||
env.error!(:dotfile_error, :env => env.env) if File.exist?(env.env.dotfile_path) &&
|
||||
!File.file?(env.env.dotfile_path)
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env.logger.info "Persisting the VM UUID (#{env["vm"].uuid})"
|
||||
env.env.update_dotfile
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Provision
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
|
||||
load_provisioner if provisioning_enabled?
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
|
||||
if !env.error? && provisioning_enabled?
|
||||
@env.logger.info "Beginning provisioning process..."
|
||||
@provisioner.provision!
|
||||
end
|
||||
end
|
||||
|
||||
def provisioning_enabled?
|
||||
!@env["config"].vm.provisioner.nil?
|
||||
end
|
||||
|
||||
def load_provisioner
|
||||
provisioner = @env["config"].vm.provisioner
|
||||
|
||||
if provisioner.is_a?(Class)
|
||||
@provisioner = provisioner.new(@env)
|
||||
return @env.error!(:provisioner_invalid_class) unless @provisioner.is_a?(Provisioners::Base)
|
||||
elsif provisioner.is_a?(Symbol)
|
||||
# We have a few hard coded provisioners for built-ins
|
||||
mapping = {
|
||||
:chef_solo => Provisioners::ChefSolo,
|
||||
:chef_server => Provisioners::ChefServer
|
||||
}
|
||||
|
||||
provisioner_klass = mapping[provisioner]
|
||||
return @env.error!(:provisioner_unknown_type, :provisioner => provisioner.to_s) if provisioner_klass.nil?
|
||||
@provisioner = provisioner_klass.new(@env)
|
||||
end
|
||||
|
||||
@env.logger.info "Provisioning enabled with #{@provisioner.class}"
|
||||
@provisioner.prepare
|
||||
@provisioner
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Resume
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if env["vm"].vm.saved?
|
||||
env.logger.info "Resuming suspended VM..."
|
||||
env["actions"].run(:start)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,11 +1,36 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Action
|
||||
module VM
|
||||
class SharedFolders < Base
|
||||
class ShareFolders
|
||||
include ExceptionCatcher
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@env = env
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@env = env
|
||||
|
||||
clear_shared_folders
|
||||
create_metadata
|
||||
|
||||
@app.call(env)
|
||||
|
||||
if !env.error?
|
||||
catch_action_exception(env) do
|
||||
# Only mount and setup shared folders in the absense of an
|
||||
# error
|
||||
mount_shared_folders
|
||||
setup_unison
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This method returns an actual list of VirtualBox shared
|
||||
# folders to create and their proper path.
|
||||
def shared_folders
|
||||
runner.env.config.vm.shared_folders.inject({}) do |acc, data|
|
||||
@env.env.config.vm.shared_folders.inject({}) do |acc, data|
|
||||
key, value = data
|
||||
|
||||
# This to prevent overwriting the actual shared folders data
|
||||
|
@ -15,7 +40,7 @@ module Vagrant
|
|||
# Syncing this folder. Change the guestpath to reflect
|
||||
# what we're actually mounting.
|
||||
value[:original] = value.dup
|
||||
value[:guestpath] = "#{value[:guestpath]}#{runner.env.config.unison.folder_suffix}"
|
||||
value[:guestpath] = "#{value[:guestpath]}#{@env.env.config.unison.folder_suffix}"
|
||||
end
|
||||
|
||||
acc[key] = value
|
||||
|
@ -33,23 +58,39 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
def before_boot
|
||||
clear_shared_folders
|
||||
create_metadata
|
||||
def clear_shared_folders
|
||||
if @env["vm"].vm.shared_folders.length > 0
|
||||
@env.logger.info "Clearing previously set shared folders..."
|
||||
|
||||
folders = @env["vm"].vm.shared_folders.dup
|
||||
folders.each do |shared_folder|
|
||||
shared_folder.destroy
|
||||
end
|
||||
|
||||
@env["vm"].reload!
|
||||
end
|
||||
end
|
||||
|
||||
def after_boot
|
||||
mount_shared_folders
|
||||
setup_unison
|
||||
def create_metadata
|
||||
@env.logger.info "Creating shared folders metadata..."
|
||||
|
||||
shared_folders.each do |name, data|
|
||||
folder = VirtualBox::SharedFolder.new
|
||||
folder.name = name
|
||||
folder.host_path = File.expand_path(data[:hostpath], @env.env.root_path)
|
||||
@env["vm"].vm.shared_folders << folder
|
||||
end
|
||||
|
||||
@env["vm"].vm.save
|
||||
end
|
||||
|
||||
def mount_shared_folders
|
||||
logger.info "Mounting shared folders..."
|
||||
@env.logger.info "Mounting shared folders..."
|
||||
|
||||
@runner.ssh.execute do |ssh|
|
||||
@env["vm"].ssh.execute do |ssh|
|
||||
shared_folders.each do |name, data|
|
||||
logger.info "-- #{name}: #{data[:guestpath]}"
|
||||
@runner.system.mount_shared_folder(ssh, name, data[:guestpath])
|
||||
@env.logger.info "-- #{name}: #{data[:guestpath]}"
|
||||
@env["vm"].system.mount_shared_folder(ssh, name, data[:guestpath])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -57,41 +98,15 @@ module Vagrant
|
|||
def setup_unison
|
||||
return if unison_folders.empty?
|
||||
|
||||
runner.ssh.execute do |ssh|
|
||||
runner.system.prepare_unison(ssh)
|
||||
@env["vm"].ssh.execute do |ssh|
|
||||
@env["vm"].system.prepare_unison(ssh)
|
||||
|
||||
logger.info "Creating unison crontab entries..."
|
||||
@env.logger.info "Creating unison crontab entries..."
|
||||
unison_folders.each do |name, data|
|
||||
runner.system.create_unison(ssh, data)
|
||||
@env["vm"].system.create_unison(ssh, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clear_shared_folders
|
||||
if runner.vm.shared_folders.length > 0
|
||||
logger.info "Clearing previously set shared folders..."
|
||||
|
||||
folders = @runner.vm.shared_folders.dup
|
||||
folders.each do |shared_folder|
|
||||
shared_folder.destroy
|
||||
end
|
||||
|
||||
@runner.reload!
|
||||
end
|
||||
end
|
||||
|
||||
def create_metadata
|
||||
logger.info "Creating shared folders metadata..."
|
||||
|
||||
shared_folders.each do |name, data|
|
||||
folder = VirtualBox::SharedFolder.new
|
||||
folder.name = name
|
||||
folder.host_path = File.expand_path(data[:hostpath], runner.env.root_path)
|
||||
@runner.vm.shared_folders << folder
|
||||
end
|
||||
|
||||
@runner.vm.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
module Vagrant
|
||||
class Action
|
||||
module VM
|
||||
class Suspend
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
if env["vm"].vm.running?
|
||||
env.logger.info "Saving VM state and suspending execution..."
|
||||
env["vm"].vm.save_state
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,130 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
# Base class for any command actions.
|
||||
#
|
||||
# Actions are the smallest unit of functionality found within
|
||||
# Vagrant. Vagrant composes many actions together to execute
|
||||
# its complex tasks while keeping the individual pieces of a
|
||||
# task as discrete reusable actions. Actions are ran exclusively
|
||||
# by an {Runner action runner} which is simply a subclass of {Runner}.
|
||||
#
|
||||
# Actions work by implementing any or all of the following methods
|
||||
# which a {Runner} executes:
|
||||
#
|
||||
# * `prepare` - Called once for each action before any action has `execute!`
|
||||
# called. This is meant for basic setup.
|
||||
# * `execute!` - This is where the meat of the action typically goes;
|
||||
# the main code which executes the action.
|
||||
# * `cleanup` - This is called exactly once for each action after every
|
||||
# other action is completed. It is meant for cleaning up any resources.
|
||||
# * `rescue` - This is called if an exception occurs in _any action_. This
|
||||
# gives every other action a chance to clean itself up.
|
||||
#
|
||||
# For details of each step of an action, read the specific function call
|
||||
# documentation below.
|
||||
class Base
|
||||
# The {Runner runner} which is executing the action
|
||||
attr_reader :runner
|
||||
|
||||
# Any options which are passed into the initializer as a hash.
|
||||
attr_reader :options
|
||||
|
||||
# Included so subclasses don't need to include it themselves.
|
||||
include Vagrant::Util
|
||||
|
||||
# A helper method for logging which simply gets the logger from
|
||||
# the runner. Since actions tend to log quite a bit, this
|
||||
# removes the need to prefix `logger` with `@runner` over and
|
||||
# over.
|
||||
def logger
|
||||
runner.env.logger
|
||||
end
|
||||
|
||||
# Initialization of the action, passing any arguments which may have
|
||||
# been given to the {Runner runner}. This method can be used by subclasses
|
||||
# to save any of the configuration options which are passed in.
|
||||
def initialize(runner, options=nil)
|
||||
@runner = runner
|
||||
@options = options || {}
|
||||
end
|
||||
|
||||
# This method is called once per action, allowing the action
|
||||
# to setup any callbacks, add more events, etc. Prepare is
|
||||
# called in the order the actions are defined, and the action
|
||||
# itself has no control over this.
|
||||
#
|
||||
# Examples of its usage:
|
||||
#
|
||||
# Perhaps we need an additional action only if a configuration is set:
|
||||
#
|
||||
# def prepare
|
||||
# @vm.actions << FooAction if Vagrant.config[:foo] == :bar
|
||||
# end
|
||||
#
|
||||
def prepare; end
|
||||
|
||||
# This method is called once, after preparing, to execute the
|
||||
# actual task. This method is responsible for calling any
|
||||
# callbacks. Adding new actions here will have unpredictable
|
||||
# effects and should never be done.
|
||||
#
|
||||
# Examples of its usage:
|
||||
#
|
||||
# def execute!
|
||||
# @vm.invoke_callback(:before_oven, "cookies")
|
||||
# # Do lots of stuff here
|
||||
# @vm.invoke_callback(:after_oven, "more", "than", "one", "option")
|
||||
# end
|
||||
#
|
||||
def execute!; end
|
||||
|
||||
# This method is called after all actions have finished executing.
|
||||
# It is meant as a place where final cleanup code can be done, knowing
|
||||
# that all other actions are finished using your data.
|
||||
def cleanup; end
|
||||
|
||||
# This method is only called if some exception occurs in the chain
|
||||
# of actions. If an exception is raised in any action in the current
|
||||
# chain, then every action part of that chain has {#rescue} called
|
||||
# before raising the exception further. This method should be used to
|
||||
# perform any cleanup necessary in the face of errors.
|
||||
#
|
||||
# **Warning:** Since this method is called when an exception is already
|
||||
# raised, be _extra careful_ when implementing this method to handle
|
||||
# all your own exceptions, otherwise it'll mask the initially raised
|
||||
# exception.
|
||||
def rescue(exception); end
|
||||
|
||||
# The following two methods are used for declaring action dependencies.
|
||||
# For example, you require that the reload action be in place before
|
||||
# a your new FooAction you might do the following
|
||||
#
|
||||
# def follows; [Reload] end
|
||||
|
||||
# This method is called when the runner is determining the actions that
|
||||
# must precede a given action. You would say "This action follows [Action1, Action2]"
|
||||
def follows; [] end
|
||||
|
||||
# This method is called when the runner is determining the actions that
|
||||
# must follow a given action. You would say "This action precedes [Action3, Action4]
|
||||
def precedes; [] end
|
||||
end
|
||||
|
||||
# An exception which occured within an action. This should be used instead of
|
||||
# {Vagrant::Util#error_and_exit error_and_exit}, since it allows the {Runner} to call
|
||||
# {Base#rescue rescue} on all the actions and properly exit. Any message
|
||||
# passed into the {ActionException} is then shown and and vagrant exits.
|
||||
class ActionException < Exception
|
||||
attr_reader :key
|
||||
attr_reader :data
|
||||
|
||||
def initialize(key, data = {})
|
||||
@key = key
|
||||
@data = data
|
||||
|
||||
message = Vagrant::Util::Translator.t(key, data)
|
||||
super(message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module Box
|
||||
# A meta-action which adds a box by downloading and unpackaging it.
|
||||
# This action downloads and unpackages a box with a given URI. This
|
||||
# is a _meta action_, meaning it simply adds more actions to the
|
||||
# action chain, and those actions do the work.
|
||||
#
|
||||
# This is the action called by {Box#add}.
|
||||
class Add < Base
|
||||
def prepare
|
||||
if File.exists?(@runner.directory)
|
||||
raise ActionException.new(:box_add_already_exists, :box_name => @runner.name)
|
||||
end
|
||||
|
||||
@runner.add_action(Download)
|
||||
@runner.add_action(Unpackage)
|
||||
@runner.add_action(Verify)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module Box
|
||||
# Action to destroy a box. This action is not reversible and expects
|
||||
# to be called by a {Box} object.
|
||||
class Destroy < Base
|
||||
def execute!
|
||||
logger.info "Deleting box directory..."
|
||||
FileUtils.rm_rf(@runner.directory)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,67 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module Box
|
||||
# An action which acts on a box by downloading the box file from
|
||||
# the given URI into a temporary location. This action parses a
|
||||
# given URI and handles downloading it via one of the many Vagrant
|
||||
# downloads (such as {Vagrant::Downloaders::File}).
|
||||
#
|
||||
# This action cleans itself up by removing the downloaded box file.
|
||||
class Download < Base
|
||||
BASENAME = "box"
|
||||
BUFFERSIZE = 1048576 # 1 MB
|
||||
|
||||
attr_reader :downloader
|
||||
|
||||
def prepare
|
||||
# Check the URI given and prepare a downloader
|
||||
[Downloaders::HTTP, Downloaders::File].each do |dler|
|
||||
if dler.match?(@runner.uri)
|
||||
logger.info "Downloading via #{dler}..."
|
||||
@downloader = dler.new(@runner.env)
|
||||
end
|
||||
end
|
||||
|
||||
raise ActionException.new(:box_download_unknown_type) unless @downloader
|
||||
|
||||
# Prepare the downloader
|
||||
@downloader.prepare(@runner.uri)
|
||||
end
|
||||
|
||||
def execute!
|
||||
with_tempfile do |tempfile|
|
||||
download_to(tempfile)
|
||||
@runner.temp_path = tempfile.path
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
if @runner.temp_path && File.exist?(@runner.temp_path)
|
||||
logger.info "Cleaning up downloaded box..."
|
||||
File.unlink(@runner.temp_path)
|
||||
end
|
||||
end
|
||||
|
||||
def rescue(exception)
|
||||
cleanup
|
||||
end
|
||||
|
||||
def with_tempfile
|
||||
logger.info "Creating tempfile for storing box file..."
|
||||
File.open(box_temp_path, Platform.tar_file_options) do |tempfile|
|
||||
yield tempfile
|
||||
end
|
||||
end
|
||||
|
||||
def box_temp_path
|
||||
File.join(@runner.env.tmp_path, BASENAME + Time.now.to_i.to_s)
|
||||
end
|
||||
|
||||
def download_to(f)
|
||||
logger.info "Copying box to temporary location..."
|
||||
downloader.download!(@runner.uri, f)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module Box
|
||||
# This action unpackages a downloaded box file into its final
|
||||
# box destination within the vagrant home folder.
|
||||
class Unpackage < Base
|
||||
def execute!
|
||||
@runner.invoke_around_callback(:unpackage) do
|
||||
setup_box_dir
|
||||
decompress
|
||||
end
|
||||
end
|
||||
|
||||
def rescue(exception)
|
||||
if File.directory?(box_dir)
|
||||
logger.info "An error occurred, rolling back box unpackaging..."
|
||||
FileUtils.rm_rf(box_dir)
|
||||
end
|
||||
end
|
||||
|
||||
def setup_box_dir
|
||||
if File.directory?(box_dir)
|
||||
error_and_exit(:box_already_exists, :box_name => @runner.name)
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(box_dir)
|
||||
end
|
||||
|
||||
def box_dir
|
||||
@runner.directory
|
||||
end
|
||||
|
||||
def decompress
|
||||
Dir.chdir(box_dir) do
|
||||
logger.info "Extracting box to #{box_dir}..."
|
||||
Archive::Tar::Minitar.unpack(@runner.temp_path, box_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module Box
|
||||
# This action verifies that a given box is valid. This works by attempting
|
||||
# to read/interpret the appliance file (OVF). If the reading succeeds, then
|
||||
# the box is assumed to be valid.
|
||||
class Verify < Base
|
||||
def execute!
|
||||
logger.info "Verifying box..."
|
||||
reload_configuration
|
||||
verify_appliance
|
||||
end
|
||||
|
||||
def reload_configuration
|
||||
# We have to reload the environment config since we _just_ added the
|
||||
# box. We do this by setting the current box to the recently added box,
|
||||
# then reloading
|
||||
@runner.env.config.vm.box = @runner.name
|
||||
@runner.env.load_box!
|
||||
@runner.env.load_config!
|
||||
end
|
||||
|
||||
def verify_appliance
|
||||
# We now try to read the applince. If it succeeds, we return true.
|
||||
VirtualBox::Appliance.new(@runner.ovf_file)
|
||||
rescue Exception
|
||||
raise ActionException.new(:box_verification_failed)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Collection < Array
|
||||
def dependencies!
|
||||
each_with_index do |action, i|
|
||||
action.follows.each do |klass|
|
||||
unless self[0..i].klasses.include?(klass)
|
||||
raise DependencyNotSatisfiedException.new("#{action.class} action must follow #{klass}")
|
||||
end
|
||||
end
|
||||
|
||||
action.precedes.each do |klass|
|
||||
unless self[i..length].klasses.include?(klass)
|
||||
raise DependencyNotSatisfiedException.new("#{action.class} action must precede #{klass}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def duplicates?
|
||||
klasses.uniq.size != size
|
||||
end
|
||||
|
||||
def duplicates!
|
||||
raise DuplicateActionException.new if duplicates?
|
||||
end
|
||||
|
||||
def klasses
|
||||
map { |o| o.class }
|
||||
end
|
||||
end
|
||||
|
||||
class DuplicateActionException < Exception; end
|
||||
class DependencyNotSatisfiedException < Exception; end
|
||||
end
|
||||
end
|
|
@ -1,131 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
# Base class for any class which will act as a runner
|
||||
# for actions. A runner handles queueing up and executing actions,
|
||||
# and executing the methods of an action in the proper order. The
|
||||
# action runner also handles invoking callbacks that actions may
|
||||
# request.
|
||||
#
|
||||
# # Executing Actions
|
||||
#
|
||||
# Actions can be executed by adding them and executing them all
|
||||
# at once:
|
||||
#
|
||||
# runner = Vagrant::Actions::Runner.new
|
||||
# runner.add_action(FooAction)
|
||||
# runner.add_action(BarAction)
|
||||
# runner.add_action(BazAction)
|
||||
# runner.execute!
|
||||
#
|
||||
# Single actions have a shorthand to be executed:
|
||||
#
|
||||
# Vagrant::Actions::Runner.execute!(FooAction)
|
||||
#
|
||||
# Arguments may be passed into added actions by adding them after
|
||||
# the action class:
|
||||
#
|
||||
# runner.add_action(FooAction, "many", "arguments", "may", "follow")
|
||||
#
|
||||
class Runner
|
||||
include Vagrant::Util
|
||||
|
||||
class << self
|
||||
# Executes a specific action, optionally passing in any arguments to that
|
||||
# action. This method is shorthand to initializing a runner, adding a single
|
||||
# action, and executing it.
|
||||
def execute!(action_klass, *args)
|
||||
runner = new
|
||||
runner.add_action(action_klass, *args)
|
||||
runner.execute!
|
||||
end
|
||||
end
|
||||
|
||||
# Returns an array of all the actions in queue. Because this
|
||||
# will persist accross calls (calling {#actions} twice will yield
|
||||
# exactly the same object), to clear or modify it, use the ruby
|
||||
# array methods which act on `self`, such as `Array#clear`.
|
||||
#
|
||||
# @return [Array]
|
||||
def actions
|
||||
@actions ||= Actions::Collection.new
|
||||
end
|
||||
|
||||
# Returns the first action instance which matches the given class.
|
||||
#
|
||||
# @param [Class] action_klass The action to search for in the queue
|
||||
# @return [Object]
|
||||
def find_action(action_klass)
|
||||
actions.find { |a| a.is_a?(action_klass) }
|
||||
end
|
||||
|
||||
# Add an action to the list of queued actions to execute. This method
|
||||
# appends the given action class to the end of the queue. Any arguments
|
||||
# given after the class are passed into the class constructor.
|
||||
def add_action(action_klass, *args)
|
||||
actions << action_klass.new(self, *args)
|
||||
end
|
||||
|
||||
# Execute the actions in queue. This method can also optionally be used
|
||||
# to execute a single action on an instance. The syntax for executing a
|
||||
# single method on an instance is the same as the {execute!} class method.
|
||||
def execute!(single_action=nil, *args)
|
||||
if single_action
|
||||
actions.clear
|
||||
add_action(single_action, *args)
|
||||
end
|
||||
|
||||
actions.duplicates!
|
||||
actions.dependencies!
|
||||
|
||||
# Call the prepare method on each once its
|
||||
# initialized, then call the execute! method
|
||||
begin
|
||||
[:prepare, :execute!, :cleanup].each do |method|
|
||||
actions.each do |action|
|
||||
action.send(method)
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
# Run the rescue code to do any emergency cleanup
|
||||
actions.each do |action|
|
||||
action.rescue(e)
|
||||
end
|
||||
|
||||
# If its an ActionException, error and exit the message
|
||||
if e.is_a?(ActionException)
|
||||
error_and_exit(e.key, e.data)
|
||||
return
|
||||
end
|
||||
|
||||
# Finally, reraise the exception
|
||||
raise
|
||||
end
|
||||
|
||||
# Clear the actions
|
||||
actions.clear
|
||||
end
|
||||
|
||||
# Invokes an "around callback" which invokes before_name and
|
||||
# after_name for the given callback name, yielding a block between
|
||||
# callback invokations.
|
||||
def invoke_around_callback(name, *args)
|
||||
invoke_callback("before_#{name}".to_sym, *args)
|
||||
yield
|
||||
invoke_callback("after_#{name}".to_sym, *args)
|
||||
end
|
||||
|
||||
# Invokes a single callback. This method will go through each action
|
||||
# and call the method given in the parameter `name` if the action
|
||||
# responds to it.
|
||||
def invoke_callback(name, *args)
|
||||
# Attempt to call the method for the callback on each of the
|
||||
# actions
|
||||
results = []
|
||||
actions.each do |action|
|
||||
results << action.send(name, *args) if action.respond_to?(name)
|
||||
end
|
||||
results
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Boot < Base
|
||||
def execute!
|
||||
@runner.invoke_around_callback(:boot) do
|
||||
# Startup the VM
|
||||
boot
|
||||
|
||||
# Wait for it to complete booting, or error if we could
|
||||
# never detect it booted up successfully
|
||||
if !wait_for_boot
|
||||
error_and_exit(:vm_failed_to_boot)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def boot
|
||||
logger.info "Booting VM..."
|
||||
@runner.vm.start(@runner.env.config.vm.boot_mode)
|
||||
end
|
||||
|
||||
def wait_for_boot(sleeptime=5)
|
||||
logger.info "Waiting for VM to boot..."
|
||||
|
||||
@runner.env.config.ssh.max_tries.to_i.times do |i|
|
||||
logger.info "Trying to connect (attempt ##{i+1} of #{@runner.env.config[:ssh][:max_tries]})..."
|
||||
|
||||
if @runner.ssh.up?
|
||||
logger.info "VM booted and ready for use!"
|
||||
return true
|
||||
end
|
||||
|
||||
sleep sleeptime
|
||||
end
|
||||
|
||||
logger.info "Failed to connect to VM! Failed to boot?"
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Customize < Base
|
||||
def execute!
|
||||
if !runner.env.config.vm.proc_stack.empty?
|
||||
logger.info "Running any VM customizations..."
|
||||
|
||||
# Run the customization procs over the VM
|
||||
runner.env.config.vm.run_procs!(@runner.vm)
|
||||
|
||||
# Save the vm
|
||||
runner.vm.save
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Destroy < Base
|
||||
def execute!
|
||||
@runner.invoke_around_callback(:destroy) do
|
||||
destroy_vm
|
||||
update_dotfile
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_vm
|
||||
logger.info "Destroying VM and associated drives..."
|
||||
@runner.vm.destroy(:destroy_medium => :delete)
|
||||
@runner.vm = nil
|
||||
end
|
||||
|
||||
def update_dotfile
|
||||
@runner.env.update_dotfile
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Down < Base
|
||||
def prepare
|
||||
# The true as the 2nd parameter always forces the shutdown so its
|
||||
# fast (since we're destroying anyways)
|
||||
@runner.add_action(Halt, :force => true) if @runner.vm.running?
|
||||
@runner.add_action(Network)
|
||||
@runner.add_action(Destroy)
|
||||
end
|
||||
|
||||
def after_halt
|
||||
# This sleep is necessary to wait for the VM to clean itself up.
|
||||
# There appears to be nothing in the API that does this "wait"
|
||||
# for us.
|
||||
Kernel.sleep(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,45 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Export < Base
|
||||
attr_reader :temp_dir
|
||||
|
||||
def execute!
|
||||
setup_temp_dir
|
||||
export
|
||||
end
|
||||
|
||||
def cleanup
|
||||
if temp_dir
|
||||
logger.info "Removing temporary export directory..."
|
||||
FileUtils.rm_r(temp_dir)
|
||||
end
|
||||
end
|
||||
|
||||
def rescue(exception)
|
||||
cleanup
|
||||
end
|
||||
|
||||
def setup_temp_dir
|
||||
@temp_dir = File.join(@runner.env.tmp_path, Time.now.to_i.to_s)
|
||||
|
||||
logger.info "Creating temporary directory for export..."
|
||||
FileUtils.mkpath(temp_dir)
|
||||
end
|
||||
|
||||
def ovf_path
|
||||
File.join(temp_dir, @runner.env.config.vm.box_ovf)
|
||||
end
|
||||
|
||||
def export
|
||||
logger.info "Exporting VM to #{ovf_path}..."
|
||||
@runner.vm.export(ovf_path) do |progress|
|
||||
logger.report_progress(progress.percent, 100, false)
|
||||
end
|
||||
|
||||
logger.clear_progress
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,24 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Halt < Base
|
||||
def execute!
|
||||
raise ActionException.new(:vm_not_running) unless @runner.vm.running?
|
||||
|
||||
@runner.invoke_around_callback(:halt) do
|
||||
@runner.system.halt if !options[:force]
|
||||
|
||||
if @runner.vm.state(true) != :powered_off
|
||||
logger.info "Forcing shutdown of VM..."
|
||||
@runner.vm.stop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def force?
|
||||
!!options[:force]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,23 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Import < Base
|
||||
def execute!
|
||||
@runner.invoke_around_callback(:import) do
|
||||
Busy.busy do
|
||||
logger.info "Importing base VM (#{@runner.env.box.ovf_file})..."
|
||||
# Use the first argument passed to the action
|
||||
@runner.vm = VirtualBox::VM.import(@runner.env.box.ovf_file) do |progress|
|
||||
logger.report_progress(progress.percent, 100, false)
|
||||
end
|
||||
|
||||
logger.clear_progress
|
||||
|
||||
raise ActionException.new(:virtualbox_import_failure) unless @runner.vm
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,51 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class MoveHardDrive < Base
|
||||
def execute!
|
||||
unless @runner.powered_off?
|
||||
error_and_exit(:vm_power_off_to_move_hd)
|
||||
return
|
||||
end
|
||||
|
||||
destroy_drive_after { clone_and_attach }
|
||||
end
|
||||
|
||||
def hard_drive
|
||||
@hard_drive ||= find_hard_drive
|
||||
end
|
||||
|
||||
# TODO won't work if the first disk is not the boot disk or even if there are multiple disks
|
||||
def find_hard_drive
|
||||
@runner.vm.storage_controllers.each do |sc|
|
||||
sc.devices.each do |d|
|
||||
return d if d.image.is_a?(VirtualBox::HardDrive)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clone_and_attach
|
||||
logger.info "Cloning current VM Disk to new location (#{new_image_path})..."
|
||||
hard_drive.image = hard_drive.image.clone(new_image_path, @runner.env.config.vm.disk_image_format, true)
|
||||
|
||||
logger.info "Attaching new disk to VM ..."
|
||||
@runner.vm.save
|
||||
end
|
||||
|
||||
def destroy_drive_after
|
||||
old_image = hard_drive.image
|
||||
|
||||
yield
|
||||
|
||||
logger.info "Destroying old VM Disk (#{old_image.filename})..."
|
||||
old_image.destroy(true)
|
||||
end
|
||||
|
||||
# Returns the path to the new location for the hard drive
|
||||
def new_image_path
|
||||
File.join(@runner.env.config.vm.hd_location, hard_drive.image.filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,94 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Package < Base
|
||||
attr_reader :export_action
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
@temp_path = nil
|
||||
end
|
||||
|
||||
def prepare
|
||||
raise ActionException.new(:box_file_exists, :output_file => tar_path) if File.exist?(tar_path)
|
||||
|
||||
# Verify the existance of all the additional files, if any
|
||||
include_files.each do |file|
|
||||
raise ActionException.new(:package_include_file_doesnt_exist, :filename => file) unless File.exists?(file)
|
||||
end
|
||||
|
||||
# Get the export action and store a reference to it
|
||||
@export_action = @runner.find_action(Export)
|
||||
raise ActionException.new(:packaged_requires_export) unless @export_action
|
||||
end
|
||||
|
||||
def execute!
|
||||
compress
|
||||
end
|
||||
|
||||
def out_path
|
||||
options[:output] || "package"
|
||||
end
|
||||
|
||||
def include_files
|
||||
options[:include] || []
|
||||
end
|
||||
|
||||
def tar_path
|
||||
File.join(FileUtils.pwd, "#{out_path}#{@runner.env.config.package.extension}")
|
||||
end
|
||||
|
||||
def temp_path
|
||||
export_action.temp_dir
|
||||
end
|
||||
|
||||
# This method copies the include files (passed in via command line)
|
||||
# to the temporary directory so they are included in a sub-folder within
|
||||
# the actual box
|
||||
def copy_include_files
|
||||
if include_files.length > 0
|
||||
include_dir = File.join(temp_path, "include")
|
||||
FileUtils.mkdir_p(include_dir)
|
||||
|
||||
include_files.each do |f|
|
||||
logger.info "Packaging additional file: #{f}"
|
||||
FileUtils.cp(f, include_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This method creates the auto-generated Vagrantfile at the root of the
|
||||
# box. This Vagrantfile contains the MAC address so that the user doesn't
|
||||
# have to worry about it.
|
||||
def create_vagrantfile
|
||||
File.open(File.join(temp_path, "Vagrantfile"), "w") do |f|
|
||||
f.write(TemplateRenderer.render("package_Vagrantfile", {
|
||||
:base_mac => @runner.vm.network_adapters.first.mac_address
|
||||
}))
|
||||
end
|
||||
end
|
||||
|
||||
def compress
|
||||
logger.info "Packaging VM into #{tar_path}..."
|
||||
File.open(tar_path, Platform.tar_file_options) do |tar|
|
||||
Archive::Tar::Minitar::Output.open(tar) do |output|
|
||||
begin
|
||||
current_dir = FileUtils.pwd
|
||||
|
||||
copy_include_files
|
||||
create_vagrantfile
|
||||
|
||||
FileUtils.cd(temp_path)
|
||||
Dir.glob(File.join(".", "**", "*")).each do |entry|
|
||||
Archive::Tar::Minitar.pack_file(entry, output)
|
||||
end
|
||||
ensure
|
||||
FileUtils.cd(current_dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,49 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Provision < Base
|
||||
attr_reader :provisioner
|
||||
|
||||
def intialize(*args)
|
||||
super
|
||||
|
||||
@provisioner = nil
|
||||
end
|
||||
|
||||
def prepare
|
||||
provisioner = @runner.env.config.vm.provisioner
|
||||
|
||||
if provisioner.nil?
|
||||
logger.info("Provisioning not enabled, ignoring this step")
|
||||
return
|
||||
end
|
||||
|
||||
if provisioner.is_a?(Class)
|
||||
@provisioner = provisioner.new(@runner)
|
||||
raise ActionException.new(:provisioner_invalid_class) unless @provisioner.is_a?(Provisioners::Base)
|
||||
elsif provisioner.is_a?(Symbol)
|
||||
# We have a few hard coded provisioners for built-ins
|
||||
mapping = {
|
||||
:chef_solo => Provisioners::ChefSolo,
|
||||
:chef_server => Provisioners::ChefServer
|
||||
}
|
||||
|
||||
provisioner_klass = mapping[provisioner]
|
||||
raise ActionException.new(:provisioner_unknown_type, :provisioner => provisioner.to_s) if provisioner_klass.nil?
|
||||
@provisioner = provisioner_klass.new(@runner)
|
||||
end
|
||||
|
||||
logger.info "Provisioning enabled with #{@provisioner.class}"
|
||||
@provisioner.prepare
|
||||
end
|
||||
|
||||
def execute!
|
||||
if provisioner
|
||||
logger.info "Beginning provisioning process..."
|
||||
provisioner.provision!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Reload < Base
|
||||
def prepare
|
||||
steps = [Customize, ForwardPorts, SharedFolders, Network, Boot]
|
||||
steps.unshift(Halt) if @runner.vm.running?
|
||||
steps << Provision if !@runner.env.config.vm.provisioner.nil?
|
||||
|
||||
steps.each do |action_klass|
|
||||
@runner.add_action(action_klass)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Resume < Base
|
||||
def execute!
|
||||
if !@runner.vm.saved?
|
||||
raise ActionException.new(:vm_not_suspended)
|
||||
end
|
||||
|
||||
logger.info "Resuming suspended VM..."
|
||||
@runner.start
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,26 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Start < Base
|
||||
def prepare
|
||||
# Start is a "meta-action" so it really just queues up a bunch
|
||||
# of other actions in its place:
|
||||
steps = [Boot]
|
||||
if !@runner.vm || !@runner.vm.saved?
|
||||
steps.unshift([Customize, ForwardPorts, SharedFolders, Network])
|
||||
steps << Provision if provision?
|
||||
end
|
||||
|
||||
steps.flatten.each do |action_klass|
|
||||
@runner.add_action(action_klass, options)
|
||||
end
|
||||
end
|
||||
|
||||
def provision?
|
||||
enabled = options[:provision].nil? ? true : options[:provision]
|
||||
!@runner.env.config.vm.provisioner.nil? && enabled
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Suspend < Base
|
||||
def execute!
|
||||
if !@runner.vm.running?
|
||||
raise ActionException.new(:vm_not_running_for_suspend)
|
||||
end
|
||||
|
||||
logger.info "Saving VM state and suspending execution..."
|
||||
@runner.vm.save_state
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,53 +0,0 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
module VM
|
||||
class Up < Base
|
||||
def prepare
|
||||
# If the dotfile is not a file, raise error
|
||||
if File.exist?(@runner.env.dotfile_path) && !File.file?(@runner.env.dotfile_path)
|
||||
raise ActionException.new(:dotfile_error, :env => @runner.env)
|
||||
end
|
||||
|
||||
# Up is a "meta-action" so it really just queues up a bunch
|
||||
# of other actions in its place:
|
||||
steps = [Import, Start]
|
||||
steps.insert(0, MoveHardDrive) if @runner.env.config.vm.hd_location
|
||||
|
||||
steps.each do |action_klass|
|
||||
@runner.add_action(action_klass, options)
|
||||
end
|
||||
end
|
||||
|
||||
def after_import
|
||||
update_dotfile
|
||||
setup_mac_address
|
||||
check_guest_additions
|
||||
end
|
||||
|
||||
def update_dotfile
|
||||
logger.info "Persisting the VM UUID (#{@runner.uuid})..."
|
||||
@runner.env.update_dotfile
|
||||
end
|
||||
|
||||
def setup_mac_address
|
||||
logger.info "Matching MAC addresses..."
|
||||
@runner.vm.network_adapters.first.mac_address = @runner.env.config.vm.base_mac
|
||||
@runner.vm.save
|
||||
end
|
||||
|
||||
def check_guest_additions
|
||||
# Use the raw interface for now, while the virtualbox gem
|
||||
# doesn't support guest properties (due to cross platform issues)
|
||||
version = @runner.vm.interface.get_guest_property_value("/VirtualBox/GuestAdd/Version")
|
||||
if version.empty?
|
||||
logger.error Translator.t(:vm_additions_not_detected)
|
||||
elsif version != VirtualBox.version
|
||||
logger.error Translator.t(:vm_additions_version_mismatch,
|
||||
:guest_additions_version => version,
|
||||
:virtualbox_version => VirtualBox.version)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -40,7 +40,7 @@ module Vagrant
|
|||
# box = Vagrant::Box.find("foo")
|
||||
# box.destroy
|
||||
#
|
||||
class Box < Actions::Runner
|
||||
class Box
|
||||
# The name of the box.
|
||||
attr_accessor :name
|
||||
|
||||
|
@ -133,12 +133,12 @@ module Vagrant
|
|||
# method requires that `name` and `uri` be set. The logic of this method
|
||||
# is kicked out to the {Actions::Box::Add add box} action.
|
||||
def add
|
||||
execute!(Actions::Box::Add)
|
||||
env.actions.run(:box_add, { "box" => self })
|
||||
end
|
||||
|
||||
# Beings the process of destroying this box.
|
||||
def destroy
|
||||
execute!(Actions::Box::Destroy)
|
||||
env.actions.run(:box_remove, { "box" => self })
|
||||
end
|
||||
|
||||
# Returns the directory to the location of this boxes content in the local
|
||||
|
|
|
@ -53,11 +53,6 @@ module Vagrant
|
|||
end
|
||||
|
||||
def package_vm(vm)
|
||||
if !vm.powered_off?
|
||||
error_and_exit(:vm_power_off_to_package)
|
||||
return # for tests
|
||||
end
|
||||
|
||||
vm.package(options)
|
||||
end
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ module Vagrant
|
|||
|
||||
def prepare(source_url)
|
||||
if !::File.file?(source_url)
|
||||
raise Actions::ActionException.new(:downloader_file_doesnt_exist, :source_url => source_url)
|
||||
raise Action::ActionException.new(:downloader_file_doesnt_exist, :source_url => source_url)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ module Vagrant
|
|||
attr_reader :active_list
|
||||
attr_reader :commands
|
||||
attr_reader :logger
|
||||
attr_reader :actions
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Class Methods
|
||||
|
@ -142,6 +143,7 @@ module Vagrant
|
|||
load_vm!
|
||||
load_active_list!
|
||||
load_commands!
|
||||
load_actions!
|
||||
self
|
||||
end
|
||||
|
||||
|
@ -301,6 +303,13 @@ module Vagrant
|
|||
@commands = Command.new(self)
|
||||
end
|
||||
|
||||
# Loads the instance of {Action} for this environment. This allows
|
||||
# users of the instance to run action sequences in the context of
|
||||
# this environment.
|
||||
def load_actions!
|
||||
@actions = Action.new(self)
|
||||
end
|
||||
|
||||
#---------------------------------------------------------------
|
||||
# Methods to manage VM
|
||||
#---------------------------------------------------------------
|
||||
|
|
|
@ -7,19 +7,27 @@ module Vagrant
|
|||
class Base
|
||||
include Vagrant::Util
|
||||
|
||||
# The VM which this is being provisioned for
|
||||
attr_reader :vm
|
||||
# The environment which provisioner is running in. This is a
|
||||
# {Vagrant::Action::Environment}
|
||||
attr_reader :action_env
|
||||
|
||||
def initialize(vm)
|
||||
@vm = vm
|
||||
def initialize(env)
|
||||
@action_env = env
|
||||
end
|
||||
|
||||
# This method returns the environment which the provisioner is working
|
||||
# on. This is also the environment of the VM. This method is provided
|
||||
# as a simple helper since the environment is often used throughout the
|
||||
# provisioner.
|
||||
# Returns the actual {Vagrant::Environment} which this provisioner
|
||||
# represents.
|
||||
#
|
||||
# @return [Vagrant::Environment]
|
||||
def env
|
||||
@vm.env
|
||||
action_env.env
|
||||
end
|
||||
|
||||
# Returns the VM which this provisioner is working on.
|
||||
#
|
||||
# @return [Vagrant::VM]
|
||||
def vm
|
||||
env.vm
|
||||
end
|
||||
|
||||
# This method returns the environment's logger as a convenience
|
||||
|
|
|
@ -72,7 +72,7 @@ module Vagrant
|
|||
Config.configures :chef, ChefConfig
|
||||
|
||||
def prepare
|
||||
raise Actions::ActionException.new(:chef_base_invalid_provisioner)
|
||||
action_env.error!(:chef_base_invalid_provisioner)
|
||||
end
|
||||
|
||||
def verify_binary(binary)
|
||||
|
|
|
@ -5,13 +5,11 @@ module Vagrant
|
|||
class ChefServer < Chef
|
||||
def prepare
|
||||
if env.config.chef.validation_key_path.nil?
|
||||
raise Actions::ActionException.new(:chef_server_validation_key_required)
|
||||
action_env.error!(:chef_server_validation_key_required)
|
||||
elsif !File.file?(validation_key_path)
|
||||
raise Actions::ActionException.new(:chef_server_validation_key_doesnt_exist)
|
||||
end
|
||||
|
||||
if env.config.chef.chef_server_url.nil?
|
||||
raise Actions::ActionException.new(:chef_server_url_required)
|
||||
action_env.error!(:chef_server_validation_key_doesnt_exist)
|
||||
elsif env.config.chef.chef_server_url.nil?
|
||||
action_env.error!(:chef_server_url_required)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ module Vagrant
|
|||
}
|
||||
}.merge(options || {})
|
||||
|
||||
raise Actions::ActionException.new(options[:error_key], options[:error_data])
|
||||
raise Action::ActionException.new(options[:error_key], options[:error_data])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -119,7 +119,7 @@ module Vagrant
|
|||
break unless result
|
||||
|
||||
attempts += 1
|
||||
raise Actions::ActionException.new(:vm_mount_fail) if attempts >= 10
|
||||
raise Action::ActionException.new(:vm_mount_fail) if attempts >= 10
|
||||
sleep sleeptime
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module Vagrant
|
||||
class VM < Actions::Runner
|
||||
class VM
|
||||
include Vagrant::Util
|
||||
|
||||
attr_reader :env
|
||||
|
@ -94,43 +94,41 @@ module Vagrant
|
|||
end
|
||||
|
||||
def package(options=nil)
|
||||
add_action(Actions::VM::Export, options)
|
||||
add_action(Actions::VM::Package, options)
|
||||
execute!
|
||||
env.actions.run(:package, options)
|
||||
end
|
||||
|
||||
def up(options=nil)
|
||||
execute!(Actions::VM::Up, options)
|
||||
env.actions.run(:up, options)
|
||||
end
|
||||
|
||||
def start
|
||||
return if @vm.running?
|
||||
|
||||
execute!(Actions::VM::Start)
|
||||
env.actions.run(:start)
|
||||
end
|
||||
|
||||
def halt(options=nil)
|
||||
execute!(Actions::VM::Halt, options)
|
||||
env.actions.run(:halt, options)
|
||||
end
|
||||
|
||||
def reload
|
||||
execute!(Actions::VM::Reload)
|
||||
env.actions.run(:reload)
|
||||
end
|
||||
|
||||
def provision
|
||||
execute!(Actions::VM::Provision)
|
||||
env.actions.run(:provision)
|
||||
end
|
||||
|
||||
def destroy
|
||||
execute!(Actions::VM::Down)
|
||||
env.actions.run(:destroy)
|
||||
end
|
||||
|
||||
def suspend
|
||||
execute!(Actions::VM::Suspend)
|
||||
env.actions.run(:suspend)
|
||||
end
|
||||
|
||||
def resume
|
||||
execute!(Actions::VM::Resume)
|
||||
env.actions.run(:resume)
|
||||
end
|
||||
|
||||
def saved?
|
||||
|
|
|
@ -250,8 +250,6 @@
|
|||
Failed to connect to VM! Failed to boot?
|
||||
:vm_base_not_found: |-
|
||||
The specified base VM "<%= name %>" was not found.
|
||||
:vm_not_running: |-
|
||||
VM is not running! Nothing to shut down!
|
||||
:vm_not_running_for_suspend: |-
|
||||
The vagrant virtual environment you are trying to suspend must be running to be suspended.
|
||||
:vm_not_suspended: |-
|
||||
|
|
|
@ -94,30 +94,10 @@ class Test::Unit::TestCase
|
|||
vm
|
||||
end
|
||||
|
||||
# Sets up the mocks and instantiates an action for testing
|
||||
def mock_action(action_klass, *args)
|
||||
vm = mock("vboxvm")
|
||||
mock_vm = mock("vm")
|
||||
action = action_klass.new(mock_vm, *args)
|
||||
stub_default_action_dependecies(action)
|
||||
|
||||
mock_vm.stubs(:name).returns("foo")
|
||||
mock_vm.stubs(:vm).returns(vm)
|
||||
mock_vm.stubs(:vm=)
|
||||
mock_vm.stubs(:invoke_callback)
|
||||
mock_vm.stubs(:invoke_around_callback).yields
|
||||
mock_vm.stubs(:actions).returns([action])
|
||||
mock_vm.stubs(:env).returns(mock_environment)
|
||||
mock_vm.env.stubs(:logger).returns(quiet_logger("mock"))
|
||||
|
||||
mock_ssh = Vagrant::SSH.new(mock_vm.env)
|
||||
mock_ssh.stubs(:execute)
|
||||
|
||||
mock_vm.stubs(:ssh).returns(mock_ssh)
|
||||
|
||||
vm.stubs(:env).returns(mock_vm.env)
|
||||
|
||||
[mock_vm, vm, action]
|
||||
def mock_action_data
|
||||
app = lambda { |env| }
|
||||
env = Vagrant::Action::Environment.new(mock_environment)
|
||||
[app, env]
|
||||
end
|
||||
|
||||
# Returns a resource logger which is safe for tests
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class DestroyBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::Box::Destroy
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
@env["box"] = Vagrant::Box.new(mock_environment, "foo")
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
@env.logger.stubs(:info)
|
||||
end
|
||||
|
||||
should "delete the box directory" do
|
||||
seq = sequence("seq")
|
||||
FileUtils.expects(:rm_rf).with(@env["box"].directory).in_sequence(seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(seq)
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,141 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class DownloadBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::Box::Download
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
@env["box"] = Vagrant::Box.new(mock_environment, "foo")
|
||||
@env["box"].uri = "http://google.com"
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
should "initialize download classes" do
|
||||
@klass.new(@app, @env)
|
||||
assert_equal [Vagrant::Downloaders::HTTP, Vagrant::Downloaders::File], @env["download.classes"]
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "call the proper methods in sequence" do
|
||||
seq = sequence("seq")
|
||||
@instance.expects(:instantiate_downloader).in_sequence(seq).returns(true)
|
||||
@instance.expects(:download).in_sequence(seq)
|
||||
@app.expects(:call).with(@env).in_sequence(seq)
|
||||
@instance.expects(:cleanup).in_sequence(seq)
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt the chain if downloader instantiation fails" do
|
||||
seq = sequence("seq")
|
||||
@env.error!(:foo)
|
||||
@instance.expects(:instantiate_downloader).in_sequence(seq).returns(false)
|
||||
@instance.expects(:download).never
|
||||
@app.expects(:call).with(@env).never
|
||||
@instance.expects(:cleanup).never
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
|
||||
context "instantiating downloader" do
|
||||
should "instantiate the proper class" do
|
||||
instance = mock("instance")
|
||||
Vagrant::Downloaders::HTTP.expects(:new).with(@env["box"].uri).returns(instance)
|
||||
instance.expects(:prepare).with(@env["box"].uri).once
|
||||
assert @instance.instantiate_downloader
|
||||
end
|
||||
|
||||
should "error environment if URI is invalid for any downloaders" do
|
||||
@env["box"].uri = "foobar"
|
||||
assert !@instance.instantiate_downloader
|
||||
assert @env.error?
|
||||
assert_equal :box_download_unknown_type, @env.error.first
|
||||
end
|
||||
end
|
||||
|
||||
context "downloading" do
|
||||
setup do
|
||||
@path = "foo"
|
||||
|
||||
@tempfile = mock("tempfile")
|
||||
@tempfile.stubs(:path).returns(@path)
|
||||
|
||||
@instance.stubs(:with_tempfile).yields(@tempfile)
|
||||
@instance.stubs(:download_to)
|
||||
end
|
||||
|
||||
should "make a tempfile and copy the URI contents to it" do
|
||||
@instance.expects(:with_tempfile).yields(@tempfile)
|
||||
@instance.expects(:download_to).with(@tempfile)
|
||||
@instance.download
|
||||
end
|
||||
|
||||
should "save the tempfile path" do
|
||||
@instance.download
|
||||
assert @env.has_key?("download.temp_path")
|
||||
assert_equal @tempfile.path, @env["download.temp_path"]
|
||||
assert_equal @tempfile.path, @instance.temp_path
|
||||
end
|
||||
end
|
||||
|
||||
context "tempfile" do
|
||||
should "create a tempfile in the vagrant tmp directory" do
|
||||
File.expects(:open).with { |name, bitmask|
|
||||
name =~ /#{Vagrant::Action::Box::Download::BASENAME}/ && name =~ /#{@env.env.tmp_path}/
|
||||
}.once
|
||||
@instance.with_tempfile
|
||||
end
|
||||
|
||||
should "yield the tempfile object" do
|
||||
@tempfile = mock("tempfile")
|
||||
File.expects(:open).yields(@tempfile)
|
||||
|
||||
@instance.with_tempfile do |otherfile|
|
||||
assert @tempfile.equal?(otherfile)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "cleaning up" do
|
||||
setup do
|
||||
@temp_path = "foo"
|
||||
@instance.stubs(:temp_path).returns(@temp_path)
|
||||
File.stubs(:exist?).returns(true)
|
||||
end
|
||||
|
||||
should "delete the temporary file if it exists" do
|
||||
File.expects(:unlink).with(@temp_path).once
|
||||
@instance.cleanup
|
||||
end
|
||||
|
||||
should "not delete anything if it doesn't exist" do
|
||||
File.stubs(:exist?).returns(false)
|
||||
File.expects(:unlink).never
|
||||
@instance.cleanup
|
||||
end
|
||||
end
|
||||
|
||||
context "downloading to" do
|
||||
setup do
|
||||
@downloader = mock("downloader")
|
||||
@instance.instance_variable_set(:@downloader, @downloader)
|
||||
end
|
||||
|
||||
should "call download! on the download with the URI and tempfile" do
|
||||
tempfile = "foo"
|
||||
@downloader.expects(:download!).with(@env["box"].uri, tempfile)
|
||||
@instance.download_to(tempfile)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,103 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class UnpackageBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::Box::Unpackage
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
@env["box"] = Vagrant::Box.new(mock_environment, "foo")
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "call the proper chain" do
|
||||
seq = sequence("sequence")
|
||||
@instance.expects(:setup_box_directory).in_sequence(seq).returns(true)
|
||||
@instance.expects(:decompress).in_sequence(seq)
|
||||
@app.expects(:call).with(@env)
|
||||
@instance.expects(:cleanup).never
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt the chain if setting up the box directory fails" do
|
||||
@instance.expects(:setup_box_directory).returns(false)
|
||||
@instance.expects(:decompress).never
|
||||
@app.expects(:call).never
|
||||
@instance.expects(:cleanup).never
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "cleanup if there was an error" do
|
||||
@env.error!(:foo)
|
||||
|
||||
seq = sequence("sequence")
|
||||
@instance.expects(:setup_box_directory).in_sequence(seq).returns(true)
|
||||
@instance.expects(:decompress).in_sequence(seq)
|
||||
@app.expects(:call).with(@env)
|
||||
@instance.expects(:cleanup).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
|
||||
context "cleaning up" do
|
||||
setup do
|
||||
@instance.stubs(:box_directory).returns("foo")
|
||||
File.stubs(:directory?).returns(false)
|
||||
FileUtils.stubs(:rm_rf)
|
||||
end
|
||||
|
||||
should "do nothing if not a directory" do
|
||||
FileUtils.expects(:rm_rf).never
|
||||
@instance.cleanup
|
||||
end
|
||||
|
||||
should "remove the directory if exists" do
|
||||
File.expects(:directory?).with(@instance.box_directory).once.returns(true)
|
||||
FileUtils.expects(:rm_rf).with(@instance.box_directory).once
|
||||
@instance.cleanup
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up the box directory" do
|
||||
setup do
|
||||
File.stubs(:directory?).returns(false)
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
end
|
||||
|
||||
should "error the environment if the box already exists" do
|
||||
File.expects(:directory?).returns(true)
|
||||
assert !@instance.setup_box_directory
|
||||
assert @env.error?
|
||||
assert_equal :box_already_exists, @env.error.first
|
||||
end
|
||||
|
||||
should "create the directory" do
|
||||
FileUtils.expects(:mkdir_p).with(@env["box"].directory).once
|
||||
@instance.setup_box_directory
|
||||
end
|
||||
end
|
||||
|
||||
context "decompressing" do
|
||||
setup do
|
||||
@env["download.temp_path"] = "bar"
|
||||
|
||||
Dir.stubs(:chdir).yields
|
||||
end
|
||||
|
||||
should "change to the box directory" do
|
||||
Dir.expects(:chdir).with(@env["box"].directory)
|
||||
@instance.decompress
|
||||
end
|
||||
|
||||
should "open the tar file within the new directory, and extract it all" do
|
||||
Archive::Tar::Minitar.expects(:unpack).with(@env["download.temp_path"], @env["box"].directory).once
|
||||
@instance.decompress
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class VerifyBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::Box::Verify
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
@env["box"] = Vagrant::Box.new(mock_environment, "foo")
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
@env.logger.stubs(:info)
|
||||
end
|
||||
|
||||
should "continue fine if verification succeeds" do
|
||||
seq = sequence("seq")
|
||||
VirtualBox::Appliance.expects(:new).with(@env["box"].ovf_file).in_sequence(seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(seq)
|
||||
@instance.call(@env)
|
||||
assert !@env.error?
|
||||
end
|
||||
|
||||
should "halt chain if verification fails" do
|
||||
VirtualBox::Appliance.expects(:new).with(@env["box"].ovf_file).raises(Exception)
|
||||
@app.expects(:call).with(@env).never
|
||||
@instance.call(@env)
|
||||
assert @env.error?
|
||||
assert_equal :box_verification_failed, @env.error.first
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,207 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ActionBuilderTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::Builder
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
should "setup empty middleware stack" do
|
||||
builder = @klass.new
|
||||
assert builder.stack.empty?
|
||||
end
|
||||
|
||||
should "take block to setup stack" do
|
||||
builder = @klass.new do
|
||||
use Hash
|
||||
use lambda { |i| i }
|
||||
end
|
||||
|
||||
assert !builder.stack.empty?
|
||||
assert_equal 2, builder.stack.length
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
@instance = @klass.new
|
||||
end
|
||||
|
||||
context "adding to the stack" do
|
||||
should "return self" do
|
||||
assert @instance.equal?(@instance.use(1))
|
||||
end
|
||||
|
||||
should "add to the end" do
|
||||
@instance.use 1
|
||||
@instance.use 2
|
||||
assert_equal [2, [], nil], @instance.stack.last
|
||||
end
|
||||
|
||||
should "merge in other builder's stack" do
|
||||
other = @klass.new do
|
||||
use 2
|
||||
use 3
|
||||
end
|
||||
|
||||
@instance.use 1
|
||||
@instance.use other
|
||||
assert_equal 3, @instance.stack.length
|
||||
end
|
||||
end
|
||||
|
||||
context "flatten" do
|
||||
should "return the flattened format of the builder" do
|
||||
env = Vagrant::Action::Environment.new(nil)
|
||||
env.expects(:foo).once
|
||||
|
||||
func = lambda { |x| x.foo }
|
||||
@instance.use func
|
||||
proc = @instance.flatten
|
||||
assert proc.respond_to?(:call)
|
||||
proc.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
context "inserting" do
|
||||
setup do
|
||||
@instance.use "1"
|
||||
@instance.use "2"
|
||||
end
|
||||
|
||||
should "insert at the proper numeric index" do
|
||||
@instance.insert(1, "3")
|
||||
assert_equal "3", @instance.stack[1].first
|
||||
end
|
||||
|
||||
should "insert next to the proper object if given" do
|
||||
@instance.insert("2", "3")
|
||||
assert_equal "3", @instance.stack[1].first
|
||||
end
|
||||
|
||||
should "be able to call insert_before as well" do
|
||||
@instance.insert_before("1", "0")
|
||||
assert_equal "0", @instance.stack.first.first
|
||||
end
|
||||
|
||||
should "be able to insert_after" do
|
||||
@instance.insert_after("1", "0")
|
||||
assert_equal "0", @instance.stack[1].first
|
||||
end
|
||||
|
||||
should "be able to insert_after using numeric index" do
|
||||
@instance.insert_after(1, "0")
|
||||
assert_equal "0", @instance.stack[2].first
|
||||
end
|
||||
|
||||
should "raise an exception if invalid index" do
|
||||
assert_raises(RuntimeError) {
|
||||
@instance.insert_after("15", "0")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context "swapping" do
|
||||
setup do
|
||||
@instance.use "1"
|
||||
@instance.use "2"
|
||||
end
|
||||
|
||||
should "be able to swap using the object" do
|
||||
@instance.swap "1", "3"
|
||||
assert_equal "3", @instance.stack.first.first
|
||||
end
|
||||
|
||||
should "be able to swap using the index" do
|
||||
@instance.swap 0, "3"
|
||||
assert_equal "3", @instance.stack.first.first
|
||||
end
|
||||
end
|
||||
|
||||
context "deleting" do
|
||||
setup do
|
||||
@instance.use "1"
|
||||
end
|
||||
|
||||
should "delete the proper object" do
|
||||
@instance.delete("1")
|
||||
assert @instance.stack.empty?
|
||||
end
|
||||
|
||||
should "delete by index if given" do
|
||||
@instance.delete(0)
|
||||
assert @instance.stack.empty?
|
||||
end
|
||||
end
|
||||
|
||||
context "getting an index of an object" do
|
||||
should "return the proper index if it exists" do
|
||||
@instance.use 1
|
||||
@instance.use 2
|
||||
@instance.use 3
|
||||
assert_equal 1, @instance.index(2)
|
||||
end
|
||||
end
|
||||
|
||||
context "converting to an app" do
|
||||
teardown do
|
||||
Vagrant::Action.actions.clear
|
||||
end
|
||||
|
||||
should "preprend error halt to the chain" do
|
||||
result = mock("result")
|
||||
env = {:a => :b}
|
||||
middleware = mock("middleware")
|
||||
middleware.stubs(:is_a?).with(Class).returns(true)
|
||||
middleware.expects(:new).with(anything, env).returns(result)
|
||||
@instance.use middleware
|
||||
result = @instance.to_app(env)
|
||||
assert result.kind_of?(Vagrant::Action::ErrorHalt)
|
||||
end
|
||||
|
||||
should "make non-classes lambdas" do
|
||||
env = Vagrant::Action::Environment.new(nil)
|
||||
env.expects(:foo).once
|
||||
|
||||
func = lambda { |x| x.foo }
|
||||
@instance.use func
|
||||
@instance.to_app(env).call(env)
|
||||
end
|
||||
|
||||
should "raise exception if given invalid middleware" do
|
||||
@instance.use 7
|
||||
assert_raises(RuntimeError) {
|
||||
@instance.to_app(nil)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
def mock_middleware
|
||||
middleware = Class.new do
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "convert to an app then call with the env" do
|
||||
mw = mock_middleware
|
||||
mw.any_instance.expects(:call).with() do |env|
|
||||
assert env.has_key?(:key)
|
||||
true
|
||||
end
|
||||
|
||||
env = Vagrant::Action::Environment.new(nil)
|
||||
env[:key] = :value
|
||||
|
||||
@instance.use(mw)
|
||||
@instance.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ActionEnvironmentTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::Environment
|
||||
@instance = @klass.new(mock_environment)
|
||||
end
|
||||
|
||||
should "default values to those on the env" do
|
||||
@instance.env.stubs(:key).returns("value")
|
||||
assert_equal "value", @instance["key"]
|
||||
end
|
||||
|
||||
should "setup the logger" do
|
||||
assert_equal @instance.env.logger, @instance.logger
|
||||
end
|
||||
|
||||
should "not be erroneous initially" do
|
||||
assert !@instance.error?
|
||||
end
|
||||
|
||||
should "mark as erroneous" do
|
||||
@instance.error!(:key)
|
||||
assert_equal [:key, {}], @instance.error
|
||||
end
|
||||
|
||||
should "properly report erroneous" do
|
||||
@instance.error!(:key)
|
||||
assert @instance.error?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ErrorHaltTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::ErrorHalt
|
||||
@app, @env = mock_action_data
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
should "continue the chain if no error" do
|
||||
assert !@env.error?
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt the chain if an error occured" do
|
||||
@env.error!(:foo)
|
||||
@app.expects(:call).never
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ExceptionCatcherTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Class.new
|
||||
@klass.send(:include, Vagrant::Action::ExceptionCatcher)
|
||||
@env = Vagrant::Action::Environment.new(mock_environment)
|
||||
|
||||
@instance = @klass.new
|
||||
end
|
||||
|
||||
should "run block and return result if no exception" do
|
||||
result = @instance.catch_action_exception(@env) do
|
||||
true
|
||||
end
|
||||
|
||||
assert result
|
||||
assert !@env.error?
|
||||
end
|
||||
|
||||
should "run block and return false with error environment on exception" do
|
||||
result = @instance.catch_action_exception(@env) do
|
||||
raise Vagrant::Action::ActionException.new(:foo, :foo => :bar)
|
||||
end
|
||||
|
||||
assert !result
|
||||
assert @env.error?
|
||||
assert_equal :foo, @env.error.first
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class BootVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Boot
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:ssh).returns(mock("ssh"))
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "run the proper methods on success" do
|
||||
boot_seq = sequence("boot_seq")
|
||||
@instance.expects(:boot).in_sequence(boot_seq)
|
||||
@instance.expects(:wait_for_boot).returns(true).in_sequence(boot_seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(boot_seq)
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "error and halt chain if boot failed" do
|
||||
boot_seq = sequence("boot_seq")
|
||||
@instance.expects(:boot).in_sequence(boot_seq)
|
||||
@instance.expects(:wait_for_boot).returns(false).in_sequence(boot_seq)
|
||||
@app.expects(:call).never
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
|
||||
context "booting" do
|
||||
should "start the VM in specified mode" do
|
||||
mode = mock("boot_mode")
|
||||
@env.env.config.vm.boot_mode = mode
|
||||
@internal_vm.expects(:start).with(mode).once
|
||||
@instance.boot
|
||||
end
|
||||
end
|
||||
|
||||
context "waiting for boot" do
|
||||
should "repeatedly ping the SSH port and return false with no response" do
|
||||
seq = sequence('pings')
|
||||
@vm.ssh.expects(:up?).times(@env.env.config.ssh.max_tries.to_i - 1).returns(false).in_sequence(seq)
|
||||
@vm.ssh.expects(:up?).once.returns(true).in_sequence(seq)
|
||||
assert @instance.wait_for_boot(0)
|
||||
end
|
||||
|
||||
should "ping the max number of times then just return" do
|
||||
@vm.ssh.expects(:up?).times(@env.env.config.ssh.max_tries.to_i).returns(false)
|
||||
assert !@instance.wait_for_boot(0)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class CheckGuestAdditionsVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::CheckGuestAdditions
|
||||
end
|
||||
|
||||
# TODO: This isn't tested.
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class CustomizeVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Customize
|
||||
@app, @env = mock_action_data
|
||||
@instance = @klass.new(@app, @env)
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
should "not run anything if no customize blocks exist" do
|
||||
@internal_vm.expects(:save).never
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "run the VM customization procs then save the VM" do
|
||||
@env.env.config.vm.customize { |vm| }
|
||||
@env.env.config.vm.expects(:run_procs!).with(@internal_vm)
|
||||
@internal_vm.expects(:save).once
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class DestroyVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Destroy
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "destroying the VM" do
|
||||
should "destroy VM and attached images" do
|
||||
@internal_vm.expects(:destroy).with(:destroy_medium => :delete).once
|
||||
@env["vm"].expects(:vm=).with(nil).once
|
||||
@env.env.expects(:update_dotfile).once
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,46 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class DestroyUnusedNetworkInterfacesVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::DestroyUnusedNetworkInterfaces
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
@network_adapters = []
|
||||
@internal_vm.stubs(:network_adapters).returns(@network_adapters)
|
||||
end
|
||||
|
||||
def stub_interface(length=5)
|
||||
interface = mock("interface")
|
||||
adapter = mock("adapter")
|
||||
adapter.stubs(:host_interface_object).returns(interface)
|
||||
interface.stubs(:attached_vms).returns(Array.new(length))
|
||||
|
||||
@network_adapters << adapter
|
||||
interface
|
||||
end
|
||||
|
||||
should "destroy only the unused network interfaces" do
|
||||
stub_interface(5)
|
||||
stub_interface(7)
|
||||
results = [stub_interface(1), stub_interface(1)]
|
||||
|
||||
results.each do |result|
|
||||
result.expects(:destroy).once
|
||||
end
|
||||
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,88 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class ExportVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Export
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
@internal_vm.stubs(:powered_off?).returns(true)
|
||||
end
|
||||
|
||||
should "call the proper methods then continue chain" do
|
||||
seq = sequence("seq")
|
||||
@instance.expects(:setup_temp_dir).in_sequence(seq)
|
||||
@instance.expects(:export).in_sequence(seq)
|
||||
@app.expects(:call).with(@env).in_sequence(seq)
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt the chain if not powered off" do
|
||||
@internal_vm.stubs(:powered_off?).returns(false)
|
||||
@instance.expects(:setup_temp_dir).never
|
||||
@instance.expects(:export).never
|
||||
@app.expects(:call).with(@env).never
|
||||
|
||||
@instance.call(@env)
|
||||
assert @env.error?
|
||||
assert_equal :vm_power_off_to_package, @env.error.first
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up the temporary directory" do
|
||||
setup do
|
||||
@time_now = Time.now.to_i.to_s
|
||||
Time.stubs(:now).returns(@time_now)
|
||||
|
||||
@tmp_path = "foo"
|
||||
@env.env.stubs(:tmp_path).returns(@tmp_path)
|
||||
|
||||
@temp_dir = File.join(@env.env.tmp_path, @time_now)
|
||||
FileUtils.stubs(:mkpath)
|
||||
end
|
||||
|
||||
should "create the temporary directory using the current time" do
|
||||
FileUtils.expects(:mkpath).with(@temp_dir).once
|
||||
@instance.setup_temp_dir
|
||||
end
|
||||
|
||||
should "set to the environment" do
|
||||
@instance.setup_temp_dir
|
||||
assert_equal @temp_dir, @env["export.temp_dir"]
|
||||
end
|
||||
end
|
||||
|
||||
context "exporting" do
|
||||
setup do
|
||||
@ovf_path = mock("ovf_path")
|
||||
@instance.stubs(:ovf_path).returns(@ovf_path)
|
||||
end
|
||||
|
||||
should "call export on the runner with the ovf path" do
|
||||
@internal_vm.expects(:export).with(@ovf_path).once
|
||||
@instance.export
|
||||
end
|
||||
end
|
||||
|
||||
context "path to OVF file" do
|
||||
setup do
|
||||
@temp_dir = "foo"
|
||||
@env["export.temp_dir"] = @temp_dir
|
||||
end
|
||||
|
||||
should "be the temporary directory joined with the OVF filename" do
|
||||
assert_equal File.join(@temp_dir, @env.env.config.vm.box_ovf), @instance.ovf_path
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,270 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class ForwardPortsVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::ForwardPorts
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:name).returns("foo")
|
||||
@env["vm"] = @vm
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
should "call proper methods" do
|
||||
@klass.any_instance.expects(:external_collision_check)
|
||||
@klass.new(@app, @env)
|
||||
end
|
||||
end
|
||||
|
||||
context "checking for colliding external ports" do
|
||||
setup do
|
||||
@env.env.config.vm.forwarded_ports.clear
|
||||
@env.env.config.vm.forward_port("ssh", 22, 2222)
|
||||
|
||||
@used_ports = []
|
||||
@klass.any_instance.stubs(:used_ports).returns(@used_ports)
|
||||
@klass.any_instance.stubs(:handle_collision)
|
||||
end
|
||||
|
||||
should "not raise any errors if no forwarded ports collide" do
|
||||
@used_ports << "80"
|
||||
@klass.new(@app, @env)
|
||||
assert !@env.error?
|
||||
end
|
||||
|
||||
should "handle collision if it happens" do
|
||||
@used_ports << "2222"
|
||||
@klass.any_instance.expects(:handle_collision).with("ssh", anything, anything).once
|
||||
@klass.new(@app, @env)
|
||||
assert !@env.error?
|
||||
end
|
||||
end
|
||||
|
||||
context "with instance" do
|
||||
setup do
|
||||
@klass.any_instance.stubs(:external_collision_check)
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "handling collisions" do
|
||||
setup do
|
||||
@name = :foo
|
||||
@options = {
|
||||
:hostport => 0,
|
||||
:auto => true
|
||||
}
|
||||
@used_ports = [1,2,3]
|
||||
|
||||
@env.env.config.vm.auto_port_range = (1..5)
|
||||
end
|
||||
|
||||
should "error if auto forwarding is disabled" do
|
||||
@options[:auto] = false
|
||||
@instance.handle_collision(@name, @options, @used_ports)
|
||||
assert @env.error?
|
||||
assert_equal :vm_port_collision, @env.error.first
|
||||
end
|
||||
|
||||
should "set the host port to the first available port" do
|
||||
assert_equal 0, @options[:hostport]
|
||||
@instance.handle_collision(@name, @options, @used_ports)
|
||||
assert_equal 4, @options[:hostport]
|
||||
end
|
||||
|
||||
should "add the newly used port to the list of used ports" do
|
||||
assert !@used_ports.include?(4)
|
||||
@instance.handle_collision(@name, @options, @used_ports)
|
||||
assert @used_ports.include?(4)
|
||||
end
|
||||
|
||||
should "not use a host port which is being forwarded later" do
|
||||
@env.env.config.vm.forward_port("http", 80, 4)
|
||||
|
||||
assert_equal 0, @options[:hostport]
|
||||
@instance.handle_collision(@name, @options, @used_ports)
|
||||
assert_equal 5, @options[:hostport]
|
||||
end
|
||||
|
||||
should "raise an exception if there are no auto ports available" do
|
||||
@env.env.config.vm.auto_port_range = (1..3)
|
||||
@instance.handle_collision(@name, @options, @used_ports)
|
||||
assert @env.error?
|
||||
assert_equal :vm_port_auto_empty, @env.error.first
|
||||
end
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "clear all previous ports and forward new ports" do
|
||||
exec_seq = sequence("exec_seq")
|
||||
@instance.expects(:clear).once.in_sequence(exec_seq)
|
||||
@instance.expects(:forward_ports).once.in_sequence(exec_seq)
|
||||
@app.expects(:call).once.with(@env).in_sequence(exec_seq)
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
|
||||
context "forwarding ports" do
|
||||
setup do
|
||||
@internal_vm = mock("internal_vm")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
should "create a port forwarding for the VM" do
|
||||
forwarded_ports = mock("forwarded_ports")
|
||||
network_adapter = mock("network_adapter")
|
||||
|
||||
@internal_vm.stubs(:network_adapters).returns([network_adapter])
|
||||
network_adapter.expects(:attachment_type).returns(:nat)
|
||||
|
||||
@instance.expects(:forward_port).once
|
||||
@internal_vm.expects(:save).once
|
||||
@vm.expects(:reload!).once
|
||||
@instance.forward_ports
|
||||
end
|
||||
|
||||
should "not port forward for non NAT interfaces" do
|
||||
forwarded_ports = mock("forwarded_ports")
|
||||
network_adapter = mock("network_adapter")
|
||||
|
||||
@internal_vm.expects(:network_adapters).returns([network_adapter])
|
||||
network_adapter.expects(:attachment_type).returns(:host_only)
|
||||
@internal_vm.expects(:save).once
|
||||
@vm.expects(:reload!).once
|
||||
@instance.forward_ports
|
||||
end
|
||||
end
|
||||
|
||||
context "clearing forwarded ports" do
|
||||
setup do
|
||||
@instance.stubs(:used_ports).returns([:a])
|
||||
@instance.stubs(:clear_ports)
|
||||
end
|
||||
|
||||
should "call destroy on all forwarded ports" do
|
||||
@instance.expects(:clear_ports).once
|
||||
@vm.expects(:reload!)
|
||||
@instance.clear
|
||||
end
|
||||
|
||||
should "do nothing if there are no forwarded ports" do
|
||||
@instance.stubs(:used_ports).returns([])
|
||||
@vm.expects(:reload!).never
|
||||
@instance.clear
|
||||
end
|
||||
end
|
||||
|
||||
context "getting list of used ports" do
|
||||
setup do
|
||||
@vms = []
|
||||
VirtualBox::VM.stubs(:all).returns(@vms)
|
||||
VirtualBox.stubs(:version).returns("3.1.0")
|
||||
@vm.stubs(:uuid).returns(:bar)
|
||||
end
|
||||
|
||||
def mock_vm(options={})
|
||||
options = {
|
||||
:running? => true,
|
||||
:uuid => :foo
|
||||
}.merge(options)
|
||||
|
||||
vm = mock("vm")
|
||||
options.each do |k,v|
|
||||
vm.stubs(k).returns(v)
|
||||
end
|
||||
|
||||
vm
|
||||
end
|
||||
|
||||
def mock_fp(hostport)
|
||||
fp = mock("fp")
|
||||
fp.stubs(:hostport).returns(hostport.to_s)
|
||||
fp
|
||||
end
|
||||
|
||||
should "ignore VMs which aren't running" do
|
||||
@vms << mock_vm(:running? => false)
|
||||
@vms[0].expects(:forwarded_ports).never
|
||||
@instance.used_ports
|
||||
end
|
||||
|
||||
should "ignore VMs of the same uuid" do
|
||||
@vms << mock_vm(:uuid => @vm.uuid)
|
||||
@vms[0].expects(:forwarded_ports).never
|
||||
@instance.used_ports
|
||||
end
|
||||
|
||||
should "return the forwarded ports for VB 3.2.x" do
|
||||
VirtualBox.stubs(:version).returns("3.2.4")
|
||||
fps = [mock_fp(2222), mock_fp(80)]
|
||||
na = mock("na")
|
||||
ne = mock("ne")
|
||||
na.stubs(:nat_driver).returns(ne)
|
||||
ne.stubs(:forwarded_ports).returns(fps)
|
||||
@vms << mock_vm(:network_adapters => [na])
|
||||
assert_equal %W[2222 80], @instance.used_ports
|
||||
end
|
||||
end
|
||||
|
||||
context "clearing ports" do
|
||||
def mock_fp
|
||||
fp = mock("fp")
|
||||
fp.expects(:destroy).once
|
||||
fp
|
||||
end
|
||||
|
||||
setup do
|
||||
VirtualBox.stubs(:version).returns("3.2.8")
|
||||
@adapters = []
|
||||
@internal_vm = mock("internal_vm")
|
||||
@internal_vm.stubs(:network_adapters).returns(@adapters)
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
def mock_adapter
|
||||
na = mock("adapter")
|
||||
engine = mock("engine")
|
||||
engine.stubs(:forwarded_ports).returns([mock_fp])
|
||||
na.stubs(:nat_driver).returns(engine)
|
||||
na
|
||||
end
|
||||
|
||||
should "destroy each forwarded port" do
|
||||
@adapters << mock_adapter
|
||||
@adapters << mock_adapter
|
||||
@instance.clear_ports
|
||||
end
|
||||
end
|
||||
|
||||
context "forwarding ports implementation" do
|
||||
setup do
|
||||
VirtualBox.stubs(:version).returns("3.2.8")
|
||||
|
||||
@internal_vm = mock("internal_vm")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
should "forward ports" do
|
||||
name, opts = @env.env.config.vm.forwarded_ports.first
|
||||
|
||||
adapters = []
|
||||
adapter = mock("adapter")
|
||||
engine = mock("engine")
|
||||
fps = mock("forwarded ports")
|
||||
adapter.stubs(:nat_driver).returns(engine)
|
||||
engine.stubs(:forwarded_ports).returns(fps)
|
||||
fps.expects(:<<).with do |port|
|
||||
assert_equal name, port.name
|
||||
assert_equal opts[:hostport], port.hostport
|
||||
assert_equal opts[:guestport], port.guestport
|
||||
true
|
||||
end
|
||||
|
||||
adapters[opts[:adapter]] = adapter
|
||||
@internal_vm.stubs(:network_adapters).returns(adapters)
|
||||
|
||||
@instance.forward_port(name, opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class HaltVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Halt
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:name).returns("foo")
|
||||
@vm.stubs(:ssh).returns(mock("ssh"))
|
||||
@vm.stubs(:system).returns(mock("system"))
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
@internal_vm.stubs(:running?).returns(true)
|
||||
|
||||
@vm.system.stubs(:halt)
|
||||
@internal_vm.stubs(:stop)
|
||||
@internal_vm.stubs(:state).returns(:powered_off)
|
||||
end
|
||||
|
||||
should "do nothing if VM not running" do
|
||||
@internal_vm.stubs(:running?).returns(false)
|
||||
@vm.system.expects(:halt).never
|
||||
@internal_vm.expects(:stop).never
|
||||
@app.expects(:call).once
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt with the system and NOT force VM to stop if powered off" do
|
||||
@internal_vm.expects(:state).with(true).returns(:powered_off)
|
||||
@vm.system.expects(:halt).once
|
||||
@internal_vm.expects(:stop).never
|
||||
@app.expects(:call).once
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt with the system and force VM to stop if NOT powered off" do
|
||||
@internal_vm.expects(:state).with(true).returns(:running)
|
||||
@vm.system.expects(:halt).once
|
||||
@internal_vm.expects(:stop).once
|
||||
@app.expects(:call).once
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "not call halt on the system if forcing" do
|
||||
@env["force"] = true
|
||||
@vm.system.expects(:halt).never
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class ImportVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Import
|
||||
@app, @env = mock_action_data
|
||||
@instance = @klass.new(@app, @env)
|
||||
|
||||
ovf_file = "foo"
|
||||
@box = mock("box")
|
||||
@box.stubs(:ovf_file).returns(ovf_file)
|
||||
@env.env.stubs(:box).returns(@box)
|
||||
|
||||
@env.env.vm = Vagrant::VM.new
|
||||
|
||||
VirtualBox::VM.stubs(:import)
|
||||
end
|
||||
|
||||
should "call import on VirtualBox with proper base" do
|
||||
VirtualBox::VM.expects(:import).once.with(@env.env.box.ovf_file).returns("foo")
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "call next in chain on success and set VM" do
|
||||
vm = mock("vm")
|
||||
VirtualBox::VM.stubs(:import).returns(vm)
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
|
||||
assert_equal vm, @env["vm"].vm
|
||||
end
|
||||
|
||||
should "mark environment erroneous and not continue chain on failure" do
|
||||
@app.expects(:call).never
|
||||
@instance.call(@env)
|
||||
|
||||
assert @env.error?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class MatchMACAddressVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::MatchMACAddress
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
should "match the mac addresses" do
|
||||
nic = mock("nic")
|
||||
nic.expects(:mac_address=).once
|
||||
|
||||
update_seq = sequence("update_seq")
|
||||
@internal_vm.expects(:network_adapters).returns([nic]).once.in_sequence(update_seq)
|
||||
@internal_vm.expects(:save).once.in_sequence(update_seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(update_seq)
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,246 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class NetworkVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Network
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:name).returns("foo")
|
||||
@vm.stubs(:ssh).returns(mock("ssh"))
|
||||
@vm.stubs(:system).returns(mock("system"))
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
should "verify no bridge collisions for each network enabled" do
|
||||
@env.env.config.vm.network("foo")
|
||||
@klass.any_instance.expects(:verify_no_bridge_collision).once.with() do |options|
|
||||
assert_equal "foo", options[:ip]
|
||||
true
|
||||
end
|
||||
|
||||
@klass.new(@app, @env)
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
@klass.any_instance.stubs(:verify_no_bridge_collision)
|
||||
@instance = @klass.new(@app, @env)
|
||||
|
||||
@interfaces = []
|
||||
VirtualBox::Global.global.host.stubs(:network_interfaces).returns(@interfaces)
|
||||
end
|
||||
|
||||
def mock_interface(options=nil)
|
||||
options = {
|
||||
:interface_type => :host_only,
|
||||
:name => "foo"
|
||||
}.merge(options || {})
|
||||
|
||||
interface = mock("interface")
|
||||
options.each do |k,v|
|
||||
interface.stubs(k).returns(v)
|
||||
end
|
||||
|
||||
@interfaces << interface
|
||||
interface
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
@env.env.config.vm.network("foo")
|
||||
@instance.stubs(:enable_network?).returns(false)
|
||||
end
|
||||
|
||||
should "do nothing if network should not be enabled" do
|
||||
@instance.expects(:assign_network).never
|
||||
@app.expects(:call).with(@env).once
|
||||
@vm.system.expects(:prepare_host_only_network).never
|
||||
@vm.system.expects(:enable_host_only_network).never
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "assign and enable the network if networking enabled" do
|
||||
@instance.stubs(:enable_network?).returns(true)
|
||||
|
||||
run_seq = sequence("run")
|
||||
@instance.expects(:assign_network).once.in_sequence(run_seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(run_seq)
|
||||
@vm.system.expects(:prepare_host_only_network).once.in_sequence(run_seq)
|
||||
@vm.system.expects(:enable_host_only_network).once.in_sequence(run_seq)
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
|
||||
context "checking if network is enabled" do
|
||||
should "return true if the network options are set" do
|
||||
@env.env.config.vm.network("foo")
|
||||
assert @instance.enable_network?
|
||||
end
|
||||
|
||||
should "return false if the network was not set" do
|
||||
assert !@instance.enable_network?
|
||||
end
|
||||
end
|
||||
|
||||
context "assigning the network" do
|
||||
setup do
|
||||
@network_name = "foo"
|
||||
@instance.stubs(:network_name).returns(@network_name)
|
||||
|
||||
@network_adapters = []
|
||||
@internal_vm.stubs(:network_adapters).returns(@network_adapters)
|
||||
|
||||
@options = {
|
||||
:ip => "foo",
|
||||
:adapter => 7
|
||||
}
|
||||
|
||||
@env.env.config.vm.network(@options[:ip], @options)
|
||||
end
|
||||
|
||||
should "setup the specified network adapter" do
|
||||
adapter = mock("adapter")
|
||||
@network_adapters[@options[:adapter]] = adapter
|
||||
|
||||
adapter.expects(:enabled=).with(true).once
|
||||
adapter.expects(:attachment_type=).with(:host_only).once
|
||||
adapter.expects(:host_interface=).with(@network_name).once
|
||||
adapter.expects(:save).once
|
||||
|
||||
@instance.assign_network
|
||||
end
|
||||
end
|
||||
|
||||
context "network name" do
|
||||
setup do
|
||||
@instance.stubs(:matching_network?).returns(false)
|
||||
|
||||
@options = { :ip => :foo, :netmask => :bar, :name => nil }
|
||||
end
|
||||
|
||||
should "return the network which matches" do
|
||||
result = mock("result")
|
||||
interface = mock_interface(:name => result)
|
||||
|
||||
@instance.expects(:matching_network?).with(interface, @options).returns(true)
|
||||
assert_equal result, @instance.network_name(@options)
|
||||
end
|
||||
|
||||
should "ignore non-host only interfaces" do
|
||||
@options[:name] = "foo"
|
||||
mock_interface(:name => @options[:name],
|
||||
:interface_type => :bridged)
|
||||
|
||||
@instance.network_name(@options)
|
||||
assert @env.error?
|
||||
end
|
||||
|
||||
should "return the network which matches the name if given" do
|
||||
@options[:name] = "foo"
|
||||
|
||||
interface = mock_interface(:name => @options[:name])
|
||||
assert_equal @options[:name], @instance.network_name(@options)
|
||||
end
|
||||
|
||||
should "error and exit if the given network name is not found" do
|
||||
@options[:name] = "foo"
|
||||
|
||||
@interfaces.expects(:create).never
|
||||
@instance.network_name(@options)
|
||||
assert @env.error?
|
||||
assert_equal :network_not_found, @env.error.first
|
||||
end
|
||||
|
||||
should "create a network for the IP and netmask" do
|
||||
result = mock("result")
|
||||
network_ip = :foo
|
||||
|
||||
interface = mock_interface(:name => result)
|
||||
interface.expects(:enable_static).with(network_ip, @options[:netmask])
|
||||
@interfaces.expects(:create).returns(interface)
|
||||
@instance.expects(:network_ip).with(@options[:ip], @options[:netmask]).once.returns(network_ip)
|
||||
|
||||
assert_equal result, @instance.network_name(@options)
|
||||
end
|
||||
end
|
||||
|
||||
context "checking for a matching network" do
|
||||
setup do
|
||||
@interface = mock("interface")
|
||||
@interface.stubs(:network_mask).returns("foo")
|
||||
@interface.stubs(:ip_address).returns("192.168.0.1")
|
||||
|
||||
@options = {
|
||||
:netmask => "foo",
|
||||
:ip => "baz"
|
||||
}
|
||||
end
|
||||
|
||||
should "return false if the netmasks don't match" do
|
||||
@options[:netmask] = "bar"
|
||||
assert @interface.network_mask != @options[:netmask] # sanity
|
||||
assert !@instance.matching_network?(@interface, @options)
|
||||
end
|
||||
|
||||
should "return true if the netmasks yield the same IP" do
|
||||
tests = [["255.255.255.0", "192.168.0.1", "192.168.0.45"],
|
||||
["255.255.0.0", "192.168.45.1", "192.168.28.7"]]
|
||||
|
||||
tests.each do |netmask, interface_ip, guest_ip|
|
||||
@options[:netmask] = netmask
|
||||
@options[:ip] = guest_ip
|
||||
@interface.stubs(:network_mask).returns(netmask)
|
||||
@interface.stubs(:ip_address).returns(interface_ip)
|
||||
|
||||
assert @instance.matching_network?(@interface, @options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "applying the netmask" do
|
||||
should "return the proper result" do
|
||||
tests = {
|
||||
["192.168.0.1","255.255.255.0"] => [192,168,0,0],
|
||||
["192.168.45.10","255.255.255.0"] => [192,168,45,0]
|
||||
}
|
||||
|
||||
tests.each do |k,v|
|
||||
assert_equal v, @instance.apply_netmask(*k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "splitting an IP" do
|
||||
should "return the proper result" do
|
||||
tests = {
|
||||
"192.168.0.1" => [192,168,0,1]
|
||||
}
|
||||
|
||||
tests.each do |k,v|
|
||||
assert_equal v, @instance.split_ip(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "network IP" do
|
||||
should "return the proper result" do
|
||||
tests = {
|
||||
["192.168.0.45", "255.255.255.0"] => "192.168.0.1"
|
||||
}
|
||||
|
||||
tests.each do |args, result|
|
||||
assert_equal result, @instance.network_ip(*args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,227 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class PackageVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Package
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
setup do
|
||||
@tar_path = "foo"
|
||||
File.stubs(:exist?).returns(false)
|
||||
@klass.any_instance.stubs(:tar_path).returns(@tar_path)
|
||||
end
|
||||
|
||||
should "initialize fine" do
|
||||
@klass.new(@app, @env)
|
||||
assert !@env.error?
|
||||
end
|
||||
|
||||
should "error the environment if the output file exists" do
|
||||
File.stubs(:exist?).with(@tar_path).returns(true)
|
||||
@klass.new(@app, @env)
|
||||
assert @env.error?
|
||||
assert_equal :box_file_exists, @env.error.first
|
||||
end
|
||||
|
||||
should "set the output path to 'package' by default" do
|
||||
@klass.new(@app, @env)
|
||||
assert_equal "package", @env["package.output"]
|
||||
end
|
||||
|
||||
should "not set the output path if it is already set" do
|
||||
@env["package.output"] = "foo"
|
||||
@klass.new(@app, @env)
|
||||
assert_equal "foo", @env["package.output"]
|
||||
end
|
||||
|
||||
should "set the included files to empty by default" do
|
||||
@klass.new(@app, @env)
|
||||
assert_equal [], @env["package.include"]
|
||||
end
|
||||
|
||||
should "not set the output path if it is already set" do
|
||||
@env["package.include"] = "foo"
|
||||
@klass.new(@app, @env)
|
||||
assert_equal "foo", @env["package.include"]
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
File.stubs(:exist?).returns(false)
|
||||
@instance = @klass.new(@app, @env)
|
||||
|
||||
@env["export.temp_dir"] = "foo"
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "call the proper methods then continue chain" do
|
||||
seq = sequence("seq")
|
||||
@instance.expects(:verify_included_files).in_sequence(seq).returns(true)
|
||||
@instance.expects(:compress).in_sequence(seq)
|
||||
@app.expects(:call).with(@env).in_sequence(seq)
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt the chain if verify failed" do
|
||||
@instance.expects(:verify_included_files).returns(false)
|
||||
@instance.expects(:compress).never
|
||||
@app.expects(:call).never
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "halt the chain if export didn't run" do
|
||||
@env["export.temp_dir"] = nil
|
||||
@app.expects(:call).never
|
||||
@instance.call(@env)
|
||||
|
||||
assert @env.error?
|
||||
assert_equal :package_requires_export, @env.error.first
|
||||
end
|
||||
end
|
||||
|
||||
context "verifying included files" do
|
||||
setup do
|
||||
@env["package.include"] = ["foo"]
|
||||
File.stubs(:exist?).returns(true)
|
||||
end
|
||||
|
||||
should "error if included file is not found" do
|
||||
File.expects(:exist?).with("foo").returns(false)
|
||||
assert !@instance.verify_included_files
|
||||
assert @env.error?
|
||||
assert_equal :package_include_file_doesnt_exist, @env.error.first
|
||||
end
|
||||
|
||||
should "return true if all exist" do
|
||||
assert @instance.verify_included_files
|
||||
assert !@env.error?
|
||||
end
|
||||
end
|
||||
|
||||
context "copying include files" do
|
||||
setup do
|
||||
@env["package.include"] = []
|
||||
end
|
||||
|
||||
should "do nothing if no include files are specified" do
|
||||
assert @env["package.include"].empty?
|
||||
FileUtils.expects(:mkdir_p).never
|
||||
FileUtils.expects(:cp).never
|
||||
@instance.copy_include_files
|
||||
end
|
||||
|
||||
should "create the include directory and copy files to it" do
|
||||
include_dir = File.join(@env["export.temp_dir"], "include")
|
||||
copy_seq = sequence("copy_seq")
|
||||
FileUtils.expects(:mkdir_p).with(include_dir).once.in_sequence(copy_seq)
|
||||
|
||||
5.times do |i|
|
||||
file = mock("f#{i}")
|
||||
@env["package.include"] << file
|
||||
FileUtils.expects(:cp).with(file, include_dir).in_sequence(copy_seq)
|
||||
end
|
||||
|
||||
@instance.copy_include_files
|
||||
end
|
||||
end
|
||||
|
||||
context "creating vagrantfile" do
|
||||
setup do
|
||||
@network_adapter = mock("nic")
|
||||
@network_adapter.stubs(:mac_address).returns("mac_address")
|
||||
@internal_vm.stubs(:network_adapters).returns([@network_adapter])
|
||||
end
|
||||
|
||||
should "write the rendered vagrantfile to temp_path Vagrantfile" do
|
||||
f = mock("file")
|
||||
rendered = mock("rendered")
|
||||
File.expects(:open).with(File.join(@env["export.temp_dir"], "Vagrantfile"), "w").yields(f)
|
||||
Vagrant::Util::TemplateRenderer.expects(:render).returns(rendered).with("package_Vagrantfile", {
|
||||
:base_mac => @internal_vm.network_adapters.first.mac_address
|
||||
})
|
||||
f.expects(:write).with(rendered)
|
||||
|
||||
@instance.create_vagrantfile
|
||||
end
|
||||
end
|
||||
|
||||
context "compression" do
|
||||
setup do
|
||||
@env["package.include"] = []
|
||||
|
||||
@tar_path = "foo"
|
||||
@instance.stubs(:tar_path).returns(@tar_path)
|
||||
|
||||
@pwd = "bar"
|
||||
FileUtils.stubs(:pwd).returns(@pwd)
|
||||
FileUtils.stubs(:cd)
|
||||
|
||||
@file = mock("file")
|
||||
File.stubs(:open).yields(@file)
|
||||
|
||||
@output = mock("output")
|
||||
@tar = Archive::Tar::Minitar
|
||||
Archive::Tar::Minitar::Output.stubs(:open).yields(@output)
|
||||
@tar.stubs(:pack_file)
|
||||
|
||||
@instance.stubs(:copy_include_files)
|
||||
@instance.stubs(:create_vagrantfile)
|
||||
end
|
||||
|
||||
should "open the tar file with the tar path properly" do
|
||||
File.expects(:open).with(@tar_path, Vagrant::Util::Platform.tar_file_options).once
|
||||
@instance.compress
|
||||
end
|
||||
|
||||
should "open tar file" do
|
||||
Archive::Tar::Minitar::Output.expects(:open).with(@file).once
|
||||
@instance.compress
|
||||
end
|
||||
|
||||
#----------------------------------------------------------------
|
||||
# Methods below this comment test the block yielded by Minitar open
|
||||
#----------------------------------------------------------------
|
||||
should "cd to the directory and append the directory" do
|
||||
@files = []
|
||||
compress_seq = sequence("compress_seq")
|
||||
|
||||
FileUtils.expects(:pwd).once.returns(@pwd).in_sequence(compress_seq)
|
||||
@instance.expects(:copy_include_files).once.in_sequence(compress_seq)
|
||||
@instance.expects(:create_vagrantfile).once.in_sequence(compress_seq)
|
||||
FileUtils.expects(:cd).with(@env["export.temp_dir"]).in_sequence(compress_seq)
|
||||
Dir.expects(:glob).returns(@files).in_sequence(compress_seq)
|
||||
|
||||
5.times do |i|
|
||||
file = mock("file#{i}")
|
||||
@tar.expects(:pack_file).with(file, @output).once.in_sequence(compress_seq)
|
||||
@files << file
|
||||
end
|
||||
|
||||
FileUtils.expects(:cd).with(@pwd).in_sequence(compress_seq)
|
||||
@instance.compress
|
||||
end
|
||||
|
||||
should "pop back to the current directory even if an exception is raised" do
|
||||
cd_seq = sequence("cd_seq")
|
||||
FileUtils.expects(:cd).with(@env["export.temp_dir"]).raises(Exception).in_sequence(cd_seq)
|
||||
FileUtils.expects(:cd).with(@pwd).in_sequence(cd_seq)
|
||||
|
||||
assert_raises(Exception) {
|
||||
@instance.compress
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class PersistVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Persist
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:uuid).returns("123")
|
||||
@env["vm"] = @vm
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
setup do
|
||||
File.stubs(:file?).returns(true)
|
||||
File.stubs(:exist?).returns(true)
|
||||
@dotfile_path = "foo"
|
||||
@env.env.stubs(:dotfile_path).returns(@dotfile_path)
|
||||
end
|
||||
|
||||
should "error environment if dotfile exists but is not a file" do
|
||||
File.expects(:file?).with(@env.env.dotfile_path).returns(false)
|
||||
@klass.new(@app, @env)
|
||||
assert @env.error?
|
||||
assert_equal :dotfile_error, @env.error.first
|
||||
end
|
||||
|
||||
should "initialize properly if dotfiles doesn't exist" do
|
||||
File.expects(:exist?).with(@env.env.dotfile_path).returns(false)
|
||||
@klass.new(@app, @env)
|
||||
assert !@env.error?
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
File.stubs(:file?).returns(true)
|
||||
File.stubs(:exist?).returns(true)
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
should "persist the dotfile then continue chain" do
|
||||
update_seq = sequence("update_seq")
|
||||
@env.env.expects(:update_dotfile).in_sequence(update_seq)
|
||||
@app.expects(:call).with(@env).in_sequence(update_seq)
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,134 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class ProvisionVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Provision
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:name).returns("foo")
|
||||
@vm.stubs(:ssh).returns(mock("ssh"))
|
||||
@vm.stubs(:system).returns(mock("system"))
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
setup do
|
||||
@klass.any_instance.stubs(:load_provisioner)
|
||||
end
|
||||
|
||||
should "load provisioner if provisioning enabled" do
|
||||
@env["config"].vm.provisioner = :chef_solo
|
||||
@klass.any_instance.expects(:load_provisioner).once
|
||||
@klass.new(@app, @env)
|
||||
end
|
||||
|
||||
should "not load provisioner if disabled" do
|
||||
@env["config"].vm.provisioner = nil
|
||||
@klass.any_instance.expects(:load_provisioner).never
|
||||
@klass.new(@app, @env)
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
# Set provisioner to nil so the provisioner isn't loaded on init
|
||||
@env["config"].vm.provisioner = nil
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "loading a provisioner" do
|
||||
context "with a Class provisioner" do
|
||||
setup do
|
||||
@prov = mock("instance")
|
||||
@prov.stubs(:is_a?).with(Vagrant::Provisioners::Base).returns(true)
|
||||
@prov.stubs(:prepare)
|
||||
@klass = mock("klass")
|
||||
@klass.stubs(:is_a?).with(Class).returns(true)
|
||||
@klass.stubs(:new).with(@env).returns(@prov)
|
||||
|
||||
@env["config"].vm.provisioner = @klass
|
||||
end
|
||||
|
||||
should "set the provisioner to an instantiation of the class" do
|
||||
@klass.expects(:new).with(@env).once.returns(@prov)
|
||||
assert_equal @prov, @instance.load_provisioner
|
||||
end
|
||||
|
||||
should "call prepare on the instance" do
|
||||
@prov.expects(:prepare).once
|
||||
@instance.load_provisioner
|
||||
end
|
||||
|
||||
should "error environment if the class is not a subclass of the provisioner base" do
|
||||
@prov.expects(:is_a?).with(Vagrant::Provisioners::Base).returns(false)
|
||||
@instance.load_provisioner
|
||||
assert @env.error?
|
||||
assert_equal :provisioner_invalid_class, @env.error.first
|
||||
end
|
||||
end
|
||||
|
||||
context "with a Symbol provisioner" do
|
||||
def provisioner_expectation(symbol, provisioner)
|
||||
@env[:config].vm.provisioner = symbol
|
||||
|
||||
instance = mock("instance")
|
||||
instance.expects(:prepare).once
|
||||
provisioner.expects(:new).with(@env).returns(instance)
|
||||
assert_equal instance, @instance.load_provisioner
|
||||
end
|
||||
|
||||
should "raise an ActionException if its an unknown symbol" do
|
||||
@env["config"].vm.provisioner = :this_will_never_exist
|
||||
@instance.load_provisioner
|
||||
assert @env.error?
|
||||
assert_equal :provisioner_unknown_type, @env.error.first
|
||||
end
|
||||
|
||||
should "set :chef_solo to the ChefSolo provisioner" do
|
||||
provisioner_expectation(:chef_solo, Vagrant::Provisioners::ChefSolo)
|
||||
end
|
||||
|
||||
should "set :chef_server to the ChefServer provisioner" do
|
||||
provisioner_expectation(:chef_server, Vagrant::Provisioners::ChefServer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
setup do
|
||||
Vagrant::Provisioners::ChefSolo.any_instance.stubs(:prepare)
|
||||
@env["config"].vm.provisioner = :chef_solo
|
||||
@prov = @instance.load_provisioner
|
||||
end
|
||||
|
||||
should "provision and continue chain" do
|
||||
seq = sequence("seq")
|
||||
@app.expects(:call).with(@env).in_sequence(seq)
|
||||
@prov.expects(:provision!).in_sequence(seq)
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "continue chain and not provision if not enabled" do
|
||||
@env["config"].vm.provisioner = nil
|
||||
@prov.expects(:provision!).never
|
||||
@app.expects(:call).with(@env).once
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "not provision if erroneous environment" do
|
||||
@env.error!(:foo)
|
||||
|
||||
@prov.expects(:provision!).never
|
||||
@app.expects(:call).with(@env).once
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class ResumeVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Resume
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "run the proper methods when saved" do
|
||||
@internal_vm.expects(:saved?).returns(true)
|
||||
|
||||
seq = sequence("seq")
|
||||
@env.env.actions.expects(:run).with(:start).once.in_sequence(seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(seq)
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "do nothing if VM is not saved" do
|
||||
@internal_vm.expects(:saved?).returns(false)
|
||||
|
||||
@vm.expects(:start).never
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +1,20 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class SharedFoldersActionTest < Test::Unit::TestCase
|
||||
class ShareFoldersVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::VM::SharedFolders)
|
||||
@runner.stubs(:system).returns(linux_system(@vm))
|
||||
@klass = Vagrant::Action::VM::ShareFolders
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@vm.stubs(:name).returns("foo")
|
||||
@vm.stubs(:ssh).returns(mock("ssh"))
|
||||
@vm.stubs(:system).returns(mock("system"))
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
def stub_shared_folders
|
||||
|
@ -20,25 +31,33 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
@runner.stubs(:env).returns(env)
|
||||
@env.stubs(:env).returns(env)
|
||||
env.config.vm.shared_folders
|
||||
end
|
||||
|
||||
context "before boot" do
|
||||
should "clear folders and create metadata, in order" do
|
||||
context "calling" do
|
||||
should "run the methods in the proper order" do
|
||||
before_seq = sequence("before")
|
||||
@action.expects(:clear_shared_folders).once.in_sequence(before_seq)
|
||||
@action.expects(:create_metadata).once.in_sequence(before_seq)
|
||||
@action.before_boot
|
||||
end
|
||||
end
|
||||
@instance.expects(:clear_shared_folders).once.in_sequence(before_seq)
|
||||
@instance.expects(:create_metadata).once.in_sequence(before_seq)
|
||||
@app.expects(:call).with(@env).in_sequence(before_seq)
|
||||
@instance.expects(:mount_shared_folders).once.in_sequence(before_seq)
|
||||
@instance.expects(:setup_unison).once.in_sequence(before_seq)
|
||||
|
||||
context "after boot" do
|
||||
should "mount folders then setup unison" do
|
||||
seq = sequence("after")
|
||||
@action.expects(:mount_shared_folders).once.in_sequence(seq)
|
||||
@action.expects(:setup_unison).once.in_sequence(seq)
|
||||
@action.after_boot
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "run only the metadata actions if erroneous environment" do
|
||||
@env.error!(:foo)
|
||||
|
||||
before_seq = sequence("before")
|
||||
@instance.expects(:clear_shared_folders).once.in_sequence(before_seq)
|
||||
@instance.expects(:create_metadata).once.in_sequence(before_seq)
|
||||
@app.expects(:call).with(@env).in_sequence(before_seq)
|
||||
@instance.expects(:mount_shared_folders).never
|
||||
@instance.expects(:setup_unison).never
|
||||
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,7 +78,7 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
result = @action.shared_folders
|
||||
result = @instance.shared_folders
|
||||
assert_equal data.length, result.length
|
||||
data.each do |name, value|
|
||||
guest, host = value
|
||||
|
@ -77,8 +96,8 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
config.vm.share_folder(name, guest, host, :sync => true)
|
||||
end
|
||||
|
||||
result = @action.shared_folders
|
||||
assert_equal "#{guest}#{@runner.env.config.unison.folder_suffix}", result[name][:guestpath]
|
||||
result = @instance.shared_folders
|
||||
assert_equal "#{guest}#{@env.env.config.unison.folder_suffix}", result[name][:guestpath]
|
||||
assert_equal guest, result[name][:original][:guestpath]
|
||||
end
|
||||
|
||||
|
@ -89,8 +108,8 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
|
||||
folder = @folders["foo"].dup
|
||||
|
||||
@action.shared_folders
|
||||
assert_equal folder, @runner.env.config.vm.shared_folders["foo"]
|
||||
@instance.shared_folders
|
||||
assert_equal folder, @env.env.config.vm.shared_folders["foo"]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -103,7 +122,7 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "only return the folders marked for syncing" do
|
||||
result = @action.unison_folders
|
||||
result = @instance.unison_folders
|
||||
assert_equal 1, result.length
|
||||
assert result.has_key?("foo")
|
||||
assert !result.has_key?("bar")
|
||||
|
@ -114,7 +133,7 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
setup do
|
||||
@shared_folder = mock("shared_folder")
|
||||
@shared_folders = [@shared_folder]
|
||||
@vm.stubs(:shared_folders).returns(@shared_folders)
|
||||
@internal_vm.stubs(:shared_folders).returns(@shared_folders)
|
||||
end
|
||||
|
||||
should "call destroy on each shared folder then reload" do
|
||||
|
@ -123,14 +142,14 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
sf.expects(:destroy).once.in_sequence(destroy_seq)
|
||||
end
|
||||
|
||||
@runner.expects(:reload!).once.in_sequence(destroy_seq)
|
||||
@action.clear_shared_folders
|
||||
@vm.expects(:reload!).once.in_sequence(destroy_seq)
|
||||
@instance.clear_shared_folders
|
||||
end
|
||||
|
||||
should "do nothing if no shared folders existed" do
|
||||
@shared_folders.clear
|
||||
@runner.expects(:reload!).never
|
||||
@action.clear_shared_folders
|
||||
@vm.expects(:reload!).never
|
||||
@instance.clear_shared_folders
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -143,16 +162,16 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
shared_folders = []
|
||||
data = %W[foo bar]
|
||||
shared_folders.expects(:<<).times(data.length).with() do |sf|
|
||||
hostpath = File.expand_path("#{sf.name}host", @runner.env.root_path)
|
||||
hostpath = File.expand_path("#{sf.name}host", @env.env.root_path)
|
||||
assert data.include?(sf.name)
|
||||
assert_equal hostpath, sf.host_path
|
||||
true
|
||||
end
|
||||
|
||||
@vm.stubs(:shared_folders).returns(shared_folders)
|
||||
@vm.expects(:save).once
|
||||
@internal_vm.stubs(:shared_folders).returns(shared_folders)
|
||||
@internal_vm.expects(:save).once
|
||||
|
||||
@action.create_metadata
|
||||
@instance.create_metadata
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -160,24 +179,24 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
setup do
|
||||
@folders = stub_shared_folders
|
||||
@ssh = mock("ssh")
|
||||
@runner.ssh.stubs(:execute).yields(@ssh)
|
||||
@runner.system.stubs(:mount_shared_folder)
|
||||
@vm.ssh.stubs(:execute).yields(@ssh)
|
||||
@vm.system.stubs(:mount_shared_folder)
|
||||
end
|
||||
|
||||
should "mount all shared folders to the VM" do
|
||||
mount_seq = sequence("mount_seq")
|
||||
@folders.each do |name, data|
|
||||
@runner.system.expects(:mount_shared_folder).with(@ssh, name, data[:guestpath]).in_sequence(mount_seq)
|
||||
@vm.system.expects(:mount_shared_folder).with(@ssh, name, data[:guestpath]).in_sequence(mount_seq)
|
||||
end
|
||||
|
||||
@action.mount_shared_folders
|
||||
@instance.mount_shared_folders
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up unison" do
|
||||
setup do
|
||||
@ssh = mock("ssh")
|
||||
@runner.ssh.stubs(:execute).yields(@ssh)
|
||||
@vm.ssh.stubs(:execute).yields(@ssh)
|
||||
|
||||
@folders = stub_shared_folders do |config|
|
||||
config.vm.share_folder("foo", "bar", "baz", :sync => true)
|
||||
|
@ -186,17 +205,17 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
should "do nothing if unison folders is empty" do
|
||||
@action.stubs(:unison_folders).returns({})
|
||||
@runner.ssh.expects(:execute).never
|
||||
@action.setup_unison
|
||||
@instance.stubs(:unison_folders).returns({})
|
||||
@vm.ssh.expects(:execute).never
|
||||
@instance.setup_unison
|
||||
end
|
||||
|
||||
should "prepare unison then create for each folder" do
|
||||
seq = sequence("unison seq")
|
||||
@runner.system.expects(:prepare_unison).with(@ssh).once.in_sequence(seq)
|
||||
@action.unison_folders.each do |name, data|
|
||||
@vm.system.expects(:prepare_unison).with(@ssh).once.in_sequence(seq)
|
||||
@instance.unison_folders.each do |name, data|
|
||||
if data[:sync]
|
||||
@runner.system.expects(:create_unison).with do |ssh, opts|
|
||||
@vm.system.expects(:create_unison).with do |ssh, opts|
|
||||
assert_equal @ssh, ssh
|
||||
assert_equal data, opts
|
||||
|
||||
|
@ -205,7 +224,7 @@ class SharedFoldersActionTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
@action.setup_unison
|
||||
@instance.setup_unison
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class SuspendVMActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action::VM::Suspend
|
||||
@app, @env = mock_action_data
|
||||
|
||||
@vm = mock("vm")
|
||||
@env["vm"] = @vm
|
||||
|
||||
@internal_vm = mock("internal")
|
||||
@vm.stubs(:vm).returns(@internal_vm)
|
||||
|
||||
@instance = @klass.new(@app, @env)
|
||||
end
|
||||
|
||||
context "calling" do
|
||||
should "run the proper methods when running" do
|
||||
@internal_vm.expects(:running?).returns(true)
|
||||
|
||||
seq = sequence("seq")
|
||||
@internal_vm.expects(:save_state).once.in_sequence(seq)
|
||||
@app.expects(:call).with(@env).once.in_sequence(seq)
|
||||
@instance.call(@env)
|
||||
end
|
||||
|
||||
should "do nothing if VM is not running" do
|
||||
@internal_vm.expects(:running?).returns(false)
|
||||
|
||||
@internal_vm.expects(:save_state).never
|
||||
@app.expects(:call).with(@env).once
|
||||
@instance.call(@env)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,96 @@
|
|||
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
||||
|
||||
class ActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@klass = Vagrant::Action
|
||||
end
|
||||
|
||||
context "with a class" do
|
||||
teardown do
|
||||
@klass.actions.clear
|
||||
end
|
||||
|
||||
should "be able to register an action" do
|
||||
@klass.register(:foo, :bar)
|
||||
assert @klass.actions.has_key?(:foo)
|
||||
assert_equal :bar, @klass.actions[:foo]
|
||||
end
|
||||
|
||||
should "be able to retrieve an action using []" do
|
||||
@klass.register(:foo, :bar)
|
||||
assert_equal :bar, @klass[:foo]
|
||||
end
|
||||
end
|
||||
|
||||
context "with an instance" do
|
||||
setup do
|
||||
@instance = @klass.new(mock_environment)
|
||||
end
|
||||
|
||||
teardown do
|
||||
@klass.actions.clear
|
||||
end
|
||||
|
||||
should "run the callable item with the proper context" do
|
||||
callable = mock("callable")
|
||||
callable.expects(:call).with() do |env|
|
||||
assert env.kind_of?(Vagrant::Action::Environment)
|
||||
assert_equal @instance.env, env.env
|
||||
true
|
||||
end
|
||||
|
||||
@instance.run(callable)
|
||||
end
|
||||
|
||||
should "run the callable with the passed in options if given" do
|
||||
options = {
|
||||
:key => :value,
|
||||
:another => %W[1 2 3]
|
||||
}
|
||||
|
||||
callable = mock("callable")
|
||||
callable.expects(:call).with() do |env|
|
||||
assert env.kind_of?(Vagrant::Action::Environment)
|
||||
assert_equal @instance.env, env.env
|
||||
|
||||
options.each do |k,v|
|
||||
assert_equal v, env[k]
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
@instance.run(callable, options)
|
||||
end
|
||||
|
||||
should "run the registered callable if a symbol is given" do
|
||||
callable = mock("callable")
|
||||
callable.expects(:call).once
|
||||
|
||||
@klass.register(:call, callable)
|
||||
@instance.run(:call)
|
||||
end
|
||||
|
||||
should "run the given class if a class is given" do
|
||||
callable = Class.new do
|
||||
def initialize(app, env); end
|
||||
end
|
||||
|
||||
callable.any_instance.expects(:call).with() do |env|
|
||||
assert_equal :foo, env[:bar]
|
||||
true
|
||||
end
|
||||
|
||||
@instance.run(callable, :bar => :foo)
|
||||
end
|
||||
|
||||
should "error and exit if erroneous environment results" do
|
||||
callable = lambda do |env|
|
||||
env.error!(:key, :foo => :bar)
|
||||
end
|
||||
|
||||
@instance.expects(:error_and_exit).with(:key, :foo => :bar)
|
||||
@instance.run(callable)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,32 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class BaseActionTest < Test::Unit::TestCase
|
||||
should "include the util class so subclasses have access to it" do
|
||||
assert Vagrant::Actions::Base.include?(Vagrant::Util)
|
||||
end
|
||||
|
||||
context "base instance" do
|
||||
setup do
|
||||
@mock_vm = mock("vm")
|
||||
@base = Vagrant::Actions::Base.new(@mock_vm)
|
||||
end
|
||||
|
||||
should "allow read-only access to the runner" do
|
||||
assert_equal @mock_vm, @base.runner
|
||||
end
|
||||
|
||||
should "implement prepare which does nothing" do
|
||||
assert_nothing_raised do
|
||||
assert @base.respond_to?(:prepare)
|
||||
@base.prepare
|
||||
end
|
||||
end
|
||||
|
||||
should "implement the execute! method which does nothing" do
|
||||
assert_nothing_raised do
|
||||
assert @base.respond_to?(:execute!)
|
||||
@base.execute!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class AddBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::Box::Add)
|
||||
end
|
||||
|
||||
context "prepare" do
|
||||
setup do
|
||||
@default_order = [Vagrant::Actions::Box::Download, Vagrant::Actions::Box::Unpackage, Vagrant::Actions::Box::Verify]
|
||||
@runner.stubs(:directory).returns("foo")
|
||||
File.stubs(:exists?).returns(false)
|
||||
end
|
||||
|
||||
def setup_action_expectations
|
||||
default_seq = sequence("default_seq")
|
||||
@default_order.each do |action|
|
||||
@runner.expects(:add_action).with(action).once.in_sequence(default_seq)
|
||||
end
|
||||
end
|
||||
|
||||
should "setup the proper sequence of actions" do
|
||||
setup_action_expectations
|
||||
@action.prepare
|
||||
end
|
||||
|
||||
should "result in an action exception if the box already exists" do
|
||||
File.expects(:exists?).once.returns(true)
|
||||
@runner.expects(:name).once.returns('foo')
|
||||
@runner.expects(:add_action).never
|
||||
assert_raise Vagrant::Actions::ActionException do
|
||||
@action.prepare
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,17 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class DestroyBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@name = "foo"
|
||||
@dir = "foo"
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::Box::Destroy)
|
||||
@runner.stubs(:directory).returns(@dir)
|
||||
end
|
||||
|
||||
context "executing" do
|
||||
should "rm_rf the directory" do
|
||||
FileUtils.expects(:rm_rf).with(@dir).once
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,137 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class DownloadBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@uri = "foo.com"
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::Box::Download)
|
||||
@runner.stubs(:uri).returns(@uri)
|
||||
@runner.stubs(:temp_path=)
|
||||
|
||||
@runner.env.stubs(:tmp_path).returns("foo")
|
||||
end
|
||||
|
||||
context "preparing" do
|
||||
setup do
|
||||
@downloader = mock("downloader")
|
||||
Vagrant::Downloaders::File.any_instance.stubs(:prepare)
|
||||
Vagrant::Downloaders::HTTP.any_instance.stubs(:prepare)
|
||||
end
|
||||
|
||||
should "raise an exception if no URI type is matched" do\
|
||||
Vagrant::Downloaders::File.expects(:match?).returns(false)
|
||||
Vagrant::Downloaders::HTTP.expects(:match?).returns(false)
|
||||
assert_raises(Vagrant::Actions::ActionException) {
|
||||
@action.prepare
|
||||
}
|
||||
end
|
||||
|
||||
should "call #prepare on the downloader" do
|
||||
@downloader.expects(:prepare).with(@runner.uri).once
|
||||
Vagrant::Downloaders::File.expects(:new).returns(@downloader)
|
||||
expect_file
|
||||
@action.prepare
|
||||
end
|
||||
|
||||
should "set the downloader to file if the uri provided is a file" do
|
||||
expect_file
|
||||
@action.prepare
|
||||
assert @action.downloader.is_a?(Vagrant::Downloaders::File)
|
||||
end
|
||||
|
||||
should "set the downloader to HTTP if the uri provided is a valid url" do
|
||||
expect_http
|
||||
@action.prepare
|
||||
assert @action.downloader.is_a?(Vagrant::Downloaders::HTTP)
|
||||
end
|
||||
|
||||
def expect_file
|
||||
Vagrant::Downloaders::File.expects(:match?).returns(true)
|
||||
Vagrant::Downloaders::HTTP.expects(:match?).returns(false)
|
||||
end
|
||||
|
||||
def expect_http
|
||||
Vagrant::Downloaders::File.expects(:match?).returns(false)
|
||||
Vagrant::Downloaders::HTTP.expects(:match?).returns(true)
|
||||
end
|
||||
end
|
||||
|
||||
context "executing" do
|
||||
setup do
|
||||
@path = "foo"
|
||||
|
||||
@tempfile = mock("tempfile")
|
||||
@tempfile.stubs(:path).returns(@path)
|
||||
|
||||
@action.stubs(:with_tempfile).yields(@tempfile)
|
||||
@action.stubs(:download_to)
|
||||
end
|
||||
|
||||
should "make a tempfile and copy the URI contents to it" do
|
||||
@action.expects(:with_tempfile).yields(@tempfile)
|
||||
@action.expects(:download_to).with(@tempfile)
|
||||
@action.execute!
|
||||
end
|
||||
|
||||
should "save the tempfile path" do
|
||||
@runner.expects(:temp_path=).with(@path).once
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
|
||||
context "rescue" do
|
||||
should "call cleanup method" do
|
||||
@action.expects(:cleanup).once
|
||||
@action.rescue(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "tempfile" do
|
||||
should "create a tempfile in the vagrant tmp directory" do
|
||||
File.expects(:open).with { |name, bitmask|
|
||||
name =~ /#{Vagrant::Actions::Box::Download::BASENAME}/ && name =~ /#{@runner.env.tmp_path}/
|
||||
}.once
|
||||
@action.with_tempfile
|
||||
end
|
||||
|
||||
should "yield the tempfile object" do
|
||||
@tempfile = mock("tempfile")
|
||||
File.expects(:open).yields(@tempfile)
|
||||
|
||||
@action.with_tempfile do |otherfile|
|
||||
assert @tempfile.equal?(otherfile)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "cleaning up" do
|
||||
setup do
|
||||
@temp_path = "foo"
|
||||
@runner.stubs(:temp_path).returns(@temp_path)
|
||||
File.stubs(:exist?).returns(true)
|
||||
end
|
||||
|
||||
should "delete the temporary file if it exists" do
|
||||
File.expects(:unlink).with(@temp_path).once
|
||||
@action.cleanup
|
||||
end
|
||||
|
||||
should "not delete anything if it doesn't exist" do
|
||||
File.stubs(:exist?).returns(false)
|
||||
File.expects(:unlink).never
|
||||
@action.cleanup
|
||||
end
|
||||
end
|
||||
|
||||
context "downloading" do
|
||||
setup do
|
||||
@downloader = mock("downloader")
|
||||
@action.stubs(:downloader).returns(@downloader)
|
||||
end
|
||||
|
||||
should "call download! on the download with the URI and tempfile" do
|
||||
tempfile = "foo"
|
||||
@downloader.expects(:download!).with(@runner.uri, tempfile)
|
||||
@action.download_to(tempfile)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,99 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class UnpackageBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::Box::Unpackage)
|
||||
@runner.stubs(:name).returns("foo")
|
||||
@runner.stubs(:temp_path).returns("bar")
|
||||
|
||||
@runner.env.stubs(:boxes_path).returns("bar")
|
||||
end
|
||||
|
||||
context "executing" do
|
||||
setup do
|
||||
@runner.stubs(:invoke_around_callback).yields
|
||||
end
|
||||
|
||||
should "execute the proper actions in the proper order" do
|
||||
exec_seq = sequence("exec_seq")
|
||||
@action.expects(:setup_box_dir).in_sequence(exec_seq)
|
||||
@action.expects(:decompress).in_sequence(exec_seq)
|
||||
@action.execute!
|
||||
end
|
||||
|
||||
should "execute it in a around block" do
|
||||
@runner.expects(:invoke_around_callback).with(:unpackage).once
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
|
||||
context "rescuing" do
|
||||
setup do
|
||||
File.stubs(:directory?).returns(false)
|
||||
FileUtils.stubs(:rm_rf)
|
||||
|
||||
@box_dir = mock("foo")
|
||||
@action.stubs(:box_dir).returns(@box_dir)
|
||||
end
|
||||
|
||||
should "do nothing if a directory doesn't exist" do
|
||||
FileUtils.expects(:rm_rf).never
|
||||
@action.rescue(nil)
|
||||
end
|
||||
|
||||
should "remove the box directory if it exists" do
|
||||
File.expects(:directory?).returns(true)
|
||||
FileUtils.expects(:rm_rf).with(@box_dir).once
|
||||
@action.rescue(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "box directory" do
|
||||
should "return the runner directory" do
|
||||
result = mock("object")
|
||||
@runner.expects(:directory).once.returns(result)
|
||||
assert result.equal?(@action.box_dir)
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up the box directory" do
|
||||
setup do
|
||||
File.stubs(:directory?).returns(false)
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
|
||||
@box_dir = "foo"
|
||||
@action.stubs(:box_dir).returns(@box_dir)
|
||||
end
|
||||
|
||||
should "error and exit if the directory exists" do
|
||||
File.expects(:directory?).returns(true)
|
||||
@action.expects(:error_and_exit).with(:box_already_exists, :box_name => @runner.name).once
|
||||
@action.setup_box_dir
|
||||
end
|
||||
|
||||
should "create the directory" do
|
||||
FileUtils.expects(:mkdir_p).with(@box_dir).once
|
||||
@action.setup_box_dir
|
||||
end
|
||||
end
|
||||
|
||||
context "decompressing" do
|
||||
setup do
|
||||
@box_dir = "foo"
|
||||
|
||||
@action.stubs(:box_dir).returns(@box_dir)
|
||||
Dir.stubs(:chdir).yields
|
||||
Archive::Tar::Minitar.stubs(:unpack)
|
||||
end
|
||||
|
||||
should "change to the box directory" do
|
||||
Dir.expects(:chdir).with(@box_dir)
|
||||
@action.decompress
|
||||
end
|
||||
|
||||
should "open the tar file within the new directory, and extract it all" do
|
||||
Archive::Tar::Minitar.expects(:unpack).with(@runner.temp_path, @box_dir).once
|
||||
@action.decompress
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,44 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class VerifyBoxActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::Box::Verify)
|
||||
@runner.stubs(:name).returns("foo")
|
||||
@runner.stubs(:temp_path).returns("bar")
|
||||
end
|
||||
|
||||
context "executing" do
|
||||
should "execute the proper actions in the proper order" do
|
||||
exec_seq = sequence("exec_seq")
|
||||
@action.expects(:reload_configuration).in_sequence(exec_seq)
|
||||
@action.expects(:verify_appliance).in_sequence(exec_seq)
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
|
||||
context "reloading configuration" do
|
||||
should "set the new box, load box, then load config" do
|
||||
reload_seq = sequence("reload_seq")
|
||||
@runner.env.config.vm.expects(:box=).with(@runner.name).in_sequence(reload_seq)
|
||||
@runner.env.expects(:load_box!).in_sequence(reload_seq)
|
||||
@runner.env.expects(:load_config!).in_sequence(reload_seq)
|
||||
@action.reload_configuration
|
||||
end
|
||||
end
|
||||
|
||||
context "verifying appliance" do
|
||||
setup do
|
||||
@runner.stubs(:ovf_file).returns("foo")
|
||||
end
|
||||
|
||||
should "create new appliance and return true if succeeds" do
|
||||
VirtualBox::Appliance.expects(:new).with(@runner.ovf_file)
|
||||
assert_nothing_raised { @action.verify_appliance }
|
||||
end
|
||||
|
||||
should "return false if an exception is raised" do
|
||||
VirtualBox::Appliance.expects(:new).with(@runner.ovf_file).raises(VirtualBox::Exceptions::FileErrorException)
|
||||
assert_raises(Vagrant::Actions::ActionException) { @action.verify_appliance }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,113 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class CollectionTest < Test::Unit::TestCase
|
||||
class MockAction; end
|
||||
class MockActionOther; end
|
||||
|
||||
context "checking uniqueness" do
|
||||
setup do
|
||||
@actions = Vagrant::Actions::Collection.new([1])
|
||||
end
|
||||
|
||||
should "return true if there are duplicate classes in the collection" do
|
||||
@actions << 1
|
||||
assert @actions.duplicates?
|
||||
end
|
||||
|
||||
should "return false it all the classes are unique" do
|
||||
@actions << 1.0 << "foo"
|
||||
assert !@actions.duplicates?
|
||||
end
|
||||
|
||||
should "raise an exception when there are duplicates" do
|
||||
@actions << 1
|
||||
assert_raise Vagrant::Actions::DuplicateActionException do
|
||||
@actions.duplicates!
|
||||
end
|
||||
end
|
||||
|
||||
should "not raise an exception when there are no duplicates" do
|
||||
@actions << 1.0 << "foo"
|
||||
assert_nothing_raised do
|
||||
@actions.duplicates!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "verifying dependencies" do
|
||||
setup do
|
||||
@mock_action = mock('action')
|
||||
@mock_action.stubs(:class).returns(MockAction)
|
||||
|
||||
@mock_action2 = mock('action2')
|
||||
@mock_action2.stubs(:class).returns(MockActionOther)
|
||||
# see test_helper
|
||||
stub_default_action_dependecies(@mock_action)
|
||||
stub_default_action_dependecies(@mock_action2)
|
||||
end
|
||||
|
||||
context "that come before an action" do
|
||||
setup do
|
||||
@mock_action.stubs(:follows).returns([MockActionOther])
|
||||
end
|
||||
should "raise an exception if they are not met" do
|
||||
assert_raise Vagrant::Actions::DependencyNotSatisfiedException do
|
||||
collection.new([@mock_action]).dependencies!
|
||||
end
|
||||
end
|
||||
|
||||
should "not raise an exception if they are met" do
|
||||
assert_nothing_raised do
|
||||
collection.new([@mock_action2, @mock_action]).dependencies!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "that follow an an action" do
|
||||
setup do
|
||||
@mock_action.stubs(:precedes).returns([MockActionOther])
|
||||
end
|
||||
|
||||
should "raise an exception if they are not met" do
|
||||
assert_raise Vagrant::Actions::DependencyNotSatisfiedException do
|
||||
collection.new([@mock_action]).dependencies!
|
||||
end
|
||||
end
|
||||
|
||||
should "not raise an exception if they are met" do
|
||||
assert_nothing_raised do
|
||||
collection.new([@mock_action, @mock_action2]).dependencies!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "that are before and after an action" do
|
||||
setup do
|
||||
@mock_action.stubs(:precedes).returns([MockActionOther])
|
||||
@mock_action.stubs(:follows).returns([MockActionOther])
|
||||
end
|
||||
|
||||
should "raise an exception if they are met" do
|
||||
assert_raise Vagrant::Actions::DependencyNotSatisfiedException do
|
||||
collection.new([@mock_action2, @mock_action]).dependencies!
|
||||
end
|
||||
end
|
||||
|
||||
should "not raise and exception if they are met" do
|
||||
assert_nothing_raised do
|
||||
collection.new([@mock_action2, @mock_action, @mock_action2]).dependencies!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "klasses" do
|
||||
should "return a list of the collection element's classes" do
|
||||
@action = mock('action')
|
||||
assert_equal collection.new([@action]).klasses, [@action.class]
|
||||
assert_equal collection.new([@action, 1.0, "foo"]).klasses, [@action.class, Float, String]
|
||||
end
|
||||
end
|
||||
|
||||
def collection; Vagrant::Actions::Collection end
|
||||
end
|
|
@ -1,268 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ActionRunnerTest < Test::Unit::TestCase
|
||||
class MockAction; end
|
||||
class MockActionOther; end
|
||||
|
||||
def mock_fake_action(action_klass = nil, runner = nil)
|
||||
action = action_klass ? action_klass.new(runner) : mock("action")
|
||||
action.stubs(:prepare)
|
||||
action.stubs(:execute!)
|
||||
action.stubs(:cleanup)
|
||||
stub_default_action_dependecies(action)
|
||||
action
|
||||
end
|
||||
|
||||
context "callbacks" do
|
||||
setup do
|
||||
@runner = Vagrant::Actions::Runner.new
|
||||
end
|
||||
|
||||
context "around callbacks" do
|
||||
should "invoke before/after_name for around callbacks" do
|
||||
block_obj = mock("block_obj")
|
||||
around_seq = sequence("around_seq")
|
||||
@runner.expects(:invoke_callback).with(:before_foo).once.in_sequence(around_seq)
|
||||
block_obj.expects(:foo).once.in_sequence(around_seq)
|
||||
@runner.expects(:invoke_callback).with(:after_foo).once.in_sequence(around_seq)
|
||||
|
||||
@runner.invoke_around_callback(:foo) do
|
||||
block_obj.foo
|
||||
end
|
||||
end
|
||||
|
||||
should "forward arguments to invoke_callback" do
|
||||
@runner.expects(:invoke_callback).with(:before_foo, "foo").once
|
||||
@runner.expects(:invoke_callback).with(:after_foo, "foo").once
|
||||
@runner.invoke_around_callback(:foo, "foo") do; end
|
||||
end
|
||||
end
|
||||
|
||||
should "not invoke callback on actions which don't respond to it" do
|
||||
action = mock("action")
|
||||
action.stubs(:respond_to?).with(:foo).returns(false)
|
||||
action.expects(:foo).never
|
||||
|
||||
assert_nothing_raised do
|
||||
@runner.actions << action
|
||||
@runner.invoke_callback(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
should "invoke callback on actions which do respond to the method" do
|
||||
action = mock("action")
|
||||
action.expects(:foo).once
|
||||
|
||||
@runner.actions << action
|
||||
@runner.invoke_callback(:foo)
|
||||
end
|
||||
|
||||
should "collect all the results and return them as an array" do
|
||||
result = []
|
||||
3.times do |i|
|
||||
action = mock("action#{i}")
|
||||
action.expects(:foo).returns("foo#{i}").once
|
||||
|
||||
@runner.actions << action
|
||||
result << "foo#{i}"
|
||||
end
|
||||
|
||||
assert_equal result, @runner.invoke_callback(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
context "finding actions" do
|
||||
setup do
|
||||
@runner = Vagrant::Actions::Runner.new
|
||||
end
|
||||
|
||||
should "return nil if the action could not be found" do
|
||||
assert_nil @runner.find_action(Vagrant::Actions::VM::Export)
|
||||
end
|
||||
|
||||
should "return the first instance of the action found" do
|
||||
@runner.add_action(Vagrant::Actions::VM::Export)
|
||||
@runner.add_action(Vagrant::Actions::VM::Export)
|
||||
|
||||
assert @runner.actions[0].equal?(@runner.find_action(Vagrant::Actions::VM::Export))
|
||||
end
|
||||
end
|
||||
|
||||
context "adding actions" do
|
||||
setup do
|
||||
@runner = Vagrant::Actions::Runner.new
|
||||
end
|
||||
|
||||
should "initialize the action when added" do
|
||||
action_klass = mock("action_class")
|
||||
action_inst = mock("action_inst")
|
||||
action_klass.expects(:new).once.returns(action_inst)
|
||||
@runner.add_action(action_klass)
|
||||
assert_equal 1, @runner.actions.length
|
||||
end
|
||||
|
||||
should "initialize the action with given arguments when added" do
|
||||
action_klass = mock("action_class")
|
||||
action_klass.expects(:new).with(@runner, "foo", "bar").once
|
||||
@runner.add_action(action_klass, "foo", "bar")
|
||||
end
|
||||
end
|
||||
|
||||
context "class method execute" do
|
||||
should "run actions on class method execute!" do
|
||||
vm = mock("vm")
|
||||
execute_seq = sequence("execute_seq")
|
||||
Vagrant::Actions::Runner.expects(:new).returns(vm).in_sequence(execute_seq)
|
||||
vm.expects(:add_action).with("foo").in_sequence(execute_seq)
|
||||
vm.expects(:execute!).once.in_sequence(execute_seq)
|
||||
|
||||
Vagrant::Actions::Runner.execute!("foo")
|
||||
end
|
||||
|
||||
should "forward arguments to add_action on class method execute!" do
|
||||
vm = mock("vm")
|
||||
execute_seq = sequence("execute_seq")
|
||||
Vagrant::Actions::Runner.expects(:new).returns(vm).in_sequence(execute_seq)
|
||||
vm.expects(:add_action).with("foo", "bar", "baz").in_sequence(execute_seq)
|
||||
vm.expects(:execute!).once.in_sequence(execute_seq)
|
||||
|
||||
Vagrant::Actions::Runner.execute!("foo", "bar", "baz")
|
||||
end
|
||||
end
|
||||
|
||||
context "instance method execute" do
|
||||
setup do
|
||||
@runner = Vagrant::Actions::Runner.new
|
||||
@runner.stubs(:action_klasses).returns([Vagrant::Actions::Base])
|
||||
end
|
||||
|
||||
should "clear the actions and run a single action if given to execute!" do
|
||||
action = mock("action")
|
||||
run_action = mock("action_run")
|
||||
stub_default_action_dependecies(run_action)
|
||||
run_class = mock("run_class")
|
||||
run_class.expects(:new).once.returns(run_action)
|
||||
@runner.actions << action
|
||||
|
||||
[:prepare, :execute!, :cleanup].each do |method|
|
||||
action.expects(method).never
|
||||
run_action.expects(method).once
|
||||
end
|
||||
|
||||
@runner.execute!(run_class)
|
||||
end
|
||||
|
||||
should "clear actions after running execute!" do
|
||||
@runner.actions << mock_fake_action
|
||||
assert !@runner.actions.empty? # sanity
|
||||
@runner.execute!
|
||||
assert @runner.actions.empty?
|
||||
end
|
||||
|
||||
should "run #prepare on all actions, then #execute!" do
|
||||
action_seq = sequence("action_seq")
|
||||
actions = []
|
||||
[MockAction, MockActionOther].each_with_index do |klass, i|
|
||||
action = mock("action#{i}")
|
||||
action.expects(:class).returns(klass)
|
||||
stub_default_action_dependecies(action)
|
||||
@runner.actions << action
|
||||
actions << action
|
||||
end
|
||||
|
||||
[:prepare, :execute!, :cleanup].each do |method|
|
||||
actions.each do |action|
|
||||
action.expects(method).once.in_sequence(action_seq)
|
||||
end
|
||||
end
|
||||
|
||||
@runner.execute!
|
||||
end
|
||||
|
||||
context "exceptions" do
|
||||
setup do
|
||||
@actions = [MockAction, MockActionOther].map do |klass|
|
||||
action = mock_fake_action
|
||||
action.expects(:class).returns(klass)
|
||||
action.stubs(:rescue)
|
||||
@runner.actions << action
|
||||
action
|
||||
end
|
||||
|
||||
@exception = Exception.new
|
||||
end
|
||||
|
||||
should "call #rescue on each action if an exception is raised during execute!" do
|
||||
@actions.each do |a|
|
||||
a.expects(:rescue).with(@exception).once
|
||||
end
|
||||
|
||||
@actions[0].stubs(:execute!).raises(@exception)
|
||||
|
||||
@runner.expects(:error_and_exit).never
|
||||
assert_raises(Exception) { @runner.execute! }
|
||||
end
|
||||
|
||||
should "call #rescue on each action if an exception is raised during prepare" do
|
||||
@actions.each do |a|
|
||||
a.expects(:rescue).with(@exception).once
|
||||
end
|
||||
|
||||
@actions[0].stubs(:prepare).raises(@exception)
|
||||
|
||||
@runner.expects(:error_and_exit).never
|
||||
assert_raises(Exception) { @runner.execute! }
|
||||
end
|
||||
|
||||
should "call error_and_exit if it is an ActionException" do
|
||||
@exception = Vagrant::Actions::ActionException.new("foo")
|
||||
@actions[0].stubs(:prepare).raises(@exception)
|
||||
|
||||
@runner.expects(:error_and_exit).with(@exception.key, @exception.data).once
|
||||
@runner.execute!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "actions" do
|
||||
setup do
|
||||
@runner = Vagrant::Actions::Runner.new
|
||||
end
|
||||
|
||||
should "setup actions to be an array" do
|
||||
assert_nil @runner.instance_variable_get(:@actions)
|
||||
actions = @runner.actions
|
||||
assert actions.is_a?(Array)
|
||||
assert actions.equal?(@runner.actions)
|
||||
end
|
||||
|
||||
should "be empty initially" do
|
||||
assert @runner.actions.empty?
|
||||
end
|
||||
end
|
||||
|
||||
context "duplicate action exceptions" do
|
||||
setup do
|
||||
@runner = Vagrant::Actions::Runner.new
|
||||
end
|
||||
|
||||
should "should be raised when a duplicate is added" do
|
||||
action = mock_fake_action
|
||||
2.times {@runner.actions << action }
|
||||
assert_raise Vagrant::Actions::DuplicateActionException do
|
||||
@runner.execute!
|
||||
end
|
||||
end
|
||||
|
||||
should "should not be raise when no duplicate actions are present" do
|
||||
@runner.actions << mock_fake_action(Vagrant::Actions::Base, @runner)
|
||||
@runner.actions << mock_fake_action(Vagrant::Actions::VM::Halt, @runner)
|
||||
|
||||
assert_nothing_raised { @runner.execute! }
|
||||
end
|
||||
|
||||
should "should not raise when a single action is specified" do
|
||||
assert_nothing_raised { @runner.execute!(Vagrant::Actions::Base) }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,49 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class BootActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::VM::Boot)
|
||||
@runner.stubs(:invoke_callback)
|
||||
end
|
||||
|
||||
context "execution" do
|
||||
should "invoke the 'boot' around callback" do
|
||||
boot_seq = sequence("boot_seq")
|
||||
@runner.expects(:invoke_around_callback).with(:boot).once.in_sequence(boot_seq).yields
|
||||
@action.expects(:boot).in_sequence(boot_seq)
|
||||
@action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq)
|
||||
@action.execute!
|
||||
end
|
||||
|
||||
should "error and exit if the bootup failed" do
|
||||
fail_boot_seq = sequence("fail_boot_seq")
|
||||
@action.expects(:boot).once.in_sequence(fail_boot_seq)
|
||||
@action.expects(:wait_for_boot).returns(false).in_sequence(fail_boot_seq)
|
||||
@action.expects(:error_and_exit).with(:vm_failed_to_boot).once.in_sequence(fail_boot_seq)
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
|
||||
context "booting" do
|
||||
should "start the VM in specified mode" do
|
||||
mode = mock("boot_mode")
|
||||
@runner.env.config.vm.boot_mode = mode
|
||||
@vm.expects(:start).with(mode).once
|
||||
@action.boot
|
||||
end
|
||||
end
|
||||
|
||||
context "waiting for boot" do
|
||||
should "repeatedly ping the SSH port and return false with no response" do
|
||||
seq = sequence('pings')
|
||||
@runner.ssh.expects(:up?).times(@runner.env.config.ssh.max_tries.to_i - 1).returns(false).in_sequence(seq)
|
||||
@runner.ssh.expects(:up?).once.returns(true).in_sequence(seq)
|
||||
assert @action.wait_for_boot(0)
|
||||
end
|
||||
|
||||
should "ping the max number of times then just return" do
|
||||
@runner.ssh.expects(:up?).times(@runner.env.config.ssh.max_tries.to_i).returns(false)
|
||||
assert !@action.wait_for_boot(0)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
|
||||
|
||||
class CustomizeActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@runner, @vm, @action = mock_action(Vagrant::Actions::VM::Customize)
|
||||
end
|
||||
|
||||
context "executing" do
|
||||
should "run the VM customization procs then save the VM" do
|
||||
@runner.env.config.vm.customize { |vm| }
|
||||
@runner.env.config.vm.expects(:run_procs!).with(@vm)
|
||||
@vm.expects(:save).once
|
||||
@action.execute!
|
||||
end
|
||||
|
||||
should "not run anything if no customize blocks exist" do
|
||||
@vm.expects(:save).never
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue