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:
parent
716a5f1501
commit
6051f3598e
|
@ -12,7 +12,7 @@ module Vagrant
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
if !env.key?(:config_validate) || env[:config_validate]
|
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?
|
if errors && !errors.empty?
|
||||||
raise Errors::ConfigInvalid,
|
raise Errors::ConfigInvalid,
|
||||||
|
|
|
@ -60,14 +60,18 @@ module Vagrant
|
||||||
#
|
#
|
||||||
# @param [Environment] env
|
# @param [Environment] env
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def validate(machine)
|
def validate(machine, ignore_provider=nil)
|
||||||
# Go through each of the configuration keys and validate
|
# Go through each of the configuration keys and validate
|
||||||
errors = {}
|
errors = {}
|
||||||
@keys.each do |_key, instance|
|
@keys.each do |_key, instance|
|
||||||
if instance.respond_to?(:validate)
|
if instance.respond_to?(:validate)
|
||||||
# Validate this single item, and if we have errors then
|
# Validate this single item, and if we have errors then
|
||||||
# we merge them into our total errors list.
|
# 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?
|
if result && !result.empty?
|
||||||
errors = Util.merge_errors(errors, result)
|
errors = Util.merge_errors(errors, result)
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,17 +8,32 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
opts = OptionParser.new do |o|
|
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
|
end
|
||||||
|
|
||||||
# Parse the options
|
# Parse the options
|
||||||
argv = parse_options(opts)
|
argv = parse_options(opts)
|
||||||
return if !argv
|
return if !argv
|
||||||
|
|
||||||
|
action_env = {}
|
||||||
|
if options[:ignore_provider]
|
||||||
|
action_env[:ignore_provider] = true
|
||||||
|
end
|
||||||
# Validate the configuration of all machines
|
# Validate the configuration of all machines
|
||||||
with_target_vms() do |machine|
|
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
|
end
|
||||||
|
|
||||||
@env.ui.info(I18n.t("vagrant.commands.validate.success"))
|
@env.ui.info(I18n.t("vagrant.commands.validate.success"))
|
||||||
|
|
|
@ -582,7 +582,7 @@ module VagrantPlugins
|
||||||
@__synced_folders
|
@__synced_folders
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate(machine)
|
def validate(machine, ignore_provider=nil)
|
||||||
errors = _detected_errors
|
errors = _detected_errors
|
||||||
|
|
||||||
if !box && !clone && !machine.provider_options[:box_optional]
|
if !box && !clone && !machine.provider_options[:box_optional]
|
||||||
|
@ -737,9 +737,13 @@ module VagrantPlugins
|
||||||
|
|
||||||
# Validate only the _active_ provider
|
# Validate only the _active_ provider
|
||||||
if machine.provider_config
|
if machine.provider_config
|
||||||
provider_errors = machine.provider_config.validate(machine)
|
if !ignore_provider
|
||||||
if provider_errors
|
provider_errors = machine.provider_config.validate(machine)
|
||||||
errors = Vagrant::Config::V2::Util.merge_errors(errors, provider_errors)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1845,6 +1845,8 @@ en:
|
||||||
hostname_invalid_characters: |-
|
hostname_invalid_characters: |-
|
||||||
The hostname set for the VM should only contain letters, numbers,
|
The hostname set for the VM should only contain letters, numbers,
|
||||||
hyphens or dots. It cannot start with a hyphen or dot.
|
hyphens or dots. It cannot start with a hyphen or dot.
|
||||||
|
ignore_provider_config: |-
|
||||||
|
Ignoring provider config for validation...
|
||||||
name_invalid: |-
|
name_invalid: |-
|
||||||
The sub-VM name '%{name}' is invalid. Please don't use special characters.
|
The sub-VM name '%{name}' is invalid. Please don't use special characters.
|
||||||
network_ip_ends_in_one: |-
|
network_ip_ends_in_one: |-
|
||||||
|
|
|
@ -5,13 +5,15 @@ describe VagrantPlugins::CommandValidate::Command do
|
||||||
include_context "unit"
|
include_context "unit"
|
||||||
include_context "command plugin helpers"
|
include_context "command plugin helpers"
|
||||||
|
|
||||||
|
let(:vagrantfile_content){ "" }
|
||||||
let(:iso_env) do
|
let(:iso_env) do
|
||||||
isolated_environment
|
env = isolated_environment
|
||||||
|
env.vagrantfile(vagrantfile_content)
|
||||||
|
env.create_vagrant_env
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:env) do
|
let(:action_runner) { double("action_runner") }
|
||||||
iso_env.create_vagrant_env
|
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
|
||||||
end
|
|
||||||
|
|
||||||
let(:argv) { [] }
|
let(:argv) { [] }
|
||||||
|
|
||||||
|
@ -20,37 +22,49 @@ describe VagrantPlugins::CommandValidate::Command do
|
||||||
I18n.reload!
|
I18n.reload!
|
||||||
end
|
end
|
||||||
|
|
||||||
subject { described_class.new(argv, env) }
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
describe "#execute" do
|
describe "#execute" do
|
||||||
it "validates correct Vagrantfile" do
|
context "validating configs" do
|
||||||
iso_env.vagrantfile(<<-EOH)
|
let(:vagrantfile_content) do
|
||||||
Vagrant.configure("2") do |config|
|
<<-VF
|
||||||
config.vm.box = "hashicorp/precise64"
|
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
|
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(subject.execute).to eq(0)
|
||||||
expect(message).to include("Vagrantfile validated successfully.")
|
end
|
||||||
}
|
|
||||||
|
|
||||||
expect(subject.execute).to eq(0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "validates the configuration" do
|
context "invalid configs" do
|
||||||
iso_env.vagrantfile <<-EOH
|
let(:vagrantfile_content) do
|
||||||
|
<<-VF
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.bix = "hashicorp/precise64"
|
config.vm.bix = "hashicorp/precise64"
|
||||||
end
|
end
|
||||||
EOH
|
VF
|
||||||
|
end
|
||||||
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
|
it "validates the configuration" do
|
||||||
expect(err.message).to include("The following settings shouldn't exist: bix")
|
expect { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
|
||||||
}
|
expect(err.message).to include("The following settings shouldn't exist: bix")
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "validates correct Vagrantfile of all vms" do
|
context "valid configs for multiple vms" do
|
||||||
iso_env.vagrantfile <<-EOH
|
let(:vagrantfile_content) do
|
||||||
|
<<-VF
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.box = "hashicorp/precise64"
|
config.vm.box = "hashicorp/precise64"
|
||||||
|
|
||||||
|
@ -62,17 +76,25 @@ describe VagrantPlugins::CommandValidate::Command do
|
||||||
vm.vm.provider :virtualbox
|
vm.vm.provider :virtualbox
|
||||||
end
|
end
|
||||||
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(subject.execute).to eq(0)
|
||||||
expect(message).to include("Vagrantfile validated successfully.")
|
end
|
||||||
}
|
|
||||||
|
|
||||||
expect(subject.execute).to eq(0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "validates the configuration of all vms" do
|
context "an invalid config for some vms" do
|
||||||
iso_env.vagrantfile <<-EOH
|
let(:vagrantfile_content) do
|
||||||
|
<<-VF
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.box = "hashicorp/precise64"
|
config.vm.box = "hashicorp/precise64"
|
||||||
|
|
||||||
|
@ -84,15 +106,59 @@ describe VagrantPlugins::CommandValidate::Command do
|
||||||
vm.vm.not_provider :virtualbox
|
vm.vm.not_provider :virtualbox
|
||||||
end
|
end
|
||||||
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 { subject.execute }.to raise_error(Vagrant::Errors::ConfigInvalid) { |err|
|
||||||
expect(err.message).to include("The following settings shouldn't exist: not_provider")
|
expect(err.message).to include("The following settings shouldn't exist: not_provider")
|
||||||
}
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "throws an exception if there's no Vagrantfile" do
|
context "with the ignore provider flag" do
|
||||||
expect { subject.execute }.to raise_error(Vagrant::Errors::NoEnvironmentError)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -368,6 +368,20 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
|
||||||
expect { subject.finalize! }.
|
expect { subject.finalize! }.
|
||||||
to raise_error(Vagrant::Errors::VagrantfileLoadError)
|
to raise_error(Vagrant::Errors::VagrantfileLoadError)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe "#provision" do
|
describe "#provision" do
|
||||||
|
|
|
@ -91,6 +91,24 @@ describe Vagrant::Config::V2::Root do
|
||||||
expect(instance.validate(env)).to eq(errors)
|
expect(instance.validate(env)).to eq(errors)
|
||||||
end
|
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
|
it "should merge errors via array concat if matching keys" do
|
||||||
errors = { "foo" => ["errors!"] }
|
errors = { "foo" => ["errors!"] }
|
||||||
env = { "errors" => errors }
|
env = { "errors" => errors }
|
||||||
|
|
Loading…
Reference in New Issue