Fixes #10224: Allow validation of config while ignoring provider

This commit adds a new flag to the `vagrant validate` command which
allows users to completely ignore the provider block of a config file.
This is useful for when you are running `vagrant validate` in CI and
don't want to install a valid provider to check the syntax of your
Vagratnfile. When the flag is invoked, a warning will be displayed
saying that the provider block will be ignored and not validated.
This commit is contained in:
Brian Cain 2018-10-30 12:35:46 -07:00
parent 716a5f1501
commit 6051f3598e
No known key found for this signature in database
GPG Key ID: 9FC4639B2E4510A0
8 changed files with 170 additions and 47 deletions

View File

@ -12,7 +12,7 @@ module Vagrant
def call(env)
if !env.key?(:config_validate) || env[:config_validate]
errors = env[:machine].config.validate(env[:machine])
errors = env[:machine].config.validate(env[:machine], env[:ignore_provider])
if errors && !errors.empty?
raise Errors::ConfigInvalid,

View File

@ -60,14 +60,18 @@ module Vagrant
#
# @param [Environment] env
# @return [Hash]
def validate(machine)
def validate(machine, ignore_provider=nil)
# Go through each of the configuration keys and validate
errors = {}
@keys.each do |_key, instance|
if instance.respond_to?(:validate)
# Validate this single item, and if we have errors then
# we merge them into our total errors list.
result = instance.validate(machine)
if _key == :vm
result = instance.validate(machine, ignore_provider)
else
result = instance.validate(machine)
end
if result && !result.empty?
errors = Util.merge_errors(errors, result)
end

View File

@ -8,17 +8,32 @@ module VagrantPlugins
end
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant validate"
o.banner = "Usage: vagrant validate [options]"
o.separator ""
o.separator "Validates a Vagrantfile config"
o.separator ""
o.separator "Options:"
o.separator ""
o.on("-p", "--ignore-provider", "Ignores provider config options") do |p|
options[:ignore_provider] = p
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
action_env = {}
if options[:ignore_provider]
action_env[:ignore_provider] = true
end
# Validate the configuration of all machines
with_target_vms() do |machine|
machine.action_raw(:config_validate, Vagrant::Action::Builtin::ConfigValidate)
machine.action_raw(:config_validate, Vagrant::Action::Builtin::ConfigValidate, action_env)
end
@env.ui.info(I18n.t("vagrant.commands.validate.success"))

View File

@ -582,7 +582,7 @@ module VagrantPlugins
@__synced_folders
end
def validate(machine)
def validate(machine, ignore_provider=nil)
errors = _detected_errors
if !box && !clone && !machine.provider_options[:box_optional]
@ -737,9 +737,13 @@ module VagrantPlugins
# Validate only the _active_ provider
if machine.provider_config
provider_errors = machine.provider_config.validate(machine)
if provider_errors
errors = Vagrant::Config::V2::Util.merge_errors(errors, provider_errors)
if !ignore_provider
provider_errors = machine.provider_config.validate(machine)
if provider_errors
errors = Vagrant::Config::V2::Util.merge_errors(errors, provider_errors)
end
else
machine.ui.warn(I18n.t("vagrant.config.vm.ignore_provider_config"))
end
end

View File

@ -1845,6 +1845,8 @@ en:
hostname_invalid_characters: |-
The hostname set for the VM should only contain letters, numbers,
hyphens or dots. It cannot start with a hyphen or dot.
ignore_provider_config: |-
Ignoring provider config for validation...
name_invalid: |-
The sub-VM name '%{name}' is invalid. Please don't use special characters.
network_ip_ends_in_one: |-

View File

@ -5,13 +5,15 @@ describe VagrantPlugins::CommandValidate::Command do
include_context "unit"
include_context "command plugin helpers"
let(:vagrantfile_content){ "" }
let(:iso_env) do
isolated_environment
env = isolated_environment
env.vagrantfile(vagrantfile_content)
env.create_vagrant_env
end
let(:env) do
iso_env.create_vagrant_env
end
let(:action_runner) { double("action_runner") }
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
let(:argv) { [] }
@ -20,37 +22,49 @@ describe VagrantPlugins::CommandValidate::Command do
I18n.reload!
end
subject { described_class.new(argv, env) }
subject { described_class.new(argv, iso_env) }
describe "#execute" do
it "validates correct Vagrantfile" do
iso_env.vagrantfile(<<-EOH)
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
context "validating configs" do
let(:vagrantfile_content) do
<<-VF
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
end
VF
end
it "validates correct Vagrantfile" do
expect(machine).to receive(:action_raw) do |name, action, env|
expect(name).to eq(:config_validate)
expect(action).to eq(Vagrant::Action::Builtin::ConfigValidate)
expect(env).to eq({})
end
EOH
expect(iso_env.ui).to receive(:info).with(any_args) { |message, _|
expect(message).to include("Vagrantfile validated successfully.")
}
expect(env.ui).to receive(:info).with(any_args) { |message, _|
expect(message).to include("Vagrantfile validated successfully.")
}
expect(subject.execute).to eq(0)
expect(subject.execute).to eq(0)
end
end
it "validates the configuration" do
iso_env.vagrantfile <<-EOH
context "invalid configs" do
let(:vagrantfile_content) do
<<-VF
Vagrant.configure("2") do |config|
config.vm.bix = "hashicorp/precise64"
end
EOH
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
expect(err.message).to include("The following settings shouldn't exist: bix")
}
VF
end
it "validates the configuration" do
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
expect(err.message).to include("The following settings shouldn't exist: bix")
}
end
end
it "validates correct Vagrantfile of all vms" do
iso_env.vagrantfile <<-EOH
context "valid configs for multiple vms" do
let(:vagrantfile_content) do
<<-VF
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
@ -62,17 +76,25 @@ describe VagrantPlugins::CommandValidate::Command do
vm.vm.provider :virtualbox
end
end
EOH
VF
end
it "validates correct Vagrantfile of all vms" do
expect(machine).to receive(:action_raw) do |name, action, env|
expect(name).to eq(:config_validate)
expect(action).to eq(Vagrant::Action::Builtin::ConfigValidate)
expect(env).to eq({})
end
expect(iso_env.ui).to receive(:info).with(any_args) { |message, _|
expect(message).to include("Vagrantfile validated successfully.")
}
expect(env.ui).to receive(:info).with(any_args) { |message, _|
expect(message).to include("Vagrantfile validated successfully.")
}
expect(subject.execute).to eq(0)
expect(subject.execute).to eq(0)
end
end
it "validates the configuration of all vms" do
iso_env.vagrantfile <<-EOH
context "an invalid config for some vms" do
let(:vagrantfile_content) do
<<-VF
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
@ -84,15 +106,59 @@ describe VagrantPlugins::CommandValidate::Command do
vm.vm.not_provider :virtualbox
end
end
EOH
VF
end
it "validates the configuration of all vms" do
expect(machine).to receive(:action_raw) do |name, action, env|
expect(name).to eq(:config_validate)
expect(action).to eq(Vagrant::Action::Builtin::ConfigValidate)
expect(env).to eq({})
end
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
expect(err.message).to include("The following settings shouldn't exist: not_provider")
}
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
expect(err.message).to include("The following settings shouldn't exist: not_provider")
}
end
end
it "throws an exception if there's no Vagrantfile" do
expect { subject.execute }.to raise_error(Vagrant::Errors::NoEnvironmentError)
context "with the ignore provider flag" do
let(:argv) { ["--ignore-provider"]}
let(:vagrantfile_content) do
<<-VF
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.define "test" do |vm|
vm.vm.hostname = "test"
vm.vm.provider :virtualbox do |v|
v.not_a_real_option = true
end
end
end
VF
end
it "ignores provider specific configurations with the flag" do
expect(iso_env.ui).to receive(:info).with(any_args) { |message, _|
expect(message).to include("Vagrantfile validated successfully.")
}
expect(machine).to receive(:action_raw) do |name, action, env|
expect(name).to eq(:config_validate)
expect(action).to eq(Vagrant::Action::Builtin::ConfigValidate)
expect(env).to eq({:ignore_provider=>true})
end
expect(subject.execute).to eq(0)
end
end
context "no vagrantfile" do
let(:vagrantfile_content){ "" }
let(:env) { isolated_environment.create_vagrant_env }
subject { described_class.new(argv, env) }
it "throws an exception if there's no Vagrantfile" do
expect { subject.execute }.to raise_error(Vagrant::Errors::NoEnvironmentError)
end
end
end
end

View File

@ -368,6 +368,20 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
expect { subject.finalize! }.
to raise_error(Vagrant::Errors::VagrantfileLoadError)
end
it "ignores providers entirely if flag is provided" do
subject.provider "virtualbox" do |vb|
vb.nope = true
end
subject.provider "virtualbox" do |vb|
vb.not_real = "foo"
end
subject.finalize!
errors = subject.validate(machine, true)
expect(errors).to eq({"vm"=>[]})
end
end
describe "#provision" do

View File

@ -91,6 +91,24 @@ describe Vagrant::Config::V2::Root do
expect(instance.validate(env)).to eq(errors)
end
context "with vms and ignoring provider validations" do
let(:instance) do
map = { vm: Object, bar: Object }
described_class.new(map)
end
it "should pass along the ignore_provider flag for ignoring validations" do
errors = { "vm" => ["errors!"] }
env = { "errors" => errors }
vm = instance.vm
def vm.validate(env, param)
env["errors"]
end
expect(instance.validate({}, true)).to eq({})
end
end
it "should merge errors via array concat if matching keys" do
errors = { "foo" => ["errors!"] }
env = { "errors" => errors }