将环境变量传递给流浪 shell 提供程序

如果使用 Ruby 供应商,调用 vagrant up时传递环境变量看起来很简单:

VAR=123 vagrant up

在流浪汉档案里:

ENV['VAR']

我如何与 :shell供应商做到这一点? 简单地这样做似乎行不通:

$VAR
74138 次浏览

It's not ideal, but I got this to work for now:

config.vm.provision "shell" do |s|
s.inline = "VAR1 is $1 and VAR2 is $2"
s.args   = "#{ENV['VAR1']} #{ENV['VAR2']}"
end

Incase someone ends up looking for how to set variables in the provisioning script's environment, this worked for me.

config.vm.provision :shell, :inline => <<-SH
export GRAPHITE_HOST=192.168.33.10
/vagrant/install_app_with_monitoring.sh
SH

Note that this assumes you're sharing your working directory as /vagrant on the VM but this should be the default.

I came with this solution for CentOS based provisioning: placing all my required envioronment variables in /etc/profile.d/vagrant.sh file and then it's accessed in any provision script.

in short:

  $before_script = <<SCRIPT
echo # vagrant profile script > /etc/profile.d/vagrant.sh
echo export ENV_VAR1=foo.com/bar >> /etc/profile.d/vagrant.sh
echo export ENV_VAR2=bar.com/foo >> /etc/profile.d/vagrant.sh
chmod +x /etc/profile.d/vagrant.sh
SCRIPT


$after_script = <<SCRIPT
rm -rf /etc/profile.d/vagrant.sh
SCRIPT


config.vm.provision "shell", inline: $before_script
config.vm.provision "shell", path: "build.sh"
config.vm.provision "shell", inline: $after_script

Complete Vagrantfile can be found here https://gist.github.com/bivas/6192d6e422f8ff87c29d

this worked for me

VAGRANTFILE_API_VERSION = "2"


kettle_dir = ENV['KETTLE_DIR']
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.synced_folder kettle_dir, "/pentaho"
config.vm.box = "ubuntu/trusty64"
end

Here's how I have it working.

I went from using the vagrant puppet provisioner way to just using the shell provisioner. I did this mainly because I wanted to puppet not to run as root, shell provider gives you :privileged => false.

MY OLD WAY:

config.vm.provision :puppet do |puppet|
puppet.module_path = ENV.fetch('MODULES_PATH', 'modules')
puppet.manifests_path = ENV.fetch('MANIFESTS_PATH', 'manifests')
puppet.manifest_file  = ENV.fetch('MANIFEST_FILE', 'site.pp')
puppet.options = "--debug"
end

MY NEW WAY:

config.vm.provision :shell, :privileged => false do |shell|
shell.inline = "puppet apply --debug --modulepath '/vagrant/#{ENV.fetch('MODULES_PATH', 'modules')}' --detailed-exitcodes '/vagrant/#{ENV.fetch('MANIFESTS_PATH', 'manifests')}/#{ENV.fetch('MANIFEST_FILE', 'site.pp')}'"
end

You can use #{ENV['VAR']} inside an inline script, e.g.:

config.vm.provision "shell", inline: <<-END
...
# Install my dotfiles are there.  If you're in a hurry you can do
# SKIP_DOTFILES=1 vagrant up
if ! [ -d /home/vagrant/dotfiles ] && [ -z '#{ENV['SKIP_DOTFILES']}']; then
if ! [ -x /usr/bin/git ]; then
DEBIAN_FRONTEND=noninteractive apt-get install -y git
fi
su - vagrant -c 'git clone https://github.com/mgedmin/dotfiles'
su - vagrant -c 'dotfiles/install.sh'
fi
...
END

Example taken from a working Vagrantfile.

This has some disadvantages: if $VAR contains single quotes, things will break.

You can specify for shell using inlinein your Vagrantfile file:

config.vm.provision "shell", inline: %Q(/usr/bin/env FOO=1 BAR=1 bash /path/to/script.sh)

Or load some extra variables from YAML file:

require 'yaml'
dir = File.dirname(File.expand_path(__FILE__))
vconfig = YAML::load_file("#{dir}/config.yml")
config.vm.provision "shell", inline: %Q(/usr/bin/env FOO=#{vconfig['foo']} bash /path/to/script.sh)

Alternatively you may implement some optional arguments from the command line, e.g.:

# Parse optional arguments.
opts = GetoptLong.new(
[ '--foo',  GetoptLong::OPTIONAL_ARGUMENT ], # With optional parameter.
[ '--bar',  GetoptLong::OPTIONAL_ARGUMENT ], # With optional parameter.files.
)
opts.each do |opt, arg|
case opt
when '--foo'
foo==arg
when '--bar'
bar=arg
end
end

then use: opt['--foo'].to_s.

See also: How to pass parameter on Vagrant up and have it in the scope of Chef cookbook?

The vagrant-env plugin does exactly this. With it, you can add environment variables to .env file in the local directory which will be loaded in Vagrant file. I suggest to keep .env in your .gitignore, this way you have your privacy guaranteed.

Since Vagrant 1.8.0 you can forget the ugly hacks from the other answers here. Just use the env option for the shell provisioner (docs).

Use it like this in your Vagrantfile:

config.vm.provision "shell", path: "provisionscript.sh", env: {"MYVAR" => "value"}

This will set the environment for the provisioning script only. If you need a persistent environment variable set for all processes in the VM, this is out of scope for Vagrant provisioning and look here: Shell environment variables in vagrant files are only passed on first up.

For posterity (aka in case I google it again)... It's possible to pass key-value pairs via env:

box.vm.provision :shell do |s|
s.env = {AWS_ACCESS_KEY:ENV['AWS_ACCESS_KEY'], AWS_SECRET_KEY:ENV['AWS_SECRET_KEY']}
s.path = 'scripts/bootstrap.sh'
end

Then reference them in your script:

export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY}
export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_KEY}

Bonus feature:

Vagrant will handle quoting for environment variable values, but the keys remain untouched

On a ubutnu box I simply did the following in my bootstrap.sh:

echo "DBHOST=localhost" >> /etc/environment
echo "DBNAME=foo" >> /etc/environment
echo "DBUSER=root" >> /etc/environment
echo "DBPASSWD=root" >> /etc/environment

Most of these answers seems to be outdated. With Vagrant 2.1.1 this worked for me:

  VAGRANTFILE_API_VERSION = "2" //...


machine.vm.provision "shell",
env: {
"ELASTIC_XMS" => servers["elastic"]["memory_xms"],
"ELASTIC_XMX" => servers["elastic"]["memory_xmx"]
},
inline: "sed -i -e \"s/-Xms.*/$ELASTIC_XMS/g\" /etc/elasticsearch/jvm.options"