This commit is contained in:
Nick Anderson 2013-07-12 10:45:36 -05:00
commit c4c8042c0d
29 changed files with 228 additions and 30 deletions

View File

@ -1,4 +1,35 @@
## 1.2.3 (unreleased)
## 1.2.4 (unreleased)
FEATURES:
- Chef solo and client provisioning now support a `custom_config_path`
setting that accepts a path to a Ruby file to load as part of Chef
configuration, allowing you to override any setting available. [GH-876]
IMPROVEMENTS:
- `vagrant box remove` works with only the name of the box if that
box exists only backed by one provider. [GH-1032]
- `vagrant destroy` returns exit status 1 if any of the confirmations
are declined. [GH-923]
- Forwarded ports can specify a host IP and guest IP to bind to. [GH-1121]
BUG FIXES:
- Boxes downloaded as part of `vagrant up` are now done so _prior_ to
config validation. This allows Vagrantfiles to references files that
may be in the box itself. [GH-1061]
- Chef removes dna.json and encrypted data bag secret file prior to
uploading. [GH-1111]
- NFS synced folders exporting sub-directories of other exported folders now
works properly. [GH-785]
- NFS shared folders properly dereference symlinks so that the real path
is used, avoiding mount errors [GH-1101]
- SSH channel is closed after the exit status is received, potentially
eliminating any SSH hangs. [GH-603]
- Fix regression where VirtualBox detection wasn't working anymore. [GH-1918]
## 1.2.3 (July 9, 2013)
FEATURES:
@ -27,6 +58,8 @@ IMPROVEMENTS:
- Default SSH forwarded port now binds to 127.0.0.1 so only local
connections are allowed. [GH-1785]
- Use `netctl` for Arch Linux network configuration. [GH-1760]
- Improve fedora host detection regular expression. [GH-1913]
- SSH shows a proper error on EHOSTUNREACH. [GH-1911]
BUG FIXES:

View File

@ -131,7 +131,7 @@ module Vagrant
# Converts the builder stack to a runnable action sequence.
#
# @param [Vagrant::Action::Environment] env The action environment
# @param [Hash] env The action environment hash
# @return [Object] A callable object
def to_app(env)
app_stack = nil

View File

@ -29,6 +29,7 @@ module Vagrant
# The result is only true if the user said "Y"
env[:result] = choice && choice.upcase == "Y"
env["#{@force_key}_result".to_sym] = env[:result]
@app.call(env)
end

View File

@ -1,5 +1,7 @@
require "thread"
require "log4r"
module Vagrant
module Action
module Builtin
@ -13,9 +15,16 @@ module Vagrant
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::action::builtin::handle_box_url")
end
def call(env)
if !env[:machine].config.vm.box || !env[:machine].config.vm.box_url
@logger.info("Skipping HandleBoxUrl because box or box_url not set.")
@app.call(env)
return
end
if !env[:machine].box
# Get a "big lock" to make sure that our more fine grained
# lock access is thread safe.

View File

@ -37,7 +37,9 @@ module Vagrant
# Expand the host path, create it if we have to and
# store away the folder.
hostpath = Pathname.new(opts[:hostpath]).expand_path(env[:root_path])
hostpath = Pathname.new(opts[:hostpath]).
expand_path(env[:root_path]).
realpath
if !hostpath.directory? && opts[:create]
# Host path doesn't exist, so let's create it.

View File

@ -455,6 +455,10 @@ module Vagrant
error_key(:ssh_key_type_not_supported)
end
class SSHNoRoute < VagrantError
error_key(:ssh_no_route)
end
class SSHNotReady < VagrantError
error_key(:ssh_not_ready)
end

View File

@ -3,7 +3,7 @@ module Vagrant
# class that simply stores a short and long description of the state
# of a machine.
#
# The state also stores a state "id" which ca be used as a unique
# The state also stores a state "id" which can be used as a unique
# identifier for a state. This should be a symbol. This allows internal
# code to compare state such as ":not_created" instead of using
# string comparison.

View File

@ -27,7 +27,7 @@ module Vagrant
def initialize(*command)
@options = command.last.is_a?(Hash) ? command.pop : {}
@command = command
@command[0] = Which.which(@command[0]) if !File.file? @command[0]
@command[0] = Which.which(@command[0]) if !File.file?(@command[0])
if !@command[0]
raise Errors::CommandUnavailableWindows, file: command[0] if Platform.windows?
raise Errors::CommandUnavailable, file: command[0]

View File

@ -2,5 +2,5 @@ module Vagrant
# This will always be up to date with the current version of Vagrant,
# since it is used to generate the gemspec and is also the source of
# the version for `vagrant -v`
VERSION = "1.2.3.dev"
VERSION = "1.2.4.dev"
end

View File

@ -12,7 +12,27 @@ module VagrantPlugins
# Parse the options
argv = parse_options(opts)
return if !argv
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if argv.length < 2
raise Vagrant::Errors::CLIInvalidUsage, :help => opts.help.chomp if argv.length < 1
if !argv[1]
# Try to automatically determine the provider.
providers = []
@env.boxes.all.each do |name, provider|
if name == argv[0]
providers << provider
end
end
if providers.length > 1
@env.ui.error(
I18n.t("vagrant.commands.box.remove_must_specify_provider",
name: args[0],
providers: providers.join(", ")))
return 1
end
argv[1] = providers[0] || ""
end
b = nil
begin

View File

@ -19,12 +19,17 @@ module VagrantPlugins
return if !argv
@logger.debug("'Destroy' each target VM...")
declined = false
with_target_vms(argv, :reverse => true) do |vm|
vm.action(:destroy, :force_confirm_destroy => options[:force])
action_env = vm.action(
:destroy, :force_confirm_destroy => options[:force])
declined = true if action_env.has_key?(:force_confirm_destroy_result) &&
action_env[:force_confirm_destroy_result] == false
end
# Success, exit status 0
0
# Success if no confirms were declined
declined ? 1 : 0
end
end
end

View File

@ -235,6 +235,9 @@ module VagrantPlugins
rescue Errno::EHOSTDOWN
# This is raised if we get an ICMP DestinationUnknown error.
raise Vagrant::Errors::SSHHostDown
rescue Errno::EHOSTUNREACH
# This is raised if we can't work out how to route traffic.
raise Vagrant::Errors::SSHNoRoute
rescue NotImplementedError
# This is raised if a private key type that Net-SSH doesn't support
# is used. Show a nicer error.
@ -279,6 +282,10 @@ module VagrantPlugins
ch2.on_request("exit-status") do |ch3, data|
exit_status = data.read_long
@logger.debug("Exit status: #{exit_status}")
# Close the channel, since after the exit status we're
# probably done. This fixes up issues with hanging.
channel.close
end
# Set the terminal

View File

@ -35,10 +35,55 @@ module VagrantPlugins
end
def nfs_export(id, ip, folders)
# We need to build up mapping of directories that are enclosed
# within each other because the exports file has to have subdirectories
# of an exported directory on the same line. e.g.:
#
# "/foo" "/foo/bar" ...
# "/bar"
#
# We build up this mapping within the following hash.
@logger.debug("Compiling map of sub-directories for NFS exports...")
dirmap = {}
folders.each do |_, opts|
hostpath = opts[:hostpath]
found = false
dirmap.each do |dirs, diropts|
dirs.each do |dir|
if dir.start_with?(hostpath) || hostpath.start_with?(dir)
# TODO: verify opts and diropts are _identical_, raise an error
# if not. NFS mandates subdirectories have identical options.
dirs << hostpath
found = true
break
end
end
break if found
end
if !found
dirmap[[hostpath]] = opts.dup
end
end
# Sort all the keys by length so that the directory closest to
# the root is exported first.
dirmap.each do |dirs, _|
dirs.sort_by! { |d| d.length }
end
@logger.info("Exporting the following for NFS...")
dirmap.each do |dirs, opts|
@logger.info("NFS DIR: #{dirs.inspect}")
@logger.info("NFS OPTS: #{opts.inspect}")
end
output = TemplateRenderer.render(@nfs_exports_template,
:uuid => id,
:ip => ip,
:folders => folders)
:folders => dirmap)
# The sleep ensures that the output is truly flushed before any `sudo`
# commands are issued.

View File

@ -34,7 +34,7 @@ module VagrantPlugins
release_file = Pathname.new("/etc/redhat-release")
begin
release_file.open("r") do |f|
version_number = /Fedora release ([0-9]+)/.match(f.gets)[1].to_i
version_number = /Fedora.*release ([0-9]+)/.match(f.gets)[1].to_i
if version_number >= 16
# "service nfs-server" will redirect properly to systemctl
# when "service nfs-server restart" is called.

View File

@ -293,12 +293,21 @@ module VagrantPlugins
def self.action_up
Vagrant::Action::Builder.new.tap do |b|
b.use CheckVirtualbox
# Handle box_url downloading early so that if the Vagrantfile
# references any files in the box or something it all just
# works fine.
b.use Call, Created do |env, b2|
if !env[:result]
b2.use HandleBoxUrl
end
end
b.use ConfigValidate
b.use Call, Created do |env, b2|
# If the VM is NOT created yet, then do the setup steps
if !env[:result]
b2.use CheckAccessible
b2.use HandleBoxUrl
b2.use Import
b2.use MatchMACAddress
end

View File

@ -32,7 +32,8 @@ module VagrantPlugins
# specific driver to instantiate.
begin
@version = read_version || ""
rescue Vagrant::Util::Subprocess::LaunchError
rescue Vagrant::Errors::CommandUnavailable,
Vagrant::Errors::CommandUnavailableWindows
# This means that VirtualBox was not found, so we raise this
# error here.
raise Vagrant::Errors::VirtualBoxNotDetected

View File

@ -142,9 +142,9 @@ module VagrantPlugins
ports.each do |options|
pf_builder = [options[:name],
options[:protocol] || "tcp",
"",
options[:hostip] || "",
options[:hostport],
"",
options[:guestip] || "",
options[:guestport]]
args.concat(["--natpf#{options[:adapter] || 1}",

View File

@ -142,9 +142,9 @@ module VagrantPlugins
ports.each do |options|
pf_builder = [options[:name],
options[:protocol] || "tcp",
"",
options[:hostip] || "",
options[:hostport],
"",
options[:guestip] || "",
options[:guestport]]
args.concat(["--natpf#{options[:adapter] || 1}",

View File

@ -6,6 +6,7 @@ module VagrantPlugins
attr_accessor :attempts
attr_accessor :binary_path
attr_accessor :binary_env
attr_accessor :custom_config_path
attr_accessor :http_proxy
attr_accessor :http_proxy_user
attr_accessor :http_proxy_pass
@ -26,6 +27,7 @@ module VagrantPlugins
@attempts = UNSET_VALUE
@binary_path = UNSET_VALUE
@binary_env = UNSET_VALUE
@custom_config_path = UNSET_VALUE
@http_proxy = UNSET_VALUE
@http_proxy_user = UNSET_VALUE
@http_proxy_pass = UNSET_VALUE
@ -46,6 +48,7 @@ module VagrantPlugins
@attempts = 1 if @attempts == UNSET_VALUE
@binary_path = nil if @binary_path == UNSET_VALUE
@binary_env = nil if @binary_env == UNSET_VALUE
@custom_config_path = nil if @custom_config_path == UNSET_VALUE
@http_proxy = nil if @http_proxy == UNSET_VALUE
@http_proxy_user = nil if @http_proxy_user == UNSET_VALUE
@http_proxy_pass = nil if @http_proxy_pass == UNSET_VALUE
@ -68,6 +71,22 @@ module VagrantPlugins
end
end
# Just like the normal configuration "validate" method except that
# it returns an array of errors that should be merged into some
# other error accumulator.
def validate_base(machine)
errors = []
if @custom_config_path
expanded = File.expand_path(@custom_config_path, machine.env.root_path)
if !File.file?(expanded)
errors << I18n.t("vagrant.config.chef.custom_config_path_missing")
end
end
errors
end
# Adds a recipe to the run list
def add_recipe(name)
name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/

View File

@ -44,6 +44,7 @@ module VagrantPlugins
def validate(machine)
errors = _detected_errors
errors.concat(validate_base(machine))
errors << I18n.t("vagrant.config.chef.server_url_empty") if \
!chef_server_url || chef_server_url.strip == ""
errors << I18n.t("vagrant.config.chef.validation_key_path") if \

View File

@ -59,6 +59,7 @@ module VagrantPlugins
def validate(machine)
errors = _detected_errors
errors.concat(validate_base(machine))
errors << I18n.t("vagrant.config.chef.cookbooks_path_empty") if \
!cookbooks_path || [cookbooks_path].flatten.empty?

View File

@ -47,14 +47,26 @@ module VagrantPlugins
end
def setup_config(template, filename, template_vars)
# If we have custom configuration, upload it
remote_custom_config_path = nil
if @config.custom_config_path
expanded = File.expand_path(
@config.custom_config_path, @machine.env.root_path)
remote_custom_config_path = File.join(
config.provisioning_path, "custom-config.rb")
@machine.communicate.upload(expanded, remote_custom_config_path)
end
config_file = Vagrant::Util::TemplateRenderer.render(template, {
:log_level => @config.log_level.to_sym,
:custom_configuration => remote_custom_config_path,
:http_proxy => @config.http_proxy,
:http_proxy_user => @config.http_proxy_user,
:http_proxy_pass => @config.http_proxy_pass,
:https_proxy => @config.https_proxy,
:https_proxy_user => @config.https_proxy_user,
:https_proxy_pass => @config.https_proxy_pass,
:log_level => @config.log_level.to_sym,
:no_proxy => @config.no_proxy
}.merge(template_vars))
@ -85,7 +97,11 @@ module VagrantPlugins
temp.write(json)
temp.close
@machine.communicate.upload(temp.path, File.join(@config.provisioning_path, "dna.json"))
remote_file = File.join(@config.provisioning_path, "dna.json")
@machine.communicate.tap do |comm|
comm.sudo("rm #{remote_file}", :error_check => false)
comm.upload(temp.path, remote_file)
end
end
end
end

View File

@ -114,9 +114,12 @@ module VagrantPlugins
def upload_encrypted_data_bag_secret
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
@machine.communicate.upload(encrypted_data_bag_secret_key_path,
@machine.communicate.tap do |comm|
comm.sudo("rm #{@config.encrypted_data_bag_secret}", :error_check => false)
comm.upload(encrypted_data_bag_secret_key_path,
@config.encrypted_data_bag_secret)
end
end
def setup_solo_config
cookbooks_path = guest_paths(@cookbook_folders)

View File

@ -426,6 +426,10 @@ en:
usually indicates that SSH within the guest machine was unable to
properly start up. Please boot the VM in GUI mode to check whether
it is booting properly.
ssh_no_route: |-
While attempting to connect with SSH, a "no route to host" (EHOSTUNREACH)
error was received. Please verify your network settings are correct
and try again.
ssh_host_down: |-
While attempting to connect with SSH, a "host is down" (EHOSTDOWN)
error was received. Please verify your SSH settings are correct
@ -584,6 +588,8 @@ en:
cookbooks_path_empty: "Must specify a cookbooks path for chef solo."
cookbooks_path_missing: |-
Cookbook path doesn't exist: %{path}
custom_config_path_missing: |-
Path specified for "custom_config_path" does not exist.
server_url_empty: "Chef server URL must be populated."
validation_key_path: "Validation key path must be valid path to your chef server validation key."
loader:
@ -605,8 +611,6 @@ en:
network_invalid: |-
The network type '%{type}' is not valid. Please use
'hostonly' or 'bridged'.
network_ip_required: |-
Host only networks require an IP as an argument.
network_ip_invalid: |-
The host only network IP '%{ip}' is invalid.
network_ip_ends_one: |-
@ -650,8 +654,19 @@ en:
vm_already_running: |-
VirtualBox VM is already running.
vm_not_created: "VM not created. Moving on..."
vm_not_running: "VM is not currently running. Please bring it up to run this command."
vm_not_running: "VM is not currently running. Please, first bring it up with `vagrant up` then run this command."
box:
remove_must_specify_provider: |-
Multiple providers were found for the box '%{name}'. Please specify
the specific provider for the box you want to remove. The list of
providers backing this box is:
'%{providers}'
To remove the box for a specific provider, run the following command,
filling in PROVIDER with one of the providers above:
vagrant box remove '%{name}' PROVIDER
no_installed_boxes: "There are no installed boxes! Use `vagrant box add` to add some."
removing: |-
Removing box '%{name}' with provider '%{provider}'...

View File

@ -1,5 +1,5 @@
# VAGRANT-BEGIN: <%= uuid %>
<% folders.each do |name, opts| %>
"<%= opts[:hostpath] %>" <%= ip %><% if opts[:map_uid] -%> -mapall=<%= [opts[:map_uid],opts[:map_gid]].compact.join(":") %><% end -%>
<% folders.each do |dirs, opts| %>
<%= dirs.map { |d| "\"#{d}\"" }.join(" ") %> <%= ip %><% if opts[:map_uid] -%> -mapall=<%= [opts[:map_uid],opts[:map_gid]].compact.join(":") %><% end -%>
<% end %>
# VAGRANT-END: <%= uuid %>

View File

@ -1,5 +1,5 @@
# VAGRANT-BEGIN: <%= uuid %>
<% folders.each do |name, opts| %>
<%= opts[:hostpath] %> <%= ip %><% if opts[:map_uid] -%> -alldirs -mapall=<%= [opts[:map_uid],opts[:map_gid]].compact.join(":") %><% end -%>
<% folders.each do |dirs, opts| %>
<%= dirs.map { |d| "\"#{d}\"" }.join(" ") %> <%= ip %><% if opts[:map_uid] -%> -alldirs -mapall=<%= [opts[:map_uid],opts[:map_gid]].compact.join(":") %><% end -%>
<% end %>
# VAGRANT-END: <%= uuid %>

View File

@ -30,3 +30,7 @@ no_proxy <%= no_proxy.inspect %>
pid_file "/var/run/chef/chef-client.pid"
Mixlib::Log::Formatter.show_time = true
<% if custom_configuration -%>
load "<%= custom_configuration %>"
<% end -%>

View File

@ -25,3 +25,7 @@ https_proxy <%= https_proxy.inspect %>
https_proxy_user <%= https_proxy_user.inspect %>
https_proxy_pass <%= https_proxy_pass.inspect %>
no_proxy <%= no_proxy.inspect %>
<% if custom_configuration -%>
load "<%= custom_configuration %>"
<% end -%>

View File

@ -17,7 +17,6 @@ Gem::Specification.new do |s|
s.add_dependency "childprocess", "~> 0.3.7"
s.add_dependency "erubis", "~> 2.7.0"
s.add_dependency "i18n", "~> 0.6.0"
s.add_dependency "json", ">= 1.5.1", "< 1.8.0"
s.add_dependency "log4r", "~> 1.1.9"
s.add_dependency "net-ssh", "~> 2.6.6"
s.add_dependency "net-scp", "~> 1.1.0"