`vagrant package` works with multi-VM environments

This commit is contained in:
Mitchell Hashimoto 2010-05-17 14:12:11 -07:00
parent f30645a967
commit 19be5f141e
3 changed files with 141 additions and 74 deletions

View File

@ -8,23 +8,58 @@ module Vagrant
description "Packages a vagrant environment for distribution" description "Packages a vagrant environment for distribution"
def execute(args=[]) def execute(args=[])
parse_options(args) args = parse_options(args)
if !options[:base] if options[:base]
# Packaging a pre-existing environment package_base
env.require_persisted_vm
else else
# Packaging a base box; that is a VM not tied to a specific package_single(args[0])
# vagrant environment end
vm = VM.find(options[:base]) end
vm.env = env if vm
env.vm = vm
error_and_exit(:vm_base_not_found, :name => options[:base]) unless vm def package_base
# Packaging a base box; that is a VM not tied to a specific
# vagrant environment
vm = VM.find(options[:base])
if !vm
error_and_exit(:vm_base_not_found, :name => options[:base])
return # for tests
end end
error_and_exit(:vm_power_off_to_package) unless env.vm.powered_off? vm.env = env
env.vm.package(args[0], options[:include]) package_vm(vm)
end
def package_single(name)
if name.nil? && env.multivm?
error_and_exit(:package_multivm)
return
end
vm = if name.nil?
env.vms.values.first
else
env.vms[name.to_sym]
end
if vm.nil?
error_and_exit(:unknown_vm, :vm => name)
return
elsif !vm.created?
error_and_exit(:environment_not_created)
return
end
package_vm(vm)
end
def package_vm(vm)
if !vm.powered_off?
error_and_exit(:vm_power_off_to_package)
return # for tests
end
vm.package(options[:output], options[:include])
end end
def options_spec(opts) def options_spec(opts)
@ -32,15 +67,21 @@ module Vagrant
# Defaults # Defaults
options[:include] = [] options[:include] = []
options[:base] = nil
options[:output] = nil
opts.on("--base [BASE]", "Name or UUID of VM to create a base box from") do |v| opts.on("--base BASE", "Name or UUID of VM to create a base box from") do |v|
options[:base] = v options[:base] = v
end end
opts.on("--include x,y,z", Array, "List of files to include in the package") do |v| opts.on("--include x,y,z", Array, "List of files to include in the package") do |v|
options[:include] = v options[:include] = v
end end
opts.on("-o", "--output FILE", "File to save the package as.") do |v|
options[:output] = v
end
end end
end end
end end
end end

View File

@ -108,6 +108,11 @@
<%= Vagrant::Environment::ROOTFILE_NAME %> and running `vagrant up` <%= Vagrant::Environment::ROOTFILE_NAME %> and running `vagrant up`
:package_include_file_doesnt_exist: |- :package_include_file_doesnt_exist: |-
File specified to include: '<%= filename %>' does not exist! File specified to include: '<%= filename %>' does not exist!
:package_multivm: |-
Because this Vagrant environment represents multiple VMs, a
specific VM must be specified. This can be done by calling
`vagrant package NAME` where NAME is a valid VM represented by
your Vagrantfile.
:package_requires_export: |- :package_requires_export: |-
Package must be used in conjunction with export. Package must be used in conjunction with export.
:provisioner_invalid_class: |- :provisioner_invalid_class: |-

View File

@ -4,81 +4,102 @@ class CommandsPackageTest < Test::Unit::TestCase
setup do setup do
@klass = Vagrant::Commands::Package @klass = Vagrant::Commands::Package
@persisted_vm = mock("persisted_vm")
@persisted_vm.stubs(:execute!)
@env = mock_environment @env = mock_environment
@env.stubs(:require_persisted_vm)
@env.stubs(:vm).returns(@persisted_vm)
@instance = @klass.new(@env) @instance = @klass.new(@env)
end end
context "executing" do context "executing" do
should "package base if a base is given" do
@instance.expects(:package_base).once
@instance.execute(["--base","foo"])
end
should "package single if no name is given" do
@instance.expects(:package_single).with(nil).once
@instance.execute
end
should "package single if a name is given" do
@instance.expects(:package_single).with("foo").once
@instance.execute(["foo"])
end
end
context "packaging base" do
should "error and exit if no VM is found" do
Vagrant::VM.expects(:find).with("foo").returns(nil)
@instance.expects(:error_and_exit).with(:vm_base_not_found, :name => "foo").once
@instance.execute(["--base", "foo"])
end
should "package the VM like any other VM" do
vm = mock("vm")
Vagrant::VM.expects(:find).with("foo").returns(vm)
vm.expects(:env=).with(@env).once
@instance.expects(:package_vm).with(vm).once
@instance.execute(["--base", "foo"])
end
end
context "packaging a single VM" do
setup do setup do
@persisted_vm.stubs(:package) @vm = mock("vm")
@persisted_vm.stubs(:powered_off?).returns(true) @vm.stubs(:created?).returns(true)
@vms = {:bar => @vm}
@env.stubs(:vms).returns(@vms)
@env.stubs(:multivm?).returns(false)
end end
context "with no base specified" do should "error and exit if no name is given in a multi-vm env" do
should "require a persisted vm" do @env.stubs(:multivm?).returns(true)
@env.expects(:require_persisted_vm).once @instance.expects(:error_and_exit).with(:package_multivm).once
@instance.execute @instance.package_single(nil)
end
end end
context "with base specified" do should "error and exit if the VM doesn't exist" do
setup do @instance.expects(:error_and_exit).with(:unknown_vm, :vm => :foo).once
@vm = mock("vm") @instance.package_single(:foo)
Vagrant::VM.stubs(:find).with(@name).returns(@vm)
@vm.stubs(:env=).with(@env)
@env.stubs(:vm=)
@name = "bar"
end
should "find the given base and set it on the env" do
Vagrant::VM.expects(:find).with(@name).returns(@vm)
@vm.expects(:env=).with(@env)
@env.expects(:vm=).with(@vm)
@instance.execute(["foo", "--base", @name])
end
should "error if the VM is not found" do
Vagrant::VM.expects(:find).with(@name).returns(nil)
@instance.expects(:error_and_exit).with(:vm_base_not_found, :name => @name).once
@instance.execute(["foo", "--base", @name])
end
end end
context "shared (with and without base specified)" do should "error and exit if the VM is not created" do
should "error and exit if the VM is not powered off" do @vm.stubs(:created?).returns(false)
@persisted_vm.stubs(:powered_off?).returns(false) @instance.expects(:error_and_exit).with(:environment_not_created).once
@instance.expects(:error_and_exit).with(:vm_power_off_to_package).once @instance.package_single(:bar)
@persisted_vm.expects(:package).never end
@instance.execute
end
should "call package on the persisted VM" do should "use the first VM is no name is given in a single VM environment" do
@persisted_vm.expects(:package).once @instance.expects(:package_vm).with(@vm).once
@instance.execute @instance.package_single(nil)
end end
should "pass the out path and include_files to the package method" do should "package the VM" do
out_path = mock("out_path") @instance.expects(:package_vm).with(@vm).once
include_files = "foo" @instance.package_single(:bar)
@persisted_vm.expects(:package).with(out_path, [include_files]).once end
@instance.execute([out_path, "--include", include_files]) end
end
should "default to an empty array when not include_files are specified" do context "packaging a VM" do
out_path = mock("out_path") setup do
@persisted_vm.expects(:package).with(out_path, []).once @vm = mock("vm")
@instance.execute([out_path]) @vm.stubs(:powered_off?).returns(true)
end
@options = {}
@instance.stubs(:options).returns(@options)
end
should "error and exit if VM is not powered off" do
@vm.stubs(:powered_off?).returns(false)
@instance.expects(:error_and_exit).with(:vm_power_off_to_package).once
@instance.package_vm(@vm)
end
should "package the VM with the proper arguments" do
@options[:output] = "foo.box"
@options[:include] = :bar
@vm.expects(:package).with(@options[:output], @options[:include]).once
@instance.package_vm(@vm)
end end
end end
end end