Search code examples
pythonshellvagrantvirtualenvwrapper

Updating .bashrc and environment variables during Vagrant provisioning


I'm using Vagrant to set up a box with python, pip, virtualenv, virtualenvwrapper and some requirements. A provisioning shell script adds the required lines for virtualenvwrapper to .bashrc. It does a very basic check that they're not already there, so that it doesn't duplicate them with every provision:

if ! grep -Fq "WORKON_HOME" /home/vagrant/.bashrc; then
    echo 'export WORKON_HOME=/home/vagrant/.virtualenvs' >> /home/vagrant/.bashrc
    echo 'export PROJECT_HOME=/home/vagrant/Devel' >> /home/vagrant/.bashrc
    echo 'source /usr/local/bin/virtualenvwrapper.sh' >> /home/vagrant/.bashrc

    source /home/vagrant/.bashrc
fi

That seems to work fine; after provisioning is finished, the lines are in .bashrc, and I can ssh to the box and use virtualenvwrapper.

However, virtualenvwrapper doesn't work during provisioning. After the section above, this next checks for a pip requirements file and tries to install with virtualenvwrapper:

if [[ -f /vagrant/requirements.txt ]]; then
    mkvirtualenv 'myvirtualenv' -r /vagrant/requirements.txt
fi

But that generates:

==> default: /tmp/vagrant-shell: line 50: mkvirtualenv: command not found

If I try and echo $WORKON_HOME from that shell script, nothing appears.

What am I missing to have those environment variables available, so virtualenvwrapper will run?

UPDATE: Further attempts... it seems that doing source /home/vagrant/.bashrc has no effect in my shell script - I can put echo "hello" in the .bashrc file , and that isn't output during provisioning (but is if I run source /home/vagrant/.bashrc when logged in.

I've also tried su -c "source /home/vagrant/.bashrc" vagrant in the shell script but that is no different.

UPDATE 2: Removed the $BASHRC_PATH variable, which was confusing the issue.

UPDATE 3: In another question I got the answer as to why source /home/vagrant/.bashrc wasn't working: the first part of the .bashrc file prevented it from doing anything when run "not interactively" in that way.


Solution

  • The Vagrant script provisioner will run as root, so it's home dir (~) will be /root. In your script if you define BASHRC_PATH=/home/vagrant, then I believe your steps will work: appending to, then sourcing from /home/vagrant/.bashrc.

    Update:

    Scratching my earlier idea ^^ because BASHRC_PATH is already set correctly.

    As an alternative we could use .profile or .bash_profile. Here's a simplified example which sets environment variable FOO, making it available during provisioning and after ssh login:

    Vagrantfile

    Vagrant.configure(2) do |config|
      config.vm.box = "hashicorp/precise32"
    
      $prov_script = <<SCRIPT
    if ! grep -q "export FOO" /home/vagrant/.profile; then
      sudo echo "export FOO=bar" >> /home/vagrant/.profile
      echo "before source, FOO=$FOO"
      source /home/vagrant/.profile
      echo "after source, FOO=$FOO"
    fi
    SCRIPT
    
      config.vm.provision "shell", inline: $prov_script
    end
    

    Results

    $ vagrant up
    ...
    ==> default: Running provisioner: shell...
        default: Running: inline script
    ==> default: before source, FOO=
    ==> default: after source, FOO=bar
    $ vagrant ssh -c 'echo $FOO'
    bar
    $ vagrant ssh -c 'tail -n 1 ~/.profile'
    export FOO=bar