`vagrant package` a single VM works!
This commit is contained in:
parent
ef5eabb63d
commit
85a4fb82a8
|
@ -6,25 +6,25 @@ module VagrantPlugins
|
||||||
def execute
|
def execute
|
||||||
options = {}
|
options = {}
|
||||||
|
|
||||||
opts = OptionParser.new do |opts|
|
opts = OptionParser.new do |o|
|
||||||
opts.banner = "Usage: vagrant package [vm-name] [--base name] [--output name.box]"
|
o.banner = "Usage: vagrant package [vm-name] [--base name] [--output name.box]"
|
||||||
opts.separator " [--include one,two,three] [--vagrantfile file]"
|
o.separator " [--include one,two,three] [--vagrantfile file]"
|
||||||
|
|
||||||
opts.separator ""
|
o.separator ""
|
||||||
|
|
||||||
opts.on("--base NAME", "Name of a VM in virtualbox to package as a base box") do |b|
|
o.on("--base NAME", "Name of a VM in virtualbox to package as a base box") do |b|
|
||||||
options[:base] = b
|
options[:base] = b
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on("--output NAME", "Name of the file to output") do |o|
|
o.on("--output NAME", "Name of the file to output") do |output|
|
||||||
options[:output] = o
|
options[:output] = output
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on("--include x,y,z", Array, "Additional files to package with the box.") do |i|
|
o.on("--include x,y,z", Array, "Additional files to package with the box.") do |i|
|
||||||
options[:include] = i
|
options[:include] = i
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on("--vagrantfile file", "Vagrantfile to package with the box.") do |v|
|
o.on("--vagrantfile file", "Vagrantfile to package with the box.") do |v|
|
||||||
options[:vagrantfile] = v
|
options[:vagrantfile] = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,7 +55,6 @@ module VagrantPlugins
|
||||||
|
|
||||||
def package_target(name, options)
|
def package_target(name, options)
|
||||||
with_target_vms(name, :single_target => true) do |vm|
|
with_target_vms(name, :single_target => true) do |vm|
|
||||||
raise Vagrant::Errors::VMNotCreatedError if !vm.created?
|
|
||||||
@logger.debug("Packaging VM: #{vm.name}")
|
@logger.debug("Packaging VM: #{vm.name}")
|
||||||
package_vm(vm, options)
|
package_vm(vm, options)
|
||||||
end
|
end
|
||||||
|
@ -68,7 +67,7 @@ module VagrantPlugins
|
||||||
acc
|
acc
|
||||||
end
|
end
|
||||||
|
|
||||||
vm.package(opts)
|
vm.action(:package, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,7 @@ module VagrantPlugins
|
||||||
autoload :DestroyConfirm, File.expand_path("../action/destroy_confirm", __FILE__)
|
autoload :DestroyConfirm, File.expand_path("../action/destroy_confirm", __FILE__)
|
||||||
autoload :DestroyUnusedNetworkInterfaces, File.expand_path("../action/destroy_unused_network_interfaces", __FILE__)
|
autoload :DestroyUnusedNetworkInterfaces, File.expand_path("../action/destroy_unused_network_interfaces", __FILE__)
|
||||||
autoload :DiscardState, File.expand_path("../action/discard_state", __FILE__)
|
autoload :DiscardState, File.expand_path("../action/discard_state", __FILE__)
|
||||||
|
autoload :Export, File.expand_path("../action/export", __FILE__)
|
||||||
autoload :ForwardPorts, File.expand_path("../action/forward_ports", __FILE__)
|
autoload :ForwardPorts, File.expand_path("../action/forward_ports", __FILE__)
|
||||||
autoload :Halt, File.expand_path("../action/halt", __FILE__)
|
autoload :Halt, File.expand_path("../action/halt", __FILE__)
|
||||||
autoload :HostName, File.expand_path("../action/host_name", __FILE__)
|
autoload :HostName, File.expand_path("../action/host_name", __FILE__)
|
||||||
|
@ -34,11 +35,14 @@ module VagrantPlugins
|
||||||
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
|
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
|
||||||
autoload :Network, File.expand_path("../action/network", __FILE__)
|
autoload :Network, File.expand_path("../action/network", __FILE__)
|
||||||
autoload :NFS, File.expand_path("../action/nfs", __FILE__)
|
autoload :NFS, File.expand_path("../action/nfs", __FILE__)
|
||||||
|
autoload :Package, File.expand_path("../action/package", __FILE__)
|
||||||
|
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
|
||||||
autoload :Provision, File.expand_path("../action/provision", __FILE__)
|
autoload :Provision, File.expand_path("../action/provision", __FILE__)
|
||||||
autoload :ProvisionerCleanup, File.expand_path("../action/provisioner_cleanup", __FILE__)
|
autoload :ProvisionerCleanup, File.expand_path("../action/provisioner_cleanup", __FILE__)
|
||||||
autoload :PruneNFSExports, File.expand_path("../action/prune_nfs_exports", __FILE__)
|
autoload :PruneNFSExports, File.expand_path("../action/prune_nfs_exports", __FILE__)
|
||||||
autoload :Resume, File.expand_path("../action/resume", __FILE__)
|
autoload :Resume, File.expand_path("../action/resume", __FILE__)
|
||||||
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
||||||
|
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
|
||||||
autoload :ShareFolders, File.expand_path("../action/share_folders", __FILE__)
|
autoload :ShareFolders, File.expand_path("../action/share_folders", __FILE__)
|
||||||
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
|
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
|
||||||
|
|
||||||
|
@ -116,6 +120,28 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This action packages the virtual machine into a single box file.
|
||||||
|
def self.action_package
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use CheckVirtualbox
|
||||||
|
b.use Call, Created do |env1, b2|
|
||||||
|
if !env1[:result]
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
b2.use SetupPackageFiles
|
||||||
|
b2.use CheckAccessible
|
||||||
|
b2.use action_halt
|
||||||
|
b2.use ClearForwardedPorts
|
||||||
|
b2.use ClearSharedFolders
|
||||||
|
b2.use Export
|
||||||
|
b2.use PackageVagrantfile
|
||||||
|
b2.use Package
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This action just runs the provisioners on the machine.
|
# This action just runs the provisioners on the machine.
|
||||||
def self.action_provision
|
def self.action_provision
|
||||||
Vagrant::Action::Builder.new.tap do |b|
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
require "fileutils"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class Export
|
||||||
|
attr_reader :temp_dir
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
|
||||||
|
raise Vagrant::Errors::VMPowerOffToPackage if @env[:machine].provider.state != :poweroff
|
||||||
|
|
||||||
|
setup_temp_dir
|
||||||
|
export
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
|
||||||
|
recover(env) # called to cleanup temp directory
|
||||||
|
end
|
||||||
|
|
||||||
|
def recover(env)
|
||||||
|
if temp_dir && File.exist?(temp_dir)
|
||||||
|
FileUtils.rm_rf(temp_dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_temp_dir
|
||||||
|
@env[:ui].info I18n.t("vagrant.actions.vm.export.create_dir")
|
||||||
|
@temp_dir = @env["export.temp_dir"] = @env[:tmp_path].join(Time.now.to_i.to_s)
|
||||||
|
FileUtils.mkpath(@env["export.temp_dir"])
|
||||||
|
end
|
||||||
|
|
||||||
|
def export
|
||||||
|
@env[:ui].info I18n.t("vagrant.actions.vm.export.exporting")
|
||||||
|
@env[:machine].provider.driver.export(ovf_path) do |progress|
|
||||||
|
@env[:ui].clear_line
|
||||||
|
@env[:ui].report_progress(progress.percent, 100, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Clear the line a final time so the next data can appear
|
||||||
|
# alone on the line.
|
||||||
|
@env[:ui].clear_line
|
||||||
|
end
|
||||||
|
|
||||||
|
def ovf_path
|
||||||
|
File.join(@env["export.temp_dir"], "box.ovf")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
require 'vagrant/action/general/package'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class Package < Vagrant::Action::General::Package
|
||||||
|
# Doing this so that we can test that the parent is properly
|
||||||
|
# called in the unit tests.
|
||||||
|
alias_method :general_call, :call
|
||||||
|
def call(env)
|
||||||
|
# Just match up a couple environmental variables so that
|
||||||
|
# the superclass will do the right thing. Then, call the
|
||||||
|
# superclass
|
||||||
|
env["package.directory"] = env["export.temp_dir"]
|
||||||
|
general_call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,33 @@
|
||||||
|
require 'vagrant/util/template_renderer'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class PackageVagrantfile
|
||||||
|
# For TemplateRenderer
|
||||||
|
include Vagrant::Util
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
create_vagrantfile
|
||||||
|
@app.call(env)
|
||||||
|
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[:machine].provider.driver.read_mac_address
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,51 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class SetupPackageFiles
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
|
||||||
|
env["package.include"] ||= []
|
||||||
|
env["package.vagrantfile"] ||= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
files = {}
|
||||||
|
env["package.include"].each do |file|
|
||||||
|
source = Pathname.new(file)
|
||||||
|
dest = nil
|
||||||
|
|
||||||
|
# If the source is relative then we add the file as-is to the include
|
||||||
|
# directory. Otherwise, we copy only the file into the root of the
|
||||||
|
# include directory. Kind of strange, but seems to match what people
|
||||||
|
# expect based on history.
|
||||||
|
if source.relative?
|
||||||
|
dest = source
|
||||||
|
else
|
||||||
|
dest = source.basename
|
||||||
|
end
|
||||||
|
|
||||||
|
# Assign the mapping
|
||||||
|
files[file] = dest
|
||||||
|
end
|
||||||
|
|
||||||
|
if env["package.vagrantfile"]
|
||||||
|
# Vagrantfiles are treated special and mapped to a specific file
|
||||||
|
files[env["package.vagrantfile"]] = "_Vagrantfile"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verify the mapping
|
||||||
|
files.each do |from, _|
|
||||||
|
raise Vagrant::Errors::PackageIncludeMissing,
|
||||||
|
:file => from if !File.exist?(from)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Save the mapping
|
||||||
|
env["package.files"] = files
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue