From 432cb8d915052165ed4986d18608c7ee5eaf4632 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 29 Aug 2017 12:57:49 -0700 Subject: [PATCH] (#7826) Add salt_arg option for passing flags to salt tool This commit introduces the salt_arg option that allows a user to pass additional command line flags to the `salt` tool when provisioning with a master setup. It also adds additional config validation to ensure that both `salt_args` and `salt_call_args` is an array. --- plugins/provisioners/salt/config.rb | 11 +++++ plugins/provisioners/salt/provisioner.rb | 23 +++++----- templates/locales/en.yml | 2 + .../plugins/provisioners/salt/config_test.rb | 36 +++++++++++++++ .../provisioners/salt/provisioner_test.rb | 44 ++++++++++++++++++- website/source/docs/provisioning/salt.html.md | 2 + 6 files changed, 106 insertions(+), 12 deletions(-) diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb index 225888def..2a8169312 100644 --- a/plugins/provisioners/salt/config.rb +++ b/plugins/provisioners/salt/config.rb @@ -25,6 +25,7 @@ module VagrantPlugins attr_accessor :masterless attr_accessor :minion_id attr_accessor :salt_call_args + attr_accessor :salt_args ## bootstrap options attr_accessor :temp_config_dir @@ -68,6 +69,7 @@ module VagrantPlugins @run_service = UNSET_VALUE @master_id = UNSET_VALUE @salt_call_args = UNSET_VALUE + @salt_args = UNSET_VALUE end def finalize! @@ -94,6 +96,7 @@ module VagrantPlugins @run_service = nil if @run_service == UNSET_VALUE @master_id = nil if @master_id == UNSET_VALUE @salt_call_args = nil if @salt_call_args == UNSET_VALUE + @salt_args = nil if @salt_args == UNSET_VALUE # NOTE: Optimistic defaults are set in the provisioner. UNSET_VALUEs # are converted there to allow proper detection of unset values. @@ -149,6 +152,14 @@ module VagrantPlugins errors << I18n.t("vagrant.provisioners.salt.must_accept_keys") end + if @salt_call_args && !@salt_call_args.is_a?(Array) + errors << I18n.t("vagrant.provisioners.salt.args_array") + end + + if @salt_args && !@salt_args.is_a?(Array) + errors << I18n.t("vagrant.provisioners.salt.args_array") + end + return {"salt provisioner" => errors} end end diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb index b00cbb059..2f55099eb 100644 --- a/plugins/provisioners/salt/provisioner.rb +++ b/plugins/provisioners/salt/provisioner.rb @@ -198,16 +198,14 @@ module VagrantPlugins return options end + # Append additional arguments to the salt command + def get_salt_args + " " + Array(@config.salt_args).join(" ") + end + # Append additional arguments to the salt-call command def get_call_args - options = "" - if @config.salt_call_args - @config.salt_call_args.each do |opt| - options += " #{opt}" - end - end - - return options + " " + Array(@config.salt_call_args).join(" ") end # Copy master and minion configs to VM @@ -377,7 +375,8 @@ module VagrantPlugins unless @config.masterless? @machine.communicate.sudo("salt '*' saltutil.sync_all") end - @machine.communicate.sudo("salt '*' state.highstate --verbose#{get_masterless}#{get_loglevel}#{get_colorize}#{get_pillar}", ssh_opts) do |type, data| + options = "#{get_masterless}#{get_loglevel}#{get_colorize}#{get_pillar}#{get_salt_args}" + @machine.communicate.sudo("salt '*' state.highstate --verbose#{options}", ssh_opts) do |type, data| if @config.verbose @machine.env.ui.info(data.rstrip) end @@ -389,7 +388,8 @@ module VagrantPlugins @machine.communicate.execute("C:\\salt\\salt-call.bat saltutil.sync_all", opts) end # TODO: something equivalent to { error_key: :ssh_bad_exit_status_muted }? - @machine.communicate.execute("C:\\salt\\salt-call.bat state.highstate --retcode-passthrough#{get_masterless}#{get_loglevel}#{get_colorize}#{get_pillar}#{get_call_args}", opts) do |type, data| + options = "#{get_masterless}#{get_loglevel}#{get_colorize}#{get_pillar}#{get_call_args}" + @machine.communicate.execute("C:\\salt\\salt-call.bat state.highstate --retcode-passthrough#{options}", opts) do |type, data| if @config.verbose @machine.env.ui.info(data.rstrip) end @@ -398,7 +398,8 @@ module VagrantPlugins unless @config.masterless? @machine.communicate.sudo("salt-call saltutil.sync_all") end - @machine.communicate.sudo("salt-call state.highstate --retcode-passthrough#{get_masterless}#{get_loglevel}#{get_colorize}#{get_pillar}#{get_call_args}", ssh_opts) do |type, data| + options = "#{get_masterless}#{get_loglevel}#{get_colorize}#{get_pillar}#{get_call_args}" + @machine.communicate.sudo("salt-call state.highstate --retcode-passthrough#{options}", ssh_opts) do |type, data| if @config.verbose @machine.env.ui.info(data.rstrip) end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index ccab103f5..f012557d9 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -2406,6 +2406,8 @@ en: You must include both public and private keys. must_accept_keys: |- You must accept keys when running highstate with master! + args_array: |- + You must set this value as an array. pushes: file: diff --git a/test/unit/plugins/provisioners/salt/config_test.rb b/test/unit/plugins/provisioners/salt/config_test.rb index 24bf24796..2571bdbb2 100644 --- a/test/unit/plugins/provisioners/salt/config_test.rb +++ b/test/unit/plugins/provisioners/salt/config_test.rb @@ -78,5 +78,41 @@ describe VagrantPlugins::Salt::Config do expect(result[error_key]).to be_empty end end + + context "salt_call_args" do + it "fails if salt_call_args is not an array" do + subject.salt_call_args = "--flags" + subject.finalize! + + result = subject.validate(machine) + expect(result[error_key]).to_not be_empty + end + + it "is valid if is set and not missing" do + subject.salt_call_args = ["--flags"] + subject.finalize! + + result = subject.validate(machine) + expect(result[error_key]).to be_empty + end + end + + context "salt_args" do + it "fails if not an array" do + subject.salt_args = "--flags" + subject.finalize! + + result = subject.validate(machine) + expect(result[error_key]).to_not be_empty + end + + it "is valid if is set and not missing" do + subject.salt_args = ["--flags"] + subject.finalize! + + result = subject.validate(machine) + expect(result[error_key]).to be_empty + end + end end end diff --git a/test/unit/plugins/provisioners/salt/provisioner_test.rb b/test/unit/plugins/provisioners/salt/provisioner_test.rb index 5920478ff..8ebf3b846 100644 --- a/test/unit/plugins/provisioners/salt/provisioner_test.rb +++ b/test/unit/plugins/provisioners/salt/provisioner_test.rb @@ -34,6 +34,46 @@ describe VagrantPlugins::Salt::Provisioner do end describe "#call_highstate" do + context "master" do + it "passes along extra cli flags" do + allow(config).to receive(:run_highstate).and_return(true) + allow(config).to receive(:verbose).and_return(true) + allow(config).to receive(:masterless?).and_return(false) + allow(config).to receive(:masterless).and_return(false) + allow(config).to receive(:minion_id).and_return(nil) + allow(config).to receive(:log_level).and_return(nil) + allow(config).to receive(:colorize).and_return(false) + allow(config).to receive(:pillar_data).and_return([]) + allow(config).to receive(:install_master).and_return(true) + + allow(config).to receive(:salt_args).and_return(["--async"]) + allow(machine.communicate).to receive(:sudo) + allow(machine.config.vm).to receive(:communicator).and_return(:notwinrm) + + expect(machine.communicate).to receive(:sudo).with("salt '*' state.highstate --verbose --log-level=debug --no-color --async", {:error_key=>:ssh_bad_exit_status_muted}) + subject.call_highstate() + end + + it "has no additional cli flags if not included" do + allow(config).to receive(:run_highstate).and_return(true) + allow(config).to receive(:verbose).and_return(true) + allow(config).to receive(:masterless?).and_return(false) + allow(config).to receive(:masterless).and_return(false) + allow(config).to receive(:minion_id).and_return(nil) + allow(config).to receive(:log_level).and_return(nil) + allow(config).to receive(:colorize).and_return(false) + allow(config).to receive(:pillar_data).and_return([]) + allow(config).to receive(:install_master).and_return(true) + + allow(config).to receive(:salt_args).and_return(nil) + allow(machine.communicate).to receive(:sudo) + allow(machine.config.vm).to receive(:communicator).and_return(:notwinrm) + + expect(machine.communicate).to receive(:sudo).with("salt '*' state.highstate --verbose --log-level=debug --no-color ", {:error_key=>:ssh_bad_exit_status_muted}) + subject.call_highstate() + end + end + context "with masterless" do it "passes along extra cli flags" do allow(config).to receive(:run_highstate).and_return(true) @@ -45,6 +85,7 @@ describe VagrantPlugins::Salt::Provisioner do allow(config).to receive(:colorize).and_return(false) allow(config).to receive(:pillar_data).and_return([]) + allow(config).to receive(:salt_args).and_return(["--async"]) allow(config).to receive(:salt_call_args).and_return(["--output-dif"]) allow(machine.communicate).to receive(:sudo) allow(machine.config.vm).to receive(:communicator).and_return(:notwinrm) @@ -65,11 +106,12 @@ describe VagrantPlugins::Salt::Provisioner do allow(config).to receive(:pillar_data).and_return([]) allow(config).to receive(:salt_call_args).and_return(nil) + allow(config).to receive(:salt_args).and_return(nil) allow(machine.communicate).to receive(:sudo) allow(machine.config.vm).to receive(:communicator).and_return(:notwinrm) allow(config).to receive(:install_master).and_return(false) - expect(machine.communicate).to receive(:sudo).with("salt-call state.highstate --retcode-passthrough --local --log-level=debug --no-color", {:error_key=>:ssh_bad_exit_status_muted}) + expect(machine.communicate).to receive(:sudo).with("salt-call state.highstate --retcode-passthrough --local --log-level=debug --no-color ", {:error_key=>:ssh_bad_exit_status_muted}) subject.call_highstate() end end diff --git a/website/source/docs/provisioning/salt.html.md b/website/source/docs/provisioning/salt.html.md index 0bf1fe1f8..c32c13924 100644 --- a/website/source/docs/provisioning/salt.html.md +++ b/website/source/docs/provisioning/salt.html.md @@ -109,6 +109,8 @@ These only make sense when `install_master` is `true`. Not supported on Windows * `seed_master` (dictionary) - Upload keys to master, thereby pre-seeding it before use. Example: `{minion_name:/path/to/key.pub}` +* `salt_args` (array) - An array of additional command line flag arguments to be passed to the `salt` command when provisioning with masterless. + ## Execute States Either of the following may be used to actually execute states