diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb index b42cfb00d..2a8169312 100644 --- a/plugins/provisioners/salt/config.rb +++ b/plugins/provisioners/salt/config.rb @@ -24,6 +24,8 @@ module VagrantPlugins attr_accessor :log_level attr_accessor :masterless attr_accessor :minion_id + attr_accessor :salt_call_args + attr_accessor :salt_args ## bootstrap options attr_accessor :temp_config_dir @@ -66,6 +68,8 @@ module VagrantPlugins @version = UNSET_VALUE @run_service = UNSET_VALUE @master_id = UNSET_VALUE + @salt_call_args = UNSET_VALUE + @salt_args = UNSET_VALUE end def finalize! @@ -91,6 +95,8 @@ module VagrantPlugins @version = nil if @version == UNSET_VALUE @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. @@ -146,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 deefa1428..2f55099eb 100644 --- a/plugins/provisioners/salt/provisioner.rb +++ b/plugins/provisioners/salt/provisioner.rb @@ -198,6 +198,16 @@ 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 + " " + Array(@config.salt_call_args).join(" ") + end + # Copy master and minion configs to VM def upload_configs if @config.minion_config @@ -365,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 @@ -377,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}", 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 @@ -386,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}", 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 b203ea332..8ebf3b846 100644 --- a/test/unit/plugins/provisioners/salt/provisioner_test.rb +++ b/test/unit/plugins/provisioners/salt/provisioner_test.rb @@ -32,4 +32,89 @@ describe VagrantPlugins::Salt::Provisioner do describe "#provision" 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) + allow(config).to receive(:verbose).and_return(true) + allow(config).to receive(:masterless?).and_return(true) + allow(config).to receive(:masterless).and_return(true) + 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(: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) + 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 --output-dif", {: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(true) + allow(config).to receive(:masterless).and_return(true) + 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(: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}) + subject.call_highstate() + end + end + end + end diff --git a/website/source/docs/provisioning/salt.html.md b/website/source/docs/provisioning/salt.html.md index 1f3ea1e4e..c32c13924 100644 --- a/website/source/docs/provisioning/salt.html.md +++ b/website/source/docs/provisioning/salt.html.md @@ -94,6 +94,8 @@ public key * `masterless` (boolean) - Calls state.highstate in local mode. Uses `minion_id` and `pillar_data` when provided. +* `salt_call_args` (array) - An array of additional command line flag arguments to be passed to the `salt-call` command when provisioning with masterless. + ## Master Options These only make sense when `install_master` is `true`. Not supported on Windows guest machines. @@ -107,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