Merge pull request #7353 from mitchellh/sethvargo/package_preflight

Move pre-flight package validation to middleware
This commit is contained in:
Seth Vargo 2016-05-27 17:16:40 -04:00
commit 171434bbf9
7 changed files with 159 additions and 93 deletions

View File

@ -20,25 +20,63 @@ module Vagrant
class Package
include Util
# Perform sanity validations that the provided output filepath is sane.
# In particular, this function validates:
#
# - The output path is a regular file (not a directory or symlink)
# - No file currently exists at the given path
# - A directory of package files was actually provided (internal)
#
# @param [String] output path to the output file
# @param [String] directory path to a directory containing the files
def self.validate!(output, directory)
filename = File.basename(output.to_s)
output = fullpath(output)
if File.directory?(output)
raise Vagrant::Errors::PackageOutputDirectory
end
if File.exist?(output)
raise Vagrant::Errors::PackageOutputExists, filename: filename
end
if !Vagrant::Util::Presence.present?(directory) || !File.directory?(directory)
raise Vagrant::Errors::PackageRequiresDirectory
end
end
# Calculate the full path of the given path, relative to the current
# working directory (where the command was run).
#
# @param [String] output the relative path
def self.fullpath(output)
File.expand_path(output, Dir.pwd)
end
# The path to the final output file.
# @return [String]
attr_reader :fullpath
def initialize(app, env)
@app = app
env["package.files"] ||= {}
env["package.output"] ||= "package.box"
@fullpath = self.class.fullpath(env["package.output"])
end
def call(env)
@env = env
file_name = File.basename(@env["package.output"].to_s)
raise Errors::PackageOutputDirectory if File.directory?(tar_path)
raise Errors::PackageOutputExists, file_name:file_name if File.exist?(tar_path)
raise Errors::PackageRequiresDirectory if !env["package.directory"] ||
!File.directory?(env["package.directory"])
self.class.validate!(env["package.output"], env["package.directory"])
raise Errors::PackageOutputDirectory if File.directory?(fullpath)
@app.call(env)
@env[:ui].info I18n.t("vagrant.actions.general.package.compressing", tar_path: tar_path)
@env[:ui].info I18n.t("vagrant.actions.general.package.compressing", fullpath: fullpath)
copy_include_files
setup_private_key
compress
@ -54,7 +92,7 @@ module Vagrant
end
# Cleanup any packaged files if the packaging failed at some point.
File.delete(tar_path) if File.exist?(tar_path)
File.delete(fullpath) if File.exist?(fullpath)
end
# This method copies the include files (passed in via command line)
@ -88,7 +126,7 @@ module Vagrant
def compress
# Get the output path. We have to do this up here so that the
# pwd returns the proper thing.
output_path = tar_path.to_s
output_path = fullpath.to_s
# Switch into that directory and package everything up
Util::SafeChdir.safe_chdir(@env["package.directory"]) do
@ -147,11 +185,6 @@ module Vagrant
f.puts %Q[end]
end
end
# Path to the final box output file
def tar_path
File.expand_path(@env["package.output"], FileUtils.pwd)
end
end
end
end

View File

@ -33,6 +33,8 @@ module VagrantPlugins
autoload :Network, File.expand_path("../action/network", __FILE__)
autoload :NetworkFixIPv6, File.expand_path("../action/network_fix_ipv6", __FILE__)
autoload :Package, File.expand_path("../action/package", __FILE__)
autoload :PackageSetupFiles, File.expand_path("../action/package_setup_files", __FILE__)
autoload :PackageSetupFolders, File.expand_path("../action/package_setup_folders", __FILE__)
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
autoload :PrepareCloneSnapshot, File.expand_path("../action/prepare_clone_snapshot", __FILE__)
autoload :PrepareNFSSettings, File.expand_path("../action/prepare_nfs_settings", __FILE__)
@ -41,12 +43,14 @@ module VagrantPlugins
autoload :Resume, File.expand_path("../action/resume", __FILE__)
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
autoload :SnapshotDelete, File.expand_path("../action/snapshot_delete", __FILE__)
autoload :SnapshotRestore, File.expand_path("../action/snapshot_restore", __FILE__)
autoload :SnapshotSave, File.expand_path("../action/snapshot_save", __FILE__)
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
# @deprecated use {PackageSetupFiles} instead
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
# Include the built-in modules so that we can use them as top-level
# things.
include Vagrant::Action::Builtin
@ -150,7 +154,8 @@ module VagrantPlugins
next
end
b2.use SetupPackageFiles
b2.use PackageSetupFolders
b2.use PackageSetupFiles
b2.use CheckAccessible
b2.use action_halt
b2.use ClearForwardedPorts

View File

@ -1,6 +1,4 @@
require 'fileutils'
require 'vagrant/action/general/package'
require_relative "../../../../lib/vagrant/action/general/package"
module VagrantPlugins
module ProviderVirtualBox
@ -10,33 +8,7 @@ module VagrantPlugins
# called in the unit tests.
alias_method :general_call, :call
def call(env)
# Setup the temporary directory
@temp_dir = env[:tmp_path].join(Time.now.to_i.to_s)
env["export.temp_dir"] = @temp_dir
FileUtils.mkpath(env["export.temp_dir"])
# 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)
# Always call recover to clean up the temp dir
clean_temp_dir
end
def recover(env)
clean_temp_dir
super
end
protected
def clean_temp_dir
if @temp_dir && File.exist?(@temp_dir)
FileUtils.rm_rf(@temp_dir)
end
end
end
end

View File

@ -0,0 +1,51 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class PackageSetupFiles
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

View File

@ -0,0 +1,38 @@
require "fileutils"
require_relative "../../../../lib/vagrant/action/general/package"
module VagrantPlugins
module ProviderVirtualBox
module Action
class PackageSetupFolders
include Vagrant::Util::Presence
def initialize(app, env)
@app = app
end
def call(env)
env["package.output"] ||= "package.box"
env["package.directory"] ||= Dir.mktmpdir("package-", env[:tmp_path])
# Match up a couple environmental variables so that the other parts of
# Vagrant will do the right thing.
env["export.temp_dir"] = env["package.directory"]
Vagrant::Action::General::Package.validate!(
env["package.output"], env["package.directory"])
@app.call(env)
end
def recover(env)
dir = env["package.directory"]
if File.exist?(dir)
FileUtils.rm_rf(dir)
end
end
end
end
end
end

View File

@ -1,49 +1,15 @@
require "log4r"
require_relative "package_setup_files"
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)
class SetupPackageFiles < PackageSetupFiles
def initialize(*)
@logger = Log4r::Logger.new("vagrant::plugins::virtualbox::setup_package_files")
@logger.warn { "SetupPackageFiles has been renamed to PackageSetupFiles" }
super
end
end
end

View File

@ -1734,10 +1734,10 @@ en:
Sometimes, Vagrant will attempt to auto-correct this for you. In this
case, Vagrant was unable to. This is usually because the guest machine
is in a state which doesn't allow modifying port forwarding. You could
try 'vagrant reload' (equivalent of running a halt followed by an up)
so vagrant can attempt to auto-correct this upon booting. Be warned
try 'vagrant reload' (equivalent of running a halt followed by an up)
so vagrant can attempt to auto-correct this upon booting. Be warned
that any unsaved work might be lost.
fixed_collision: |-
Fixed port collision for %{guest_port} => %{host_port}. Now on port %{new_port}.
forwarding: Forwarding ports...
@ -1883,16 +1883,17 @@ en:
general:
package:
packaging: "Packaging additional file: %{file}"
compressing: "Compressing package to: %{tar_path}"
compressing: "Compressing package to: %{fullpath}"
output_exists: |-
The specified file '%{file_name}' to save the package as already exists. Please
The specified file '%{filename}' to save the package as already exists. Please
remove this file or specify a different file name for outputting.
output_is_directory: |-
The specified output is a directory. Please specify a path including
a filename.
requires_directory: |-
A directory was not specified to package. This should never happen
and is a result of an internal inconsistency.
and is a result of an internal inconsistency. Please report a bug
on the Vagrant bug tracker.
include_file_missing: |-
Package include file doesn't exist: %{file}