diff --git a/plugins/provisioners/shell/config.rb b/plugins/provisioners/shell/config.rb index 24021e9de..d5f260b91 100644 --- a/plugins/provisioners/shell/config.rb +++ b/plugins/provisioners/shell/config.rb @@ -5,6 +5,7 @@ module VagrantPlugins class Config < Vagrant.plugin("2", :config) attr_accessor :inline attr_accessor :path + attr_accessor :env attr_accessor :upload_path attr_accessor :args attr_accessor :privileged @@ -18,6 +19,7 @@ module VagrantPlugins @args = UNSET_VALUE @inline = UNSET_VALUE @path = UNSET_VALUE + @env = UNSET_VALUE @upload_path = UNSET_VALUE @privileged = UNSET_VALUE @binary = UNSET_VALUE @@ -31,6 +33,7 @@ module VagrantPlugins @args = nil if @args == UNSET_VALUE @inline = nil if @inline == UNSET_VALUE @path = nil if @path == UNSET_VALUE + @env = {} if @env == UNSET_VALUE @upload_path = "/tmp/vagrant-shell" if @upload_path == UNSET_VALUE @privileged = true if @privileged == UNSET_VALUE @binary = false if @binary == UNSET_VALUE @@ -72,6 +75,10 @@ module VagrantPlugins end end + if !env.is_a?(Hash) + errors << I18n.t("vagrant.provisioners.shell.env_must_be_a_hash") + end + # There needs to be a path to upload the script to if !upload_path errors << I18n.t("vagrant.provisioners.shell.upload_path_not_set") diff --git a/plugins/provisioners/shell/provisioner.rb b/plugins/provisioners/shell/provisioner.rb index 6899f11da..a04d80c92 100644 --- a/plugins/provisioners/shell/provisioner.rb +++ b/plugins/provisioners/shell/provisioner.rb @@ -47,7 +47,12 @@ module VagrantPlugins # This is the provision method called if SSH is what is running # on the remote end, which assumes a POSIX-style host. def provision_ssh(args) - command = "chmod +x #{config.upload_path} && #{config.upload_path}#{args}" + env = config.env.map { |k,v| "#{k}=#{quote_and_escape(v)}" }.join(" ") + + command = "chmod +x '#{config.upload_path}'" + command << " &&" + command << " #{env}" if !env.empty? + command << " #{config.upload_path}#{args}" with_script_file do |path| # Upload the script to the machine @@ -107,6 +112,9 @@ module VagrantPlugins # Upload it comm.upload(path.to_s, upload_path) + # Build the environment + env = config.env.map { |k,v| "$env:#{k} = #{quote_and_escape(v)}" }.join("; ") + # Calculate the path that we'll be executing exec_path = upload_path exec_path.gsub!('/', '\\') @@ -125,6 +133,11 @@ module VagrantPlugins command = "powershell #{shell_args.to_s} -file #{command}" if File.extname(exec_path).downcase == '.ps1' + # Append the environment + if !env.empty? + command = "#{env}; #{command}" + end + if config.name @machine.ui.detail(I18n.t("vagrant.provisioners.shell.running", script: "script: #{config.name}")) diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 0b93f9c79..2720e9cf4 100755 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -2054,6 +2054,8 @@ en: invalid_encoding: |- Invalid encoding '%{actual}' for script at '%{path}'. Must be '%{default}' or UTF-8. + env_must_be_a_hash: |- + The shell provisioner's `env' option must be a hash. no_path_or_inline: "One of `path` or `inline` must be set." path_and_inline_set: "Only one of `path` or `inline` may be set." path_invalid: "`path` for shell provisioner does not exist on the host system: %{path}" diff --git a/test/unit/plugins/provisioners/shell/config_test.rb b/test/unit/plugins/provisioners/shell/config_test.rb index c0f04dd2f..c4d260b90 100644 --- a/test/unit/plugins/provisioners/shell/config_test.rb +++ b/test/unit/plugins/provisioners/shell/config_test.rb @@ -98,6 +98,17 @@ describe "VagrantPlugins::Shell::Config" do I18n.t("vagrant.provisioners.shell.interactive_not_elevated") ]) end + + it "returns an error if the environment is not a hash" do + subject.env = "foo" + subject.finalize! + + result = subject.validate(machine) + + expect(result["shell provisioner"]).to include( + I18n.t("vagrant.provisioners.shell.env_must_be_a_hash") + ) + end end describe 'finalize!' do diff --git a/test/unit/plugins/provisioners/shell/provisioner_test.rb b/test/unit/plugins/provisioners/shell/provisioner_test.rb index 8c9201717..8f83f2554 100644 --- a/test/unit/plugins/provisioners/shell/provisioner_test.rb +++ b/test/unit/plugins/provisioners/shell/provisioner_test.rb @@ -16,6 +16,7 @@ describe "Vagrant::Shell::Provisioner" do double( :config, :args => "doesn't matter", + :env => {}, :upload_path => "arbitrary", :remote? => false, :path => nil, diff --git a/website/docs/source/v2/provisioning/shell.html.md b/website/docs/source/v2/provisioning/shell.html.md index d5b0d6174..eaee7779c 100644 --- a/website/docs/source/v2/provisioning/shell.html.md +++ b/website/docs/source/v2/provisioning/shell.html.md @@ -39,6 +39,10 @@ The remainder of the available options are optional: etc. as needed. You may also pass the arguments in using an array. In this case, Vagrant will handle quoting for you. +* `env` (hash) - List of key-value pairs to pass in as environment variables to + the script. Vagrant will handle quoting for environment variable values, but + the keys remain untouched. + * `binary` (boolean) - Vagrant automatically replaces Windows line endings with Unix line endings. If this is true, then Vagrant will not do this. By default this is "false". If the shell provisioner is communicating over WinRM, this