From 9a29d7be6bb7919b6c9bd20bf86a7eb6b1ec741f Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 29 Aug 2017 10:24:10 -0700 Subject: [PATCH 1/2] (#7836) Introduce salt_call_args option for salt provisioner This config option for the salt provisioner allows you to pass additional arguments to the salt-call executable. --- plugins/provisioners/salt/config.rb | 3 ++ plugins/provisioners/salt/provisioner.rb | 16 ++++++- .../provisioners/salt/provisioner_test.rb | 43 +++++++++++++++++++ website/source/docs/provisioning/salt.html.md | 2 + 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/plugins/provisioners/salt/config.rb b/plugins/provisioners/salt/config.rb index b42cfb00d..225888def 100644 --- a/plugins/provisioners/salt/config.rb +++ b/plugins/provisioners/salt/config.rb @@ -24,6 +24,7 @@ module VagrantPlugins attr_accessor :log_level attr_accessor :masterless attr_accessor :minion_id + attr_accessor :salt_call_args ## bootstrap options attr_accessor :temp_config_dir @@ -66,6 +67,7 @@ module VagrantPlugins @version = UNSET_VALUE @run_service = UNSET_VALUE @master_id = UNSET_VALUE + @salt_call_args = UNSET_VALUE end def finalize! @@ -91,6 +93,7 @@ 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 # NOTE: Optimistic defaults are set in the provisioner. UNSET_VALUEs # are converted there to allow proper detection of unset values. diff --git a/plugins/provisioners/salt/provisioner.rb b/plugins/provisioners/salt/provisioner.rb index deefa1428..b00cbb059 100644 --- a/plugins/provisioners/salt/provisioner.rb +++ b/plugins/provisioners/salt/provisioner.rb @@ -198,6 +198,18 @@ module VagrantPlugins return options 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 + end + # Copy master and minion configs to VM def upload_configs if @config.minion_config @@ -377,7 +389,7 @@ 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| + @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| if @config.verbose @machine.env.ui.info(data.rstrip) end @@ -386,7 +398,7 @@ 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| + @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| if @config.verbose @machine.env.ui.info(data.rstrip) end diff --git a/test/unit/plugins/provisioners/salt/provisioner_test.rb b/test/unit/plugins/provisioners/salt/provisioner_test.rb index b203ea332..5920478ff 100644 --- a/test/unit/plugins/provisioners/salt/provisioner_test.rb +++ b/test/unit/plugins/provisioners/salt/provisioner_test.rb @@ -32,4 +32,47 @@ describe VagrantPlugins::Salt::Provisioner do describe "#provision" do end + + describe "#call_highstate" do + 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_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(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..0bf1fe1f8 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. From 432cb8d915052165ed4986d18608c7ee5eaf4632 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Tue, 29 Aug 2017 12:57:49 -0700 Subject: [PATCH 2/2] (#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