Merge branch 'runners' which brings in the "actions" model.
This commit is contained in:
commit
3c42db7dfe
|
@ -1,10 +1,10 @@
|
|||
libdir = File.dirname(__FILE__)
|
||||
$:.unshift(libdir)
|
||||
PROJECT_ROOT = File.join(libdir, '..')
|
||||
PROJECT_ROOT = File.join(libdir, '..') unless defined?(PROJECT_ROOT)
|
||||
|
||||
# The libs which must be loaded prior to the rest
|
||||
%w{ftools json pathname logger virtualbox net/ssh
|
||||
net/scp tarruby fileutils vagrant/util}.each do |f|
|
||||
net/scp tarruby fileutils vagrant/util vagrant/actions/base}.each do |f|
|
||||
require f
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
# Base class for any command actions. A command action handles
|
||||
# executing a step or steps on a given Vagrant::VM object. The
|
||||
# action should define any callbacks that it will call, or
|
||||
# attach itself to some callbacks on the VM object.
|
||||
class Base
|
||||
attr_reader :vm
|
||||
|
||||
# Included so subclasses don't need to include it themselves.
|
||||
include Vagrant::Util
|
||||
|
||||
# Initialization of the actions are done all at once. The guarantee
|
||||
# is that when an action is initialized, no other action has had
|
||||
# its `prepare` or `execute!` method called yet, so an action can
|
||||
# setup anything it needs to with this safety. An example of this
|
||||
# would be instance_evaling the vm instance to include a module so
|
||||
# additionally functionality could be defined on the vm which other
|
||||
# action `prepare` methods may rely on.
|
||||
def initialize(vm)
|
||||
@vm = vm
|
||||
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, so no race conditions between
|
||||
# action setups should be done here.
|
||||
def prepare
|
||||
# Examples:
|
||||
#
|
||||
# Perhaps we need an additional action to go, specifically
|
||||
# maybe only if a configuration is set
|
||||
#
|
||||
#@vm.actions << FooAction if Vagrant.config[:foo] == :bar
|
||||
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 NO EFFECT, and
|
||||
# adding callbacks has unpredictable effects.
|
||||
def execute!
|
||||
# Example code:
|
||||
#
|
||||
# @vm.invoke_callback(:before_oven, "cookies")
|
||||
# Do lots of stuff here
|
||||
# @vm.invoke_callback(:after_oven, "more", "than", "one", "option")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class ForwardPorts < Base
|
||||
def execute!
|
||||
logger.info "Forwarding ports..."
|
||||
|
||||
Vagrant.config.vm.forwarded_ports.each do |name, options|
|
||||
logger.info "Forwarding \"#{name}\": #{options[:guestport]} => #{options[:hostport]}"
|
||||
port = VirtualBox::ForwardedPort.new
|
||||
port.name = name
|
||||
port.hostport = options[:hostport]
|
||||
port.guestport = options[:guestport]
|
||||
@vm.vm.forwarded_ports << port
|
||||
end
|
||||
|
||||
@vm.vm.save(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Import < Base
|
||||
def execute!
|
||||
@vm.invoke_callback(:before_import)
|
||||
|
||||
logger.info "Importing base VM (#{Vagrant.config[:vm][:base]})..."
|
||||
@vm.vm = VirtualBox::VM.import(File.expand_path(Vagrant.config[:vm][:base]))
|
||||
|
||||
@vm.invoke_callback(:after_import)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,43 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class MoveHardDrive < Base
|
||||
def execute!
|
||||
unless @vm.powered_off?
|
||||
error_and_exit(<<-error)
|
||||
The virtual machine must be powered off to move its disk.
|
||||
error
|
||||
return
|
||||
end
|
||||
|
||||
destroy_drive_after { clone_and_attach }
|
||||
end
|
||||
|
||||
# TODO: Better way to detect main bootup drive?
|
||||
def hard_drive
|
||||
@vm.storage_controllers.first.devices.first
|
||||
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, Vagrant.config.vm.disk_image_format, true)
|
||||
|
||||
logger.info "Attaching new disk to VM ..."
|
||||
@vm.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(Vagrant.config.vm.hd_location, hard_drive.image.filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Provision < Base
|
||||
def execute!
|
||||
chown_provisioning_folder
|
||||
setup_json
|
||||
setup_solo_config
|
||||
run_chef_solo
|
||||
end
|
||||
|
||||
def chown_provisioning_folder
|
||||
logger.info "Setting permissions on provisioning folder..."
|
||||
SSH.execute do |ssh|
|
||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
||||
end
|
||||
end
|
||||
|
||||
def setup_json
|
||||
logger.info "Generating JSON and uploading..."
|
||||
|
||||
json = { :project_directory => Vagrant.config.vm.project_directory }.merge(Vagrant.config.chef.json).to_json
|
||||
|
||||
SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
|
||||
end
|
||||
|
||||
def setup_solo_config
|
||||
solo_file = <<-solo
|
||||
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||
cookbook_path "#{cookbooks_path}"
|
||||
solo
|
||||
|
||||
logger.info "Uploading chef-solo configuration script..."
|
||||
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
|
||||
end
|
||||
|
||||
def run_chef_solo
|
||||
logger.info "Running chef recipes..."
|
||||
SSH.execute do |ssh|
|
||||
ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
|
||||
# TODO: Very verbose. It would be easier to save the data and only show it during
|
||||
# an error, or when verbosity level is set high
|
||||
logger.info("#{stream}: #{data}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cookbooks_path
|
||||
File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
||||
end
|
||||
|
||||
def collect_shared_folders
|
||||
["vagrant-provisioning", File.expand_path(Vagrant.config.chef.cookbooks_path, Env.root_path), cookbooks_path]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class SharedFolders < Base
|
||||
def shared_folders
|
||||
shared_folders = @vm.invoke_callback(:collect_shared_folders)
|
||||
|
||||
# Basic filtering of shared folders. Basically only verifies that
|
||||
# the result is an array of 3 elements. In the future this should
|
||||
# also verify that the host path exists, the name is valid,
|
||||
# and that the guest path is valid.
|
||||
shared_folders.collect do |folder|
|
||||
if folder.is_a?(Array) && folder.length == 3
|
||||
folder
|
||||
else
|
||||
nil
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
||||
def before_boot
|
||||
logger.info "Creating shared folders metadata..."
|
||||
|
||||
shared_folders.each do |name, hostpath, guestpath|
|
||||
folder = VirtualBox::SharedFolder.new
|
||||
folder.name = name
|
||||
folder.hostpath = hostpath
|
||||
@vm.vm.shared_folders << folder
|
||||
end
|
||||
|
||||
@vm.vm.save(true)
|
||||
end
|
||||
|
||||
def after_boot
|
||||
logger.info "Mounting shared folders..."
|
||||
|
||||
Vagrant::SSH.execute do |ssh|
|
||||
shared_folders.each do |name, hostpath, guestpath|
|
||||
logger.info "-- #{name}: #{guestpath}"
|
||||
ssh.exec!("sudo mkdir -p #{guestpath}")
|
||||
ssh.exec!("sudo mount -t vboxsf #{name} #{guestpath}")
|
||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{guestpath}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,45 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Start < Base
|
||||
def execute!
|
||||
@vm.invoke_callback(:before_boot)
|
||||
|
||||
# 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(<<-error)
|
||||
Failed to connect to VM! Failed to boot?
|
||||
error
|
||||
end
|
||||
|
||||
@vm.invoke_callback(:after_boot)
|
||||
end
|
||||
|
||||
def boot
|
||||
logger.info "Booting VM..."
|
||||
@vm.vm.start(:headless, true)
|
||||
end
|
||||
|
||||
def wait_for_boot(sleeptime=5)
|
||||
logger.info "Waiting for VM to boot..."
|
||||
|
||||
Vagrant.config[:ssh][:max_tries].to_i.times do |i|
|
||||
logger.info "Trying to connect (attempt ##{i+1} of #{Vagrant.config[:ssh][:max_tries]})..."
|
||||
|
||||
if Vagrant::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
|
|
@ -0,0 +1,37 @@
|
|||
module Vagrant
|
||||
module Actions
|
||||
class Up < Base
|
||||
def prepare
|
||||
# Up is a "meta-action" so it really just queues up a bunch
|
||||
# of other actions in its place:
|
||||
steps = [Import, ForwardPorts, SharedFolders, Start]
|
||||
steps.insert(1, MoveHardDrive) if Vagrant.config.vm.hd_location
|
||||
|
||||
steps.each do |action_klass|
|
||||
@vm.add_action(action_klass)
|
||||
end
|
||||
end
|
||||
|
||||
def collect_shared_folders
|
||||
# The root shared folder for the project
|
||||
["vagrant-root", Env.root_path, Vagrant.config.vm.project_directory]
|
||||
end
|
||||
|
||||
def after_import
|
||||
persist
|
||||
setup_mac_address
|
||||
end
|
||||
|
||||
def persist
|
||||
logger.info "Persisting the VM UUID (#{@vm.vm.uuid})..."
|
||||
Env.persist_vm(@vm.vm)
|
||||
end
|
||||
|
||||
def setup_mac_address
|
||||
logger.info "Matching MAC addresses..."
|
||||
@vm.vm.nics.first.macaddress = Vagrant.config[:vm][:base_mac]
|
||||
@vm.vm.save(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -40,7 +40,7 @@ run `vagrant down` first.
|
|||
error
|
||||
end
|
||||
|
||||
VM.up
|
||||
VM.execute!(Actions::Up)
|
||||
end
|
||||
|
||||
# Tear down a vagrant instance. This not only shuts down the instance
|
||||
|
@ -99,7 +99,7 @@ error
|
|||
end
|
||||
|
||||
# Export and package the current vm
|
||||
#
|
||||
#
|
||||
# This command requires that an instance be powered off
|
||||
def package(name=nil)
|
||||
Env.load!
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
module Vagrant
|
||||
class Provisioning
|
||||
include Vagrant::Util
|
||||
|
||||
def initialize(vm)
|
||||
@vm = vm
|
||||
|
||||
# Share the cookbook folder. We'll use the provisioning path exclusively for
|
||||
# chef stuff.
|
||||
@vm.share_folder("vagrant-provisioning", File.expand_path(Vagrant.config.chef.cookbooks_path, Env.root_path), cookbooks_path)
|
||||
end
|
||||
|
||||
def run
|
||||
chown_provisioning_folder
|
||||
setup_json
|
||||
setup_solo_config
|
||||
run_chef_solo
|
||||
end
|
||||
|
||||
def chown_provisioning_folder
|
||||
logger.info "Setting permissions on provisioning folder..."
|
||||
SSH.execute do |ssh|
|
||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
||||
end
|
||||
end
|
||||
|
||||
def setup_json
|
||||
logger.info "Generating JSON and uploading..."
|
||||
|
||||
json = { :project_directory => Vagrant.config.vm.project_directory }.merge(Vagrant.config.chef.json).to_json
|
||||
|
||||
SSH.upload!(StringIO.new(json), File.join(Vagrant.config.chef.provisioning_path, "dna.json"))
|
||||
end
|
||||
|
||||
def setup_solo_config
|
||||
solo_file = <<-solo
|
||||
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||
cookbook_path "#{cookbooks_path}"
|
||||
solo
|
||||
|
||||
logger.info "Uploading chef-solo configuration script..."
|
||||
SSH.upload!(StringIO.new(solo_file), File.join(Vagrant.config.chef.provisioning_path, "solo.rb"))
|
||||
end
|
||||
|
||||
def run_chef_solo
|
||||
logger.info "Running chef recipes..."
|
||||
SSH.execute do |ssh|
|
||||
ssh.exec!("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json") do |channel, data, stream|
|
||||
# TODO: Very verbose. It would be easier to save the data and only show it during
|
||||
# an error, or when verbosity level is set high
|
||||
logger.info("#{stream}: #{data}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cookbooks_path
|
||||
File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,16 +1,17 @@
|
|||
module Vagrant
|
||||
class VM
|
||||
include Vagrant::Util
|
||||
attr_reader :vm
|
||||
|
||||
attr_accessor :vm
|
||||
attr_reader :actions
|
||||
attr_accessor :from
|
||||
|
||||
class << self
|
||||
# Bring up the virtual machine. Imports the base image and
|
||||
# provisions it.
|
||||
def up(from=Vagrant.config[:vm][:base])
|
||||
# Executes a specific action
|
||||
def execute!(action_klass)
|
||||
vm = new
|
||||
vm.from = from
|
||||
vm.create
|
||||
vm.add_action(action_klass)
|
||||
vm.execute!
|
||||
end
|
||||
|
||||
# Unpack the specified vm package
|
||||
|
@ -21,20 +22,20 @@ module Vagrant
|
|||
# Exit if folder of same name exists
|
||||
# TODO provide a way for them to specify the directory name
|
||||
error_and_exit(<<-error) if File.exists?(new_base_dir)
|
||||
The directory `#{File.basename(package_path, '.*')}` already exists under #{Vagrant.config[:vagrant][:home]}. Please
|
||||
remove it, rename your packaged VM file, or (TODO) specifiy an
|
||||
alternate directory
|
||||
The directory `#{File.basename(package_path, '.*')}` already exists under #{Vagrant.config[:vagrant][:home]}. Please
|
||||
remove it, rename your packaged VM file, or (TODO) specifiy an
|
||||
alternate directory
|
||||
error
|
||||
|
||||
|
||||
logger.info "Creating working dir: #{working_dir} ..."
|
||||
FileUtils.mkpath(working_dir)
|
||||
|
||||
logger.info "Decompressing the packaged VM: #{package_path} ..."
|
||||
decompress(package_path, working_dir)
|
||||
|
||||
|
||||
logger.info "Moving the unpackaged VM to #{new_base_dir} ..."
|
||||
FileUtils.mv(working_dir, Vagrant.config[:vagrant][:home])
|
||||
|
||||
|
||||
#Return the ovf file for importation
|
||||
Dir["#{new_base_dir}/*.ovf"].first
|
||||
end
|
||||
|
@ -44,14 +45,14 @@ error
|
|||
Zlib::GzipReader.open(path) do |gz|
|
||||
begin
|
||||
gz.each_line do |line|
|
||||
|
||||
|
||||
# If the line is a file delimiter create new file and write to it
|
||||
if line =~ file_delimeter
|
||||
|
||||
#Write the the part of the line belonging to the previous file
|
||||
if file
|
||||
file.write $1
|
||||
file.close
|
||||
file.close
|
||||
end
|
||||
|
||||
#Open a new file with the name contained in the delimiter
|
||||
|
@ -80,27 +81,11 @@ error
|
|||
|
||||
def initialize(vm=nil)
|
||||
@vm = vm
|
||||
@actions = []
|
||||
end
|
||||
|
||||
def create
|
||||
share_folder("vagrant-root", Env.root_path, Vagrant.config.vm.project_directory)
|
||||
|
||||
# Create the provisioning object, prior to doing anything so it can
|
||||
# set any configuration on the VM object prior to creation
|
||||
provisioning = Provisioning.new(self)
|
||||
|
||||
# The path of righteousness
|
||||
import
|
||||
move_hd if Vagrant.config[:vm][:hd_location]
|
||||
persist
|
||||
setup_mac_address
|
||||
forward_ports
|
||||
setup_shared_folders
|
||||
start
|
||||
mount_shared_folders
|
||||
|
||||
# Once we're started, run the provisioning
|
||||
provisioning.run
|
||||
def add_action(action_klass)
|
||||
@actions << action_klass.new(self)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -113,112 +98,35 @@ error
|
|||
@vm.destroy(:destroy_image => true)
|
||||
end
|
||||
|
||||
def move_hd
|
||||
error_and_exit(<<-error) unless @vm.powered_off?
|
||||
The virtual machine must be powered off to move its disk.
|
||||
error
|
||||
|
||||
old_image = hd.image.dup
|
||||
new_image_file = Vagrant.config[:vm][:hd_location] + old_image.filename
|
||||
|
||||
logger.info "Cloning current VM Disk to new location (#{ new_image_file })..."
|
||||
# TODO image extension default?
|
||||
new_image = hd.image.clone(new_image_file , Vagrant.config[:vm][:disk_image_format], true)
|
||||
hd.image = new_image
|
||||
|
||||
logger.info "Attaching new disk to VM ..."
|
||||
@vm.save
|
||||
|
||||
logger.info "Destroying old VM Disk (#{ old_image.filename })..."
|
||||
old_image.destroy(true)
|
||||
end
|
||||
|
||||
def import
|
||||
logger.info "Importing base VM (#{Vagrant.config[:vm][:base]})..."
|
||||
@vm = VirtualBox::VM.import(@from)
|
||||
end
|
||||
|
||||
def persist
|
||||
logger.info "Persisting the VM UUID (#{@vm.uuid})..."
|
||||
Env.persist_vm(@vm)
|
||||
end
|
||||
|
||||
def setup_mac_address
|
||||
logger.info "Matching MAC addresses..."
|
||||
@vm.nics.first.macaddress = Vagrant.config[:vm][:base_mac]
|
||||
@vm.save(true)
|
||||
end
|
||||
|
||||
def forward_ports
|
||||
logger.info "Forwarding ports..."
|
||||
|
||||
Vagrant.config.vm.forwarded_ports.each do |name, options|
|
||||
logger.info "Forwarding \"#{name}\": #{options[:guestport]} => #{options[:hostport]}"
|
||||
port = VirtualBox::ForwardedPort.new
|
||||
port.name = name
|
||||
port.hostport = options[:hostport]
|
||||
port.guestport = options[:guestport]
|
||||
@vm.forwarded_ports << port
|
||||
end
|
||||
|
||||
@vm.save(true)
|
||||
end
|
||||
|
||||
def setup_shared_folders
|
||||
logger.info "Creating shared folders metadata..."
|
||||
|
||||
shared_folders.each do |name, hostpath, guestpath|
|
||||
folder = VirtualBox::SharedFolder.new
|
||||
folder.name = name
|
||||
folder.hostpath = hostpath
|
||||
@vm.shared_folders << folder
|
||||
end
|
||||
|
||||
@vm.save(true)
|
||||
end
|
||||
|
||||
def mount_shared_folders
|
||||
logger.info "Mounting shared folders..."
|
||||
|
||||
Vagrant::SSH.execute do |ssh|
|
||||
shared_folders.each do |name, hostpath, guestpath|
|
||||
logger.info "-- #{name}: #{guestpath}"
|
||||
ssh.exec!("sudo mkdir -p #{guestpath}")
|
||||
ssh.exec!("sudo mount -t vboxsf #{name} #{guestpath}")
|
||||
ssh.exec!("sudo chown #{Vagrant.config.ssh.username} #{guestpath}")
|
||||
def execute!
|
||||
# Call the prepare method on each once its
|
||||
# initialized, then call the execute! method
|
||||
[:prepare, :execute!].each do |method|
|
||||
@actions.each do |action|
|
||||
action.send(method)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def start(sleep_interval = 5)
|
||||
logger.info "Booting VM..."
|
||||
@vm.start(:headless, true)
|
||||
|
||||
# Now we have to wait for the boot to be successful
|
||||
logger.info "Waiting for VM to boot..."
|
||||
|
||||
Vagrant.config[:ssh][:max_tries].to_i.times do |i|
|
||||
logger.info "Trying to connect (attempt ##{i+1} of #{Vagrant.config[:ssh][:max_tries]})..."
|
||||
|
||||
if Vagrant::SSH.up?
|
||||
logger.info "VM booted and ready for use!"
|
||||
return true
|
||||
end
|
||||
|
||||
sleep sleep_interval
|
||||
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
|
||||
|
||||
logger.info "Failed to connect to VM! Failed to boot?"
|
||||
false
|
||||
results
|
||||
end
|
||||
|
||||
def shared_folders(clear=false)
|
||||
@shared_folders = nil if clear
|
||||
@shared_folders ||= []
|
||||
end
|
||||
def destroy
|
||||
if @vm.running?
|
||||
logger.info "VM is running. Forcing immediate shutdown..."
|
||||
@vm.stop(true)
|
||||
end
|
||||
|
||||
def share_folder(name, hostpath, guestpath)
|
||||
shared_folders << [name, hostpath, guestpath]
|
||||
logger.info "Destroying VM and associated drives..."
|
||||
@vm.destroy(:destroy_image => true)
|
||||
end
|
||||
|
||||
def saved?
|
||||
|
@ -238,10 +146,10 @@ error
|
|||
|
||||
ovf_path = File.join(folder, "#{name}.ovf")
|
||||
tar_path = "#{folder}.box"
|
||||
|
||||
|
||||
logger.info "Exporting required VM files to working directory ..."
|
||||
@vm.export(ovf_path)
|
||||
|
||||
|
||||
logger.info "Packaging VM into #{tar_path} ..."
|
||||
Zlib::GzipWriter.open(tar_path) do |gz|
|
||||
first_file = true
|
||||
|
@ -249,7 +157,7 @@ error
|
|||
next if File.directory?(file)
|
||||
# Delimit the files, and guarantee new line for next file if not the first
|
||||
gz.write "#{delimiter}#{file}#{delimiter}"
|
||||
File.open(File.join(folder, file)).each { |line| gz.write(line) }
|
||||
File.open(File.join(folder, file)).each { |line| gz.write(line) }
|
||||
first_file = false
|
||||
end
|
||||
end
|
||||
|
@ -260,12 +168,6 @@ error
|
|||
tar_path
|
||||
end
|
||||
|
||||
|
||||
# TODO need a better way to which controller is the hd
|
||||
def hd
|
||||
@vm.storage_controllers.first.devices.first
|
||||
end
|
||||
|
||||
def powered_off?; @vm.powered_off? end
|
||||
|
||||
def export(filename); @vm.export(filename, {}, true) end
|
||||
|
|
|
@ -18,6 +18,7 @@ require 'contest'
|
|||
require 'mocha'
|
||||
|
||||
class Test::Unit::TestCase
|
||||
# Clears the previous config and sets up the new config
|
||||
def mock_config
|
||||
Vagrant::Config.instance_variable_set(:@config_runners, nil)
|
||||
Vagrant::Config.instance_variable_set(:@config, nil)
|
||||
|
@ -34,6 +35,7 @@ class Test::Unit::TestCase
|
|||
config.vm.base = "foo"
|
||||
config.vm.base_mac = "42"
|
||||
config.vm.project_directory = "/hobo"
|
||||
config.vm.disk_image_format = 'VMDK'
|
||||
config.vm.forward_port("ssh", 22, 2222)
|
||||
|
||||
config.package.delimiter = 'V'
|
||||
|
@ -48,6 +50,24 @@ class Test::Unit::TestCase
|
|||
config.vagrant.home = '~/.home'
|
||||
end
|
||||
|
||||
if block_given?
|
||||
Vagrant::Config.run do |config|
|
||||
yield config
|
||||
end
|
||||
end
|
||||
|
||||
Vagrant::Config.execute!
|
||||
end
|
||||
|
||||
# Sets up the mocks and instantiates an action for testing
|
||||
def mock_action(action_klass)
|
||||
@vm = mock("vboxvm")
|
||||
@mock_vm = mock("vm")
|
||||
@mock_vm.stubs(:vm).returns(@vm)
|
||||
@mock_vm.stubs(:vm=)
|
||||
@mock_vm.stubs(:invoke_callback)
|
||||
@action = action_klass.new(@mock_vm)
|
||||
|
||||
[@mock_vm, @vm, @action]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
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 VM" do
|
||||
assert_equal @mock_vm, @base.vm
|
||||
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
|
|
@ -0,0 +1,25 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ForwardPortsActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::ForwardPorts)
|
||||
mock_config
|
||||
end
|
||||
|
||||
should "create a port forwarding for the VM" do
|
||||
forwarded_ports = mock("forwarded_ports")
|
||||
|
||||
Vagrant.config.vm.forwarded_ports.each do |name, opts|
|
||||
forwarded_ports.expects(:<<).with do |port|
|
||||
assert_equal name, port.name
|
||||
assert_equal opts[:hostport], port.hostport
|
||||
assert_equal opts[:guestport], port.guestport
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
@vm.expects(:forwarded_ports).returns(forwarded_ports)
|
||||
@vm.expects(:save).with(true).once
|
||||
@action.execute!
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ImportActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@mock_vm, @vm, @import = mock_action(Vagrant::Actions::Import)
|
||||
|
||||
VirtualBox::VM.stubs(:import)
|
||||
end
|
||||
|
||||
should "invoke before/after callbacks around the import" do
|
||||
callback_seq = sequence("callback_seq")
|
||||
@mock_vm.expects(:invoke_callback).with(:before_import).once.in_sequence(callback_seq)
|
||||
VirtualBox::VM.expects(:import).once.in_sequence(callback_seq)
|
||||
@mock_vm.expects(:invoke_callback).with(:after_import).once.in_sequence(callback_seq)
|
||||
@import.execute!
|
||||
end
|
||||
|
||||
should "call import on VirtualBox::VM with the proper base" do
|
||||
VirtualBox::VM.expects(:import).once
|
||||
@import.execute!
|
||||
end
|
||||
|
||||
should "set the resulting VM as the VM of the Vagrant VM object" do
|
||||
new_vm = mock("new_vm")
|
||||
@mock_vm.expects(:vm=).with(new_vm).once
|
||||
VirtualBox::VM.expects(:import).returns(new_vm)
|
||||
@import.execute!
|
||||
end
|
||||
end
|
|
@ -0,0 +1,93 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class MoveHardDriveActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::MoveHardDrive)
|
||||
@hd_location = "/foo"
|
||||
mock_config do |config|
|
||||
File.expects(:directory?).with(@hd_location).returns(true)
|
||||
config.vm.hd_location = @hd_location
|
||||
end
|
||||
end
|
||||
|
||||
context "execution" do
|
||||
should "error and exit if the vm is not powered off" do
|
||||
@mock_vm.expects(:powered_off?).returns(false)
|
||||
@action.expects(:error_and_exit).once
|
||||
@action.execute!
|
||||
end
|
||||
|
||||
should "move the hard drive if vm is powered off" do
|
||||
@mock_vm.expects(:powered_off?).returns(true)
|
||||
@action.expects(:error_and_exit).never
|
||||
@action.expects(:destroy_drive_after).once
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
|
||||
context "new image path" do
|
||||
setup do
|
||||
@hd = mock("hd")
|
||||
@image = mock("image")
|
||||
@filename = "foo"
|
||||
@hd.stubs(:image).returns(@image)
|
||||
@image.stubs(:filename).returns(@filename)
|
||||
@action.stubs(:hard_drive).returns(@hd)
|
||||
end
|
||||
|
||||
should "be the configured hd location and the existing hard drive filename" do
|
||||
joined = File.join(Vagrant.config.vm.hd_location, @filename)
|
||||
assert_equal joined, @action.new_image_path
|
||||
end
|
||||
end
|
||||
|
||||
context "cloning and attaching new image" do
|
||||
setup do
|
||||
@hd = mock("hd")
|
||||
@image = mock("image")
|
||||
@hd.stubs(:image).returns(@image)
|
||||
@action.stubs(:hard_drive).returns(@hd)
|
||||
@new_image_path = "foo"
|
||||
@action.stubs(:new_image_path).returns(@new_image_path)
|
||||
end
|
||||
|
||||
should "clone to the new path" do
|
||||
new_image = mock("new_image")
|
||||
@image.expects(:clone).with(@new_image_path, Vagrant.config.vm.disk_image_format, true).returns(new_image).once
|
||||
@hd.expects(:image=).with(new_image).once
|
||||
@vm.expects(:save).once
|
||||
@action.clone_and_attach
|
||||
end
|
||||
end
|
||||
|
||||
context "destroying the old image" do
|
||||
setup do
|
||||
@hd = mock("hd")
|
||||
@action.stubs(:hard_drive).returns(@hd)
|
||||
end
|
||||
|
||||
should "yield the block, and destroy the old image after" do
|
||||
image = mock("image")
|
||||
image.stubs(:filename).returns("foo")
|
||||
destroy_seq = sequence("destroy_seq")
|
||||
@hd.expects(:image).returns(image).in_sequence(destroy_seq)
|
||||
@hd.expects(:foo).once.in_sequence(destroy_seq)
|
||||
image.expects(:destroy).with(true).once.in_sequence(destroy_seq)
|
||||
|
||||
@action.destroy_drive_after { @hd.foo }
|
||||
end
|
||||
|
||||
# Ensures that the image is not destroyed in an "ensure" block
|
||||
should "not destroy the image if an exception is raised" do
|
||||
image = mock("image")
|
||||
image.expects(:destroy).never
|
||||
@hd.expects(:image).returns(image)
|
||||
|
||||
assert_raises(Exception) do
|
||||
@action.destroy_drive_after do
|
||||
raise Exception.new("FOO")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +1,27 @@
|
|||
require File.join(File.dirname(__FILE__), '..', 'test_helper')
|
||||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class ProvisioningTest < Test::Unit::TestCase
|
||||
class ProvisionActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
# Stub upload so nothing happens
|
||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::Provision)
|
||||
|
||||
Vagrant::SSH.stubs(:execute)
|
||||
Vagrant::SSH.stubs(:upload!)
|
||||
|
||||
vm = mock("vm")
|
||||
vm.stubs(:share_folder)
|
||||
@prov = Vagrant::Provisioning.new(vm)
|
||||
mock_config
|
||||
end
|
||||
|
||||
context "initializing" do
|
||||
context "shared folders" do
|
||||
should "setup shared folder on VM for the cookbooks" do
|
||||
File.expects(:expand_path).with(Vagrant.config.chef.cookbooks_path, Vagrant::Env.root_path).returns("foo")
|
||||
Vagrant::Provisioning.any_instance.expects(:cookbooks_path).returns("bar")
|
||||
vm = mock("vm")
|
||||
vm.expects(:share_folder).with("vagrant-provisioning", "foo", "bar")
|
||||
Vagrant::Provisioning.new(vm)
|
||||
@action.expects(:cookbooks_path).returns("bar")
|
||||
assert_equal ["vagrant-provisioning", "foo", "bar"], @action.collect_shared_folders
|
||||
end
|
||||
end
|
||||
|
||||
context "cookbooks path" do
|
||||
should "return the proper cookbook path" do
|
||||
cookbooks_path = File.join(Vagrant.config.chef.provisioning_path, "cookbooks")
|
||||
assert_equal cookbooks_path, @prov.cookbooks_path
|
||||
assert_equal cookbooks_path, @action.cookbooks_path
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -30,14 +30,14 @@ class ProvisioningTest < Test::Unit::TestCase
|
|||
ssh = mock("ssh")
|
||||
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{Vagrant.config.chef.provisioning_path}")
|
||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||
@prov.chown_provisioning_folder
|
||||
@action.chown_provisioning_folder
|
||||
end
|
||||
end
|
||||
|
||||
context "generating and uploading json" do
|
||||
should "convert the JSON config to JSON" do
|
||||
Hash.any_instance.expects(:to_json).once.returns("foo")
|
||||
@prov.setup_json
|
||||
@action.setup_json
|
||||
end
|
||||
|
||||
should "add the project directory to the JSON" do
|
||||
|
@ -47,14 +47,14 @@ class ProvisioningTest < Test::Unit::TestCase
|
|||
true
|
||||
end
|
||||
|
||||
@prov.setup_json
|
||||
@action.setup_json
|
||||
end
|
||||
|
||||
should "upload a StringIO to dna.json" do
|
||||
StringIO.expects(:new).with(anything).returns("bar")
|
||||
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "dna.json").once.returns("baz")
|
||||
Vagrant::SSH.expects(:upload!).with("bar", "baz").once
|
||||
@prov.setup_json
|
||||
@action.setup_json
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -62,19 +62,19 @@ class ProvisioningTest < Test::Unit::TestCase
|
|||
should "upload properly generate the configuration file using configuration data" do
|
||||
expected_config = <<-config
|
||||
file_cache_path "#{Vagrant.config.chef.provisioning_path}"
|
||||
cookbook_path "#{@prov.cookbooks_path}"
|
||||
cookbook_path "#{@action.cookbooks_path}"
|
||||
config
|
||||
|
||||
StringIO.expects(:new).with(expected_config).once
|
||||
@prov.setup_solo_config
|
||||
@action.setup_solo_config
|
||||
end
|
||||
|
||||
should "upload this file as solo.rb to the provisioning folder" do
|
||||
@prov.expects(:cookbooks_path).returns("cookbooks")
|
||||
@action.expects(:cookbooks_path).returns("cookbooks")
|
||||
StringIO.expects(:new).returns("foo")
|
||||
File.expects(:join).with(Vagrant.config.chef.provisioning_path, "solo.rb").once.returns("bar")
|
||||
Vagrant::SSH.expects(:upload!).with("foo", "bar").once
|
||||
@prov.setup_solo_config
|
||||
@action.setup_solo_config
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -83,7 +83,7 @@ config
|
|||
ssh = mock("ssh")
|
||||
ssh.expects(:exec!).with("cd #{Vagrant.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json").once
|
||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||
@prov.run_chef_solo
|
||||
@action.run_chef_solo
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class SharedFoldersActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::SharedFolders)
|
||||
mock_config
|
||||
end
|
||||
|
||||
def stub_shared_folders
|
||||
folders = [%w{foo from to}, %w{bar bfrom bto}]
|
||||
@action.expects(:shared_folders).returns(folders)
|
||||
folders
|
||||
end
|
||||
|
||||
context "collecting shared folders" do
|
||||
should "return the arrays that the callback returns" do
|
||||
result = [[1,2,3],[4,5,6]]
|
||||
@mock_vm.expects(:invoke_callback).with(:collect_shared_folders).once.returns(result)
|
||||
assert_equal result, @action.shared_folders
|
||||
end
|
||||
|
||||
should "filter out invalid results" do
|
||||
result = [[1,2,3],[4,5]]
|
||||
@mock_vm.expects(:invoke_callback).with(:collect_shared_folders).once.returns(result)
|
||||
assert_equal [[1,2,3]], @action.shared_folders
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up shared folder metadata" do
|
||||
setup do
|
||||
@folders = stub_shared_folders
|
||||
end
|
||||
|
||||
should "add all shared folders to the VM" do
|
||||
share_seq = sequence("share_seq")
|
||||
shared_folders = mock("shared_folders")
|
||||
shared_folders.expects(:<<).in_sequence(share_seq).with() { |sf| sf.name == "foo" && sf.hostpath == "from" }
|
||||
shared_folders.expects(:<<).in_sequence(share_seq).with() { |sf| sf.name == "bar" && sf.hostpath == "bfrom" }
|
||||
@vm.stubs(:shared_folders).returns(shared_folders)
|
||||
@vm.expects(:save).with(true).once
|
||||
|
||||
@action.before_boot
|
||||
end
|
||||
end
|
||||
|
||||
context "mounting the shared folders" do
|
||||
setup do
|
||||
@folders = stub_shared_folders
|
||||
end
|
||||
|
||||
should "mount all shared folders to the VM" do
|
||||
mount_seq = sequence("mount_seq")
|
||||
ssh = mock("ssh")
|
||||
@folders.each do |name, hostpath, guestpath|
|
||||
ssh.expects(:exec!).with("sudo mkdir -p #{guestpath}").in_sequence(mount_seq)
|
||||
ssh.expects(:exec!).with("sudo mount -t vboxsf #{name} #{guestpath}").in_sequence(mount_seq)
|
||||
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{guestpath}").in_sequence(mount_seq)
|
||||
end
|
||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||
|
||||
@action.after_boot
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class StartActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::Start)
|
||||
@mock_vm.stubs(:invoke_callback)
|
||||
mock_config
|
||||
end
|
||||
|
||||
context "execution" do
|
||||
should "invoke before callback, boot, and invoke the after callback" do
|
||||
boot_seq = sequence("boot_seq")
|
||||
@mock_vm.expects(:invoke_callback).with(:before_boot).once.in_sequence(boot_seq)
|
||||
@action.expects(:boot).in_sequence(boot_seq)
|
||||
@action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq)
|
||||
@mock_vm.expects(:invoke_callback).with(:after_boot).once.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(:invoke_callback).with(:after_boot).never
|
||||
@action.expects(:error_and_exit).once.in_sequence(fail_boot_seq)
|
||||
@action.execute!
|
||||
end
|
||||
end
|
||||
|
||||
context "booting" do
|
||||
should "start the VM in headless mode" do
|
||||
@vm.expects(:start).with(:headless, true).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')
|
||||
Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq)
|
||||
Vagrant::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
|
||||
Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i).returns(false)
|
||||
assert !@action.wait_for_boot(0)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
|
||||
|
||||
class UpActionTest < Test::Unit::TestCase
|
||||
setup do
|
||||
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::Up)
|
||||
mock_config
|
||||
end
|
||||
|
||||
context "sub-actions" do
|
||||
setup do
|
||||
@default_order = [Vagrant::Actions::Import, Vagrant::Actions::ForwardPorts, Vagrant::Actions::SharedFolders, Vagrant::Actions::Start]
|
||||
end
|
||||
|
||||
def setup_action_expectations
|
||||
default_seq = sequence("default_seq")
|
||||
@default_order.each do |action|
|
||||
@mock_vm.expects(:add_action).with(action).once.in_sequence(default_seq)
|
||||
end
|
||||
end
|
||||
|
||||
should "do the proper actions by default" do
|
||||
setup_action_expectations
|
||||
@action.prepare
|
||||
end
|
||||
|
||||
should "add in the action to move hard drive if config is set" do
|
||||
mock_config do |config|
|
||||
File.expects(:directory?).with("foo").returns(true)
|
||||
config.vm.hd_location = "foo"
|
||||
end
|
||||
|
||||
@default_order.insert(1, Vagrant::Actions::MoveHardDrive)
|
||||
setup_action_expectations
|
||||
@action.prepare
|
||||
end
|
||||
end
|
||||
|
||||
context "callbacks" do
|
||||
should "call persist and mac address setup after import" do
|
||||
boot_seq = sequence("boot")
|
||||
@action.expects(:persist).once.in_sequence(boot_seq)
|
||||
@action.expects(:setup_mac_address).once.in_sequence(boot_seq)
|
||||
@action.after_import
|
||||
end
|
||||
|
||||
should "setup the root directory shared folder" do
|
||||
expected = ["vagrant-root", Vagrant::Env.root_path, Vagrant.config.vm.project_directory]
|
||||
assert_equal expected, @action.collect_shared_folders
|
||||
end
|
||||
end
|
||||
|
||||
context "persisting" do
|
||||
should "persist the VM with Env" do
|
||||
@vm.stubs(:uuid)
|
||||
Vagrant::Env.expects(:persist_vm).with(@vm).once
|
||||
@action.persist
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up MAC address" do
|
||||
should "match the mac address with the base" do
|
||||
nic = mock("nic")
|
||||
nic.expects(:macaddress=).once
|
||||
|
||||
@vm.expects(:nics).returns([nic]).once
|
||||
@vm.expects(:save).with(true).once
|
||||
|
||||
@action.setup_mac_address
|
||||
end
|
||||
end
|
||||
end
|
|
@ -31,7 +31,7 @@ class CommandsTest < Test::Unit::TestCase
|
|||
context "up" do
|
||||
setup do
|
||||
Vagrant::Env.stubs(:persisted_vm).returns(nil)
|
||||
Vagrant::VM.stubs(:up)
|
||||
Vagrant::VM.stubs(:execute!)
|
||||
end
|
||||
|
||||
should "require load the environment" do
|
||||
|
@ -46,8 +46,8 @@ class CommandsTest < Test::Unit::TestCase
|
|||
Vagrant::Commands.up
|
||||
end
|
||||
|
||||
should "call up on VM" do
|
||||
Vagrant::VM.expects(:up).once
|
||||
should "call the up action on VM" do
|
||||
Vagrant::VM.expects(:execute!).with(Vagrant::Actions::Up).once
|
||||
Vagrant::Commands.up
|
||||
end
|
||||
end
|
||||
|
@ -149,13 +149,13 @@ class CommandsTest < Test::Unit::TestCase
|
|||
@persisted_vm.expects(:package).never
|
||||
Vagrant::Commands.package
|
||||
end
|
||||
|
||||
|
||||
should "package the vm with the default name and the current directory" do
|
||||
@persisted_vm.expects(:package).with(Vagrant.config[:package][:name], FileUtils.pwd).once
|
||||
Vagrant::Commands.package
|
||||
end
|
||||
|
||||
should "package the vm with the specified name" do
|
||||
should "package the vm with the specified name" do
|
||||
@persisted_vm.expects(:package).with('foo', FileUtils.pwd).once
|
||||
Vagrant::Commands.package('foo')
|
||||
end
|
||||
|
|
|
@ -11,13 +11,88 @@ class VMTest < Test::Unit::TestCase
|
|||
Net::SSH.stubs(:start)
|
||||
end
|
||||
|
||||
context "vagrant up" do
|
||||
should "create a Vagrant::VM instance and call create" do
|
||||
inst = mock("instance")
|
||||
inst.expects(:create).once
|
||||
inst.expects(:from=).with(File.expand_path(Vagrant.config[:vm][:base]))
|
||||
Vagrant::VM.expects(:new).returns(inst)
|
||||
Vagrant::VM.up
|
||||
context "callbacks" do
|
||||
setup do
|
||||
@vm = Vagrant::VM.new(@mock_vm)
|
||||
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
|
||||
@vm.actions << action
|
||||
@vm.invoke_callback(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
should "invoke callback on actions which do respond to the method" do
|
||||
action = mock("action")
|
||||
action.expects(:foo).once
|
||||
|
||||
@vm.actions << action
|
||||
@vm.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
|
||||
|
||||
@vm.actions << action
|
||||
result << "foo#{i}"
|
||||
end
|
||||
|
||||
assert_equal result, @vm.invoke_callback(:foo)
|
||||
end
|
||||
end
|
||||
|
||||
context "actions" do
|
||||
setup do
|
||||
@vm = Vagrant::VM.new(@mock_vm)
|
||||
end
|
||||
|
||||
should "be empty initially" do
|
||||
assert @vm.actions.empty?
|
||||
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)
|
||||
@vm.add_action(action_klass)
|
||||
assert_equal 1, @vm.actions.length
|
||||
end
|
||||
|
||||
should "run #prepare on all actions, then #execute!" do
|
||||
action_seq = sequence("action_seq")
|
||||
actions = []
|
||||
5.times do |i|
|
||||
action = mock("action#{i}")
|
||||
|
||||
@vm.actions << action
|
||||
actions << action
|
||||
end
|
||||
|
||||
[:prepare, :execute!].each do |method|
|
||||
actions.each do |action|
|
||||
action.expects(method).once.in_sequence(action_seq)
|
||||
end
|
||||
end
|
||||
|
||||
@vm.execute!
|
||||
end
|
||||
|
||||
should "run actions on class method execute!" do
|
||||
vm = mock("vm")
|
||||
execute_seq = sequence("execute_seq")
|
||||
Vagrant::VM.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::VM.execute!("foo")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -40,23 +115,6 @@ class VMTest < Test::Unit::TestCase
|
|||
@vm = Vagrant::VM.new(@mock_vm)
|
||||
end
|
||||
|
||||
context "creating" do
|
||||
should "create the VM in the proper order" do
|
||||
prov = mock("prov")
|
||||
create_seq = sequence("create_seq")
|
||||
Vagrant::Provisioning.expects(:new).with(@vm).in_sequence(create_seq).returns(prov)
|
||||
@vm.expects(:import).in_sequence(create_seq)
|
||||
@vm.expects(:persist).in_sequence(create_seq)
|
||||
@vm.expects(:setup_mac_address).in_sequence(create_seq)
|
||||
@vm.expects(:forward_ports).in_sequence(create_seq)
|
||||
@vm.expects(:setup_shared_folders).in_sequence(create_seq)
|
||||
@vm.expects(:start).in_sequence(create_seq)
|
||||
@vm.expects(:mount_shared_folders).in_sequence(create_seq)
|
||||
prov.expects(:run).in_sequence(create_seq)
|
||||
@vm.create
|
||||
end
|
||||
end
|
||||
|
||||
context "destroying" do
|
||||
setup do
|
||||
@mock_vm.stubs(:running?).returns(false)
|
||||
|
@ -75,127 +133,6 @@ class VMTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
context "starting" do
|
||||
setup do
|
||||
@mock_vm.stubs(:start)
|
||||
end
|
||||
|
||||
should "start the VM in headless mode" do
|
||||
@mock_vm.expects(:start).with(:headless, true).once
|
||||
Vagrant::SSH.expects(:up?).once.returns(true)
|
||||
@vm.start(0)
|
||||
end
|
||||
|
||||
should "repeatedly ping the SSH port and return false with no response" do
|
||||
seq = sequence('pings')
|
||||
Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq)
|
||||
Vagrant::SSH.expects(:up?).once.returns(true).in_sequence(seq)
|
||||
assert @vm.start(0)
|
||||
end
|
||||
|
||||
should "ping the max number of times then just return" do
|
||||
Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i).returns(false)
|
||||
assert !@vm.start(0)
|
||||
end
|
||||
end
|
||||
|
||||
context "importing" do
|
||||
should "call import on VirtualBox::VM with the proper base" do
|
||||
VirtualBox::VM.expects(:import).once
|
||||
@vm.import
|
||||
end
|
||||
|
||||
should "return the VM object" do
|
||||
VirtualBox::VM.expects(:import).returns(@mock_vm).once
|
||||
assert_equal @mock_vm, @vm.import
|
||||
end
|
||||
end
|
||||
|
||||
context "persisting" do
|
||||
should "persist the VM with Env" do
|
||||
@mock_vm.stubs(:uuid)
|
||||
Vagrant::Env.expects(:persist_vm).with(@mock_vm).once
|
||||
@vm.persist
|
||||
end
|
||||
end
|
||||
|
||||
context "setting up MAC address" do
|
||||
should "match the mac address with the base" do
|
||||
nic = mock("nic")
|
||||
nic.expects(:macaddress=).once
|
||||
|
||||
@mock_vm.expects(:nics).returns([nic]).once
|
||||
@mock_vm.expects(:save).with(true).once
|
||||
|
||||
@vm.setup_mac_address
|
||||
end
|
||||
end
|
||||
|
||||
context "forwarding ports" do
|
||||
should "create a port forwarding for the VM" do
|
||||
# TODO: Test the actual port value to make sure it has the
|
||||
# correct attributes
|
||||
forwarded_ports = mock("forwarded_ports")
|
||||
forwarded_ports.expects(:<<)
|
||||
@mock_vm.expects(:forwarded_ports).returns(forwarded_ports)
|
||||
@mock_vm.expects(:save).with(true).once
|
||||
@vm.forward_ports
|
||||
end
|
||||
end
|
||||
|
||||
context "shared folders" do
|
||||
setup do
|
||||
@mock_vm = mock("mock_vm")
|
||||
@vm = Vagrant::VM.new(@mock_vm)
|
||||
end
|
||||
|
||||
should "not have any shared folders initially" do
|
||||
assert @vm.shared_folders.empty?
|
||||
end
|
||||
|
||||
should "be able to add shared folders" do
|
||||
@vm.share_folder("foo", "from", "to")
|
||||
assert_equal 1, @vm.shared_folders.length
|
||||
end
|
||||
|
||||
should "be able to clear shared folders" do
|
||||
@vm.share_folder("foo", "from", "to")
|
||||
assert !@vm.shared_folders.empty?
|
||||
@vm.shared_folders(true)
|
||||
assert @vm.shared_folders.empty?
|
||||
end
|
||||
|
||||
should "add all shared folders to the VM with 'setup_shared_folders'" do
|
||||
@vm.share_folder("foo", "from", "to")
|
||||
@vm.share_folder("bar", "bfrom", "bto")
|
||||
|
||||
share_seq = sequence("share_seq")
|
||||
shared_folders = mock("shared_folders")
|
||||
shared_folders.expects(:<<).in_sequence(share_seq).with() { |sf| sf.name == "foo" && sf.hostpath == "from" }
|
||||
shared_folders.expects(:<<).in_sequence(share_seq).with() { |sf| sf.name == "bar" && sf.hostpath == "bfrom" }
|
||||
@mock_vm.stubs(:shared_folders).returns(shared_folders)
|
||||
@mock_vm.expects(:save).with(true).once
|
||||
|
||||
@vm.setup_shared_folders
|
||||
end
|
||||
|
||||
should "mount all shared folders to the VM with `mount_shared_folders`" do
|
||||
@vm.share_folder("foo", "from", "to")
|
||||
@vm.share_folder("bar", "bfrom", "bto")
|
||||
|
||||
mount_seq = sequence("mount_seq")
|
||||
ssh = mock("ssh")
|
||||
@vm.shared_folders.each do |name, hostpath, guestpath|
|
||||
ssh.expects(:exec!).with("sudo mkdir -p #{guestpath}").in_sequence(mount_seq)
|
||||
ssh.expects(:exec!).with("sudo mount -t vboxsf #{name} #{guestpath}").in_sequence(mount_seq)
|
||||
ssh.expects(:exec!).with("sudo chown #{Vagrant.config.ssh.username} #{guestpath}").in_sequence(mount_seq)
|
||||
end
|
||||
Vagrant::SSH.expects(:execute).yields(ssh)
|
||||
|
||||
@vm.mount_shared_folders
|
||||
end
|
||||
end
|
||||
|
||||
context "saving the state" do
|
||||
should "check if a VM is saved" do
|
||||
@mock_vm.expects(:saved?).returns("foo")
|
||||
|
@ -207,40 +144,6 @@ class VMTest < Test::Unit::TestCase
|
|||
@vm.save_state
|
||||
end
|
||||
end
|
||||
|
||||
context "creating a new vm with a specified disk storage location" do
|
||||
should "error and exit of the vm is not powered off" do
|
||||
# Exit does not prevent method from proceeding in test, so we must set expectations
|
||||
vm = move_hd_expectations
|
||||
@mock_vm.expects(:powered_off?).returns(false)
|
||||
vm.expects(:error_and_exit)
|
||||
vm.move_hd
|
||||
end
|
||||
|
||||
should "create assign a new disk image, and delete the old one" do
|
||||
vm = move_hd_expectations
|
||||
@mock_vm.expects(:powered_off?).returns(true)
|
||||
vm.move_hd
|
||||
end
|
||||
|
||||
def move_hd_expectations
|
||||
image, hd = mock('image'), mock('hd')
|
||||
|
||||
Vagrant.config[:vm].expects(:hd_location).at_least_once.returns('/locations/')
|
||||
image.expects(:clone).with(Vagrant.config[:vm][:hd_location] + 'foo', Vagrant.config[:vm][:disk_image_format], true).returns(image)
|
||||
image.expects(:filename).twice.returns('foo')
|
||||
image.expects(:destroy)
|
||||
|
||||
hd.expects(:image).twice.returns(image)
|
||||
hd.expects(:image=).with(image)
|
||||
|
||||
@mock_vm.expects(:save)
|
||||
|
||||
vm = Vagrant::VM.new(@mock_vm)
|
||||
vm.expects(:hd).times(3).returns(hd)
|
||||
vm
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO more comprehensive testing
|
||||
|
@ -258,9 +161,9 @@ class VMTest < Test::Unit::TestCase
|
|||
assert_equal Vagrant::VM.new(@mock_vm).package(name, location), "#{new_dir}.box"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "unpackaging a vm" do
|
||||
|
||||
|
||||
# TODO test actual decompression
|
||||
should "call decompress with the path to the file and the directory to decompress to" do
|
||||
working_dir = File.join FileUtils.pwd, 'something'
|
||||
|
|
Loading…
Reference in New Issue