diff --git a/CHANGELOG.md b/CHANGELOG.md index bb6027bc9..994bc3e78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ IMPROVEMENTS: them altogether. [GH-1004] - Specify the default provider with the `VAGRANT_DEFAULT_PROVIDER` environmental variable. [GH-1478] + - Invalid settings are now caught and shown in a user-friendly way. [GH-1484] BUG FIXES: diff --git a/lib/vagrant/plugin/v2/config.rb b/lib/vagrant/plugin/v2/config.rb index f3db8e610..dfdff8e1c 100644 --- a/lib/vagrant/plugin/v2/config.rb +++ b/lib/vagrant/plugin/v2/config.rb @@ -1,3 +1,5 @@ +require "set" + module Vagrant module Plugin module V2 @@ -57,9 +59,27 @@ module Vagrant end end + # Persist through the set of invalid methods + this_invalid = @__invalid_methods || Set.new + other_invalid = other.instance_variable_get(:"@__invalid_methods") || Set.new + result.instance_variable_set(:"@__invalid_methods", this_invalid + other_invalid) + result end + # Capture all bad configuration calls and save them for an error + # message later during validation. + def method_missing(name, *args, &block) + name = name.to_s + name = name[0...-1] if name.end_with?("=") + + @__invalid_methods ||= Set.new + @__invalid_methods.add(name) + + # Return the dummy object so that anything else works + ::Vagrant::Config::V2::DummyConfig.new + end + # Allows setting options from a hash. By default this simply calls # the `#{key}=` method on the config class with the value, which is # the expected behavior most of the time. @@ -79,6 +99,11 @@ module Vagrant instance_variables_hash.to_json(*a) end + # A default to_s implementation. + def to_s + self.class.to_s + end + # Returns the instance variables as a hash of key-value pairs. def instance_variables_hash instance_variables.inject({}) do |acc, iv| @@ -94,6 +119,16 @@ module Vagrant # validated. # @return [Hash] def validate(machine) + return { self.to_s => _detected_errors } + end + + # This returns any automatically detected errors. + # + # @return [Array] + def _detected_errors + return [] if !@__invalid_methods || @__invalid_methods.empty? + return [I18n.t("vagrant.config.common.bad_field", + :fields => @__invalid_methods.to_a.sort.join(", "))] end end end diff --git a/plugins/kernel_v2/config/nfs.rb b/plugins/kernel_v2/config/nfs.rb index cd5964d6d..21e7ea7bf 100644 --- a/plugins/kernel_v2/config/nfs.rb +++ b/plugins/kernel_v2/config/nfs.rb @@ -5,6 +5,10 @@ module VagrantPlugins class NFSConfig < Vagrant.plugin("2", :config) attr_accessor :map_uid attr_accessor :map_gid + + def to_s + "NFS" + end end end end diff --git a/plugins/kernel_v2/config/package.rb b/plugins/kernel_v2/config/package.rb index eda055895..c8b3b8c56 100644 --- a/plugins/kernel_v2/config/package.rb +++ b/plugins/kernel_v2/config/package.rb @@ -4,6 +4,10 @@ module VagrantPlugins module Kernel_V2 class PackageConfig < Vagrant.plugin("2", :config) attr_accessor :name + + def to_s + "Package" + end end end end diff --git a/plugins/kernel_v2/config/ssh.rb b/plugins/kernel_v2/config/ssh.rb index e57bc3ba0..083efb743 100644 --- a/plugins/kernel_v2/config/ssh.rb +++ b/plugins/kernel_v2/config/ssh.rb @@ -40,8 +40,12 @@ module VagrantPlugins @username = nil if @username == UNSET_VALUE end + def to_s + "SSH" + end + def validate(machine) - errors = [] + errors = _detected_errors [:max_tries, :timeout].each do |field| value = instance_variable_get("@#{field}".to_sym) @@ -54,7 +58,7 @@ module VagrantPlugins end # Return the errors - { "ssh" => errors } + { to_s => errors } end end end diff --git a/plugins/kernel_v2/config/vagrant.rb b/plugins/kernel_v2/config/vagrant.rb index afe13213f..5e049fe60 100644 --- a/plugins/kernel_v2/config/vagrant.rb +++ b/plugins/kernel_v2/config/vagrant.rb @@ -4,6 +4,10 @@ module VagrantPlugins module Kernel_V2 class VagrantConfig < Vagrant.plugin("2", :config) attr_accessor :host + + def to_s + "Vagrant" + end end end end diff --git a/plugins/kernel_v2/config/vm.rb b/plugins/kernel_v2/config/vm.rb index 45320f3f4..32e4efeba 100644 --- a/plugins/kernel_v2/config/vm.rb +++ b/plugins/kernel_v2/config/vm.rb @@ -268,7 +268,7 @@ module VagrantPlugins end def validate(machine) - errors = [] + errors = _detected_errors errors << I18n.t("vagrant.config.vm.box_missing") if !box errors << I18n.t("vagrant.config.vm.box_not_found", :name => box) if \ box && !box_url && !machine.box diff --git a/plugins/providers/virtualbox/config.rb b/plugins/providers/virtualbox/config.rb index 846bdc08e..b14d262d0 100644 --- a/plugins/providers/virtualbox/config.rb +++ b/plugins/providers/virtualbox/config.rb @@ -77,6 +77,10 @@ module VagrantPlugins # The default name is just nothing, and we default it @name = nil if @name == UNSET_VALUE end + + def to_s + "VirtualBox" + end end end end diff --git a/plugins/provisioners/chef/config/chef_client.rb b/plugins/provisioners/chef/config/chef_client.rb index 7d89aa5fd..360fd4c7a 100644 --- a/plugins/provisioners/chef/config/chef_client.rb +++ b/plugins/provisioners/chef/config/chef_client.rb @@ -23,7 +23,7 @@ module VagrantPlugins def encrypted_data_bag_secret; @encrypted_data_bag_secret || "/tmp/encrypted_data_bag_secret"; end def validate(machine) - errors = [] + errors = _detected_errors 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 \ diff --git a/plugins/provisioners/chef/config/chef_solo.rb b/plugins/provisioners/chef/config/chef_solo.rb index 1bc5e21f3..e6c91f0a2 100644 --- a/plugins/provisioners/chef/config/chef_solo.rb +++ b/plugins/provisioners/chef/config/chef_solo.rb @@ -52,7 +52,7 @@ module VagrantPlugins end def validate(machine) - errors = [] + errors = _detected_errors errors << I18n.t("vagrant.config.chef.cookbooks_path_empty") if \ !cookbooks_path || [cookbooks_path].flatten.empty? errors << I18n.t("vagrant.config.chef.run_list_empty") if \ diff --git a/plugins/provisioners/shell/config.rb b/plugins/provisioners/shell/config.rb index c44c8f72a..61b39d0ae 100644 --- a/plugins/provisioners/shell/config.rb +++ b/plugins/provisioners/shell/config.rb @@ -21,7 +21,7 @@ module VagrantPlugins end def validate(machine) - errors = [] + errors = _detected_errors # Validate that the parameters are properly set if path && inline diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 708fb542b..832fb2701 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -471,6 +471,7 @@ en: #------------------------------------------------------------------------------- config: common: + bad_field: "The following settings don't exist: %{fields}" error_empty: "`%{field}` must be not be empty." chef: cookbooks_path_empty: "Must specify a cookbooks path for chef solo."