Create linux environment variable using vagrant provisioner - vagrant

I've got vagrant running Ubuntu for development purposes. I've used a shell script provisioner to download/install my dependencies and create some aliases, but I've hit a wall in terms of using the provisioner to create environment variables (which are used for several flags within my project). Originally I had something like:
export MY_VAR='value'
Into my provisioner script, but then found out that you can't add environment variables from inside a shell script by running it normally. Fair enough, so I tried instead changing my line of the Vagrantfile to:
config.vm.provision "shell", inline: “source setup.sh"
Which didn't solve the problem. Environment variables still weren't there. I tried adding the exports directly as an inline:
config.vm.provision "shell", inline: “export MY_VAR='value'"
No luck. Still no global environment when I ssh'ed in. Is there a way to use the shell script to set a bash environment variable, or is it time to throw in the towel on shell provisioners and learn chef?

You should have the provisioning script add a line to your .profile:
echo "export VAR=value" >> ~/.profile
On login, the .profile script will be read by bash and the variable will be set.

Seeing as the accepted answer does indeed add an export VAR=value to your .profile (or .bashrc) file each time you run vagrant provision, here's how I've added environment variables quickly
source ~/.profile && [ -z "$VAR" ] && echo "export VAR=value" >> ~/.profile
Breakdown:
source ~/.profile: load the current .profile file
[ -z "$VAR"]: check whether or not VAR is set, if not:
echo "export VAR=value" >> ~/.profile: add the export line to .profile
Putting it all together:
I normally use puphpet for my vagrant boxes, so I tend to stick to the directory structure it uses, which means putting my provisioning script in puphpet/shell/* (relative to the Vagrantfile file). In that file, you can add as many environment variables as you like:
#!/usr/bin/env bash
#Replace .profile with .bashrc if required
source ~/.profile
if [ -z "$VAR" ]; then # only checks if VAR is set, regardless of its value
echo "export VAR=value" >> ~/.profile
fi
#other env variables and profile stuff here
If you want to set the environment variables to a specific value, even if they're set, you can replace [ -z "$VAR" ] with this (As Maks3w suggested):
if [ -z "$VAR" ] || [ "$VAR" != "value" ]; then
#same as before
fi
Then simply add this to your Vagrantfile:
config.vm.provision "shell", path: "puphpet/shell/your-script.sh"
That ought to do the trick...

Here's how I got $GOPATH working:
config.vm.provision "shell", inline: <<-SHELL
echo -n > /etc/profile.d/gopath.sh
echo 'export GOPATH=$HOME/go' >> /etc/profile.d/gopath.sh
echo 'export PATH=$PATH:$GOPATH/bin' >> /etc/profile.d/gopath.sh
SHELL
The use of single quotes and $HOME (instead of ~) were necessary---I couldn't make it work otherwise.

This answer shows how to add environment variables just modifying VagrantFile using Ruby HEREDOC (Here doc) syntax
$install_user_vars = <<SCRIPT
source ~/.profile
if [ -z "$VAR" ] || [ "$VAR" != "value" ]; then
echo "export VAR=value" >> ~/.profile
fi
if [ $(pwd) != "/vagrant" ]; then
echo "cd /vagrant" >> ~/.profile
fi
SCRIPT
config.vm.provision "shell", inline: $install_user_vars
Note: The close SCRIPT must be the first character in his own line

I was looking for the same thing. I wanted to set http(s)_proxy environment variables in Vagrantfile. The requirement was that I can change these variables at any time and vagrant reload to apply them.
Finally, I came up with the solution:
config.vm.provision "shell", inline: "> /etc/profile.d/myvars.sh", run: "always"
config.vm.provision "shell", inline: "echo \"export http_proxy=http://proxy.somedomain.com:3128\" >> /etc/profile.d/myvars.sh", run: "always"
config.vm.provision "shell", inline: "echo \"export https_proxy=https://proxy.somedomain.com:3128\" >> /etc/profile.d/myvars.sh", run: "always"
0) /etc/profile.d/*.sh scripts are run at the startup of the bash shell
1) removes everything from myvars.sh
2) sets the first variable
3) sets the second variable
Because of run: "always" I can add/remove variables and after vagrant reload they are applied.

In CentOs7 you need to place env vars under /etc/profile.d/
This worked in my case:
machine.vm.provision 'shell',
inline: 'sudo su - && echo "export VAR1=test export VAR2=test" > /etc/profile.d/vars.sh'

Related

Save environmental variables in vagrant

I have CentOS7 set up via vagrant and when I export $MYVAR=test I can successfully echo $MYVAR. The problem arises when I close the vagrant session and have to ssh back in, this variable gets wiped and I have to reset it every time.
Is there a workaround for this? Possibly in the .vagrantfile?
The easiest is to add your export line in your ~/.profile file so it will always be available when you start a new session
You can try adding following to your provisioning script.
echo "export MYVAR=test" >> ~/.profile
On Vagrantfile, It will look like:
config.vm.provision "shell", inline: <<-SHELL
echo "export MYVAR=test" >> ~/.profile
SHELL

why doesn't vagrant provisioner modify ~/.bashrc?

How can I make the Vagrantfile append the contents of a file to the ~/.bashrc file ?
In my Vagrantfile, I am trying to append the contents of a file /vagrant/dev_env_config to the ~/.bashrc file.
When I run vagrant up it outputs the echo statement AND it outputs the expected contents of the ~/.bashrc file.... so I know it's reading the file dev_env_config and APPEARS to be appending it.
However, when I then run vagrant ssh and then cat ~/.bashrc the ~/.bashrc file is unmodified, it's the default ~/.bashrc file
In other words the mods to ~/.bashrc file are lost somewhere between when the vagrant provison runs and when I run vagrant ssh
# Vagrantfile
Vagrant.configure("2") do |config|
... various cmds to set box and network...
$install_user_vars = <<SCRIPT
sudo cat /vagrant/dev_env_config >> ~/.bashrc
echo "*** here is the .bashrc file:"
cat ~/.bashrc
SCRIPT
config.vm.provision "shell", inline: $install_user_vars
end
I think what's happening is the provisioning script is run as root (or sudo), so the "~" home location is actually /root rather than the default user home location /home/vagrant.
I can think of a couple ways to solve this:
First (and probably easiest) is to be explicit about the .bashrc path, like:
# Vagrantfile
Vagrant.configure("2") do |config|
... various cmds to set box and network...
$install_user_vars = <<SCRIPT
sudo cat /vagrant/dev_env_config >> /home/vagrant/.bashrc
echo "*** here is the .bashrc file:"
cat /home/vagrant/.bashrc
SCRIPT
config.vm.provision "shell", inline: $install_user_vars
end
The second option could be to run this part of the provisioning script as a non-privileged user. See the 'privileged' option on the Shell Scripts docs page.
A primitive solution is to set the path to .bashrc explicitly. As a rule default username of a SSH user (which will be used for vagrant ssh action) is vagrant so:
$install_user_vars = <<SCRIPT
sudo cat /vagrant/dev_env_config >> /home/vagrant/.bashrc
echo "*** here is the .bashrc file:"
cat /home/vagrant/.bashrc
SCRIPT
Also I'm not sure that it's a necessary to use a sudo command (in sudo cat ...). Probably you don't need it, but it depends on which user is used to run a provision script. I guess it's also vagrant.
So if it's really a vagrant you could leave the path to .bashrc unmodified (~/.bashrc), but have to remove sudo cat ... command and use simple cat ... instead. And it's a more clean solution in my opinion. Because actually we shouldn't use sudo (root) permissions without need.

Why is `source /home/vagrant/.bashrc` not working in a Vagrant shell provisioning script?

I'm having problems with a shell provisioning script used by Vagrant, as it's not executing source /home/vagrant/.bashrc. I've reduced the problem down to this...
Within my VM I have a file at /home/vagrant/testfile that contains this:
echo "In testfile"
And at the end of /home/vagrant/.bashrc I have this:
echo "In .bashrc"
Both files are owned by the vagrant user.
In one of my Vagrant provisioning shell scripts I have this:
echo "Hello"
source /home/vagrant/testfile
source /home/vagrant/.bashrc
echo "Goodbye"
Running vagrant provision gives this:
Hello
In testfile
Goodbye
When I do vagrant ssh then /home/vagrant/.bashrc is run as usual, and I automatically see:
In .bashrc
So why does doing source /home/vagrant/.bashrc have no effect from within my provisioning script?
You need to remove the “exit if not running interactively” bit (e.g. [ -z "$PS1" ] && return) from the top of your .bashrc.

Updating path in Vagrant using shell provisioning

I am using Vagrant to deploy a virtual machine with several installed packages using shell provisioning. One of the packages needs an update of path to be used properly which I wasn't able to do.
These are the contents of my Vagrantfile:
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
#config.vm.network "forwarded_port", guest: 8888, host: 8888
config.ssh.forward_agent = true
config.vm.provision "shell", path: "provision.sh"
end
These are the following things I tried:
Create a separate .bashrc and .profile files with the following commands (appended at the end of file) and copy them into home directory:
export PATH="/usr/local/x86_64/bin:$PATH"
Try to write into .profile file:
echo 'export PATH="/usr/local/x86_64/bin:$PATH"' >> .profile
Just try exporting PATH during the provisioning (i.e. as a line of code in the provision.sh):
export PATH="/usr/local/x86_64/bin:$PATH"
After vagrant up command finishes, this command does enable the change of path following vagrant ssh.
The problem was resolved with the following added to the provision.sh file based on this post:
echo PATH $PATH
[ -f ~/.profile ] || touch ~/.profile
[ -f ~/.bash_profile ] || touch ~/.bash_profile
grep 'PATH=/usr/local/x86_64/bin' ~/.profile || echo 'export PATH=/usr/local/x86_64/bin:$PATH' | tee -a ~/.profile
grep 'PATH=/usr/local/x86_64/bin' ~/.bash_profile || echo 'export PATH=/usr/local/x86_64/bin:$PATH' | tee -a ~/.bash_profile
. ~/.profile
. ~/.bash_profile
echo PATH $PATH
This works for the precise 64 box all the commands should be one line.
Example using Ex/vi editor:
ex +'$s#$#\rexport PATH=/var/lib/vendor/bin:$PATH#' -cwq /etc/bash.bashrc
which appends:
export PATH=/var/lib/vendor/bin:$PATH
into global /etc/bash.bashrc file (so it's available for all users using bash shell, or use /etc/profile to use for all Bourne shells).
Alternatively use simply cat, e.g.:
cat >> ~/.bashrc <<EOF
export PATH=~/.composer/vendor/bin:\$PATH
EOF
If you need to have access to newly tool straight away, then you need to source the file.
If you're using composer, you may consider installing the binaries by specifying the requirements in composer.json, see some examples here, so in this case, you don't have to worry about configuring PATH variable.
If you're using Ansible playbooks, you can try using Files Modules with the following rule in yml file:
- name: Update bashrc to add new PATH entry:
dest=/home/vagrant/.bashrc
line="export PATH='/usr/local/x86_64/bin:$PATH'"
regexp="^export PATH"
owner=vagrant
state=present
insertafter=EOF
create=True

Automatically chdir to vagrant directory upon "vagrant ssh"

So, I've got a bunch of vagrant VMs running some flavor of Linux (centos, ubuntu, whatever). I would like to automatically ensure that a "vagrant ssh" will also "cd /vagrant" so that no-one has to remember to do that whenever they log in.
I've figured out (duh!) that echo "\n\ncd /vagrant" >> /home/vagrant/.bashrc will do the trick. What I don't know is how to ensure that this only happens if the cd command isn't already there. I'm not a shell expert, so I'm completely confused here. :)
You can do this by using the config.ssh.extra_args setting in your Vagrantfile:
config.ssh.extra_args = ["-t", "cd /vagrant; bash --login"]
Then anytime you run vagrant ssh you will be in the /vagrant directory.
I put
echo "cd /vagrant_projects/my-project" >> /home/vagrant/.bashrc
in my provision.sh, and it works like a charm.
cd is a Bash shell built-in, as long as a shell is installed it should be there.
Also, be aware that ~/.bash_profile is for interactive login shell, if you add cd /vagrant in ~vagrant/.bashrc, it may NOT work.
Because distros like Ubuntu does NOT have this file -> ~/.bash_profile by default and instead use ~/.bashrc and ~/.profile
If someone creates a ~/.bash_profile for vagrant user on Ubuntu, ~vagrant/.bashrc will not be read.
You need to add cd /vagrant to your .bashrc in the vm. The best way to do this is in your provisioner script.
If you don't have a provisioner script, make one by adding this line to your Vagrantfile before end:
config.vm.provision "shell", path: "scripts/vagrant/provisioner.sh", privileged: false
Path is relative to the project root where the Vagrantfile is, and privileged depends on your project and what else is in your provisioner script which might need to be privileged. I use priveleged false and sudo explicitly when necessary.
And in the provisioner script:
if ! grep -q "cd /vagrant" ~/.bashrc ; then
echo "cd /vagrant" >> ~/.bashrc
fi
This will add cd /vagrant to .bashrc, but only if it isn't there already. This is useful if you reprovision, as it will prevent your .bashrc from getting cluttered.
Some answers mention a conflict with .bash_profile. If the above code doesn't work, you can try the same line with .bash_profile or .profile instead of .bashrc. However, I've been using vagrant with ubuntu guests. My Laravel/homestead box based on Ubuntu has a .bash_profile and a .profile but having cd /vagrant in .bashrc did work for me when using vagrant ssh without changing or deleting the other files.
You can add cd /vagrant to your .bashrc and it will run the command when you ssh. The /bashrc you want is in /home/vagrant (the user you login as when you vagrant ssh.) You can just stick the new line at the bottom of the file.
You can also do it this way:
vagrant ssh -c "cd /vagrant && bash"
And you could include it in a script to launch it (like ./vagrant-ssh).
May be this can help. Edit the Vagrantfile as replace your username with vagrant
`
config.vm.provision "shell" do |s|
s.inline = <<-SHELL
# Change directory automatically on ssh login
if ! grep -qF "cd /home/vagrant/ansible" /home/vagrant/.bashrc ;
then echo "cd /home/vagrant/ansible" >> /home/vagrant/.bashrc ; fi
chown vagrant. /home/vagrant/.bashrc
`
Ideally we just want to alter the vagrant ssh behaviour.
In my case, I wanted something that didn't affect any other processes in the environment, so we can do something like this in the vagrant file-
VAGRANT_COMMAND = ARGV[0]
if VAGRANT_COMMAND == "ssh"
config.ssh.extra_args = ["-t", "cd /vagrant; bash --login"]
end
You can use Ansible to assert that your .bashrc file contains cd /vagrant.
If you are not already using the Ansible provisioner for your VM, add the following lines to your Vagrantfile:
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "provisioning/playbook.yml"
end
And in your playbook, add the following task/play:
---
- hosts: all
gather_facts: no
tasks:
- name: chdir to vagrant directory
ansible.builtin.lineinfile:
path: /home/vagrant/.bashrc
line: cd /vagrant
According to this Q&A, I would recommend to modify .bashrc instead of .profile or .bash_profile.

Resources