debugging a vagrant setup bash script - bash

I have a Vagrantfile with a setup script as below. I've run it several times with vagrant up and I know the first few commands work, but later ones I know did not succeed.
Vagrantfile:
# -*- mode: ruby -*-
VAGRANTFILE_API_VERSION = "2"
$setup = <<END
# some bash code
# ...
# something that somehow never runs
sudo chown -R vagrant:vagrant /some/path
END
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "puppetlabs/centos-7.0-64-nocm"
config.vm.define "client", primary: true do |client|
client.vm.hostname = "client.example.com"
client.vm.network :private_network, ip: "192.168.250.10"
client.vm.provision "shell", inline: $setup
end
end
Is there any way to see what errors happen when scripts are run on vagrant up?
I tried vagrant up --debug &> vagrant.log but the output was literally thousands of lines and I couldn't find anything useful (or didn't know what to look for, which is more likely).

echo should do the trick and display messages from your shell file.
echo "running update ..."
sudo apt-get update
echo "running install lib ..."
sudo apt-get install --yes git-all libreadline-dev build-essential curl git m4 python-setuptools ruby texinfo libbz2-dev libcurl4-openssl-dev libexpat-dev libncurses-dev zlib1g-dev
echo "install rvm ..."
curl -L https://get.rvm.io | bash -s stable --ruby=2.0.0
all echo messages will be displayed in the output when running the shell provisioning
If you need to redirect stderr to stdout you can do something like grep * 2>&1 -
ref: http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html

While Frédéric Henri's answer is definitely recommended and helpful, vagrant also comes with some built in debugging help which you can read more about here, but basically you can vagrant up with a debug flag for more information:
vagrant up --debug

Related

Installing golang 1.10 on vagrant vbox

I am running the following script from a Vagrantfile and everything is working fine. In the end, I see the output go1.10 linux/amd64 as expected.
But, when I run vagrant ssh I get The program 'go' is currently not installed.
What is the difference between vagrant provision that was able to see go and vagrant ssh that was not able to see go?
config.vm.box = "ubuntu/xenial64"
config.vm.provision "shell" do |s|
s.inline = "
sudo apt-get update
export GOPATH=$HOME/work
sudo curl -O https://storage.googleapis.com/golang/go1.10.linux-amd64.tar.gz
sudo tar -xvf go1.10.linux-amd64.tar.gz
sudo mv go /usr/local
sudo echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
export PATH=$PATH:/usr/local/go/bin
go version" # this row is working fine on the script but not after ssh
end
In order to make your changes to $PATH available to all users, you have to change it in the global profile, not the user's. Change the line
sudo echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
to
sudo echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile

Vagrant - Provisioning script not changing directory

New to vagrant, please help!
Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "laravel/homestead"
config.vm.provision "shell", path: "vm-setup/provision.sh"
end
vm-setup/provision.sh
# Update apt-get
apt-get -y update
# Install tree
apt-get install tree
# Create .bash_aliases
sudo echo 'alias cls="clear"' >> ~/.bash_aliases
sudo chsh -s $(which zsh) vagrant
cd /vagrant
provision.sh file runs fine. When I run "vagrant provision" it updates apt-get, installs tree and even changes the shell to ZSH.
But sudo echo 'alias cls="clear"' >> ~/.bash_aliases and cd /vagrant lines do not work, not sure why. When I vagrant ssh into the machine, I am being taken to root directory (/home/vagrant). I would like to start in /vagrant folder.
Vagrant's shell provisioner by default runs with privileged = true:
privileged (boolean) - Specifies whether to execute the shell script
as a privileged user or not (sudo). By default this is "true".
When you perform vagrant ssh you login to a VM as vagrant user.
That's why:
1.
# Create .bash_aliases
sudo echo 'alias cls="clear"' >> ~/.bash_aliases
It writes to root's ~/.bash_aliases and it is really there:
root#vagrant:~# id
uid=0(root) gid=0(root) groups=0(root)
root#vagrant:~# cat .bash_aliases
alias cls="clear"
Solution: write to vagrant's home folder:
# Create .bash_aliases
echo 'alias cls="clear"' >> /home/vagrant/.bash_aliases
chown vagrant:vagrant /home/vagrant/.bash_aliases
2.
cd /vagrant
This means that folder was changed in provision script, nothing else.
Solution: add this statement to vagrant's .bash_aliases as well:
echo 'cd vagrant' >> /home/vagrant/.bash_aliases
Your final vm-setup/provision.sh is:
# Update apt-get
apt-get -y update
# Install tree
apt-get install tree
# Create .bash_aliases
echo 'alias cls="clear"' >> /home/vagrant/.bash_aliases
echo 'cd /vagrant' >> /home/vagrant/.bash_aliases
chown vagrant:vagrant /home/vagrant/.bash_aliases
chsh -s $(which zsh) vagrant
Even not being the case, just for the sake of completion:
I had struggled many times while trying to use Vagrant as testing tool for setup scripts and just now I realized the underlying reason:
Using this Vagrantfile statement:
config.vm.provision "shell", path: "myScript.sh"
myScript.sh is inlined to the virtual machine standard input. This is good in the sense you don't need access to the actual script from inside the virtual machine (typically through /vagrant path).
...but it comes with the drawback that any relative path won't work properly.
Of course: We can adjust it to absolute path based on /vagrant. But this requires to modify the script we are trying to test.
So in this case (and in my opinion in any case we are not going to disable /vagrant share), it is a better solution to use "inline:" option with the "machine-internal" path:
config.vm.provision "shell", inline: "/vagrant/myScript.sh"
...This will inline this statement instead of the contents of the file and relative paths (or even "script path based" ones such as $(dirname "${0}")/relative/path) are going to work properly.
Additionally, if the setup script you are going to test is intended to be executed by non privileged users (for example if it is going to set up some user configuration we will expect to work just after a vagrant ssh -with vagrant user-) it is also a good idea to add the privileged: false option, pointed out by #Nickolay:
config.vm.provision "shell", inline: "/vagrant/myScript.sh", privileged: false

Automatically Installing and running Ansible Local via Vagrant

I am using Vagrant and trying to enable Ansible to work with it. Because I am working in a virtualenv with Python 3.5.0, I have to use Ansible-Local – the "main" Ansible will not run on my host because I am not running Python 2.x.
Regardless, everything mostly works, except that vagrant up does not find Ansible. Here is the output from the call:
==> default: Running provisioner: ansible_local...
default: Installing Ansible...
The Ansible software could not be found! Please verify
that Ansible is correctly installed on your guest system.
If you haven't installed Ansible yet, please install Ansible
on your Vagrant basebox, or enable the automated setup with the
`install` option of this provisioner. Please check
https://docs.vagrantup.com/v2/provisioning/ansible_local.html
for more information.
However, if I use vagrant ssh to access the VM, Ansible is clearly installed:
vagrant#vagrant-ubuntu-trusty-64:~$ ansible --version
ansible 2.0.0.2
config file = /etc/ansible/ansible.cfg
configured module search path = Default w/o overrides
I'm at a loss of what to do. I can run ansible-playbook server.yml, while SSH'd into the server, and it works correctly. However, the whole point of me using Ansible is that I could automatically run it via Vagrant. Here's the relevant portion of my Vagrantfile:
config.vm.provision "ansible_local" do |ansible|
ansible.install = true
ansible.version = "latest"
ansible.sudo = true
ansible.playbook = "server.yml"
end
Any suggestions are greatly appreciated. Thank you!
By bringing the box up in debug mode:
VAGRANT_LOG=debug vagrant up
Shows:
DEBUG ssh: Re-using SSH connection.
INFO ssh: Execute: ansible-galaxy --help && ansible-playbook --help (sudo=false)
DEBUG ssh: stderr: ERROR! Missing required action
DEBUG ssh: stdout: Usage: ansible-galaxy [delete|import|info|init|install|list|login|remove|search|setup] [--help] [options] ...
Options:
-h, --help show this help message and exit
-v, --verbose verbose mode (-vvv for more, -vvvv to enable connection
debugging)
--version show program's version number and exit
DEBUG ssh: Exit status: 5
ansible-galaxy --help is the problem as it expected an action. Because that failed, vagrant thinks that there was a problem with the install.
It looks like this has been fixed on the master branch and will be in the next version.
What you could try is:
# -*- mode: ruby -*-
# vi: set ft=ruby :
$install_ansible = <<SCRIPT
apt-get -y install software-properties-common
apt-add-repository ppa:ansible/ansible
apt-get -y update
apt-get -y install ansible
SCRIPT
Vagrant.configure(2) do |config|
config.vm.box = 'ubuntu/trusty64'
config.vm.provision 'shell', inline: $install_ansible
# Patch for https://github.com/mitchellh/vagrant/issues/6793
config.vm.provision "shell" do |s|
s.inline = '[[ ! -f $1 ]] || grep -F -q "$2" $1 || sed -i "/__main__/a \\ $2" $1'
s.args = ['/usr/bin/ansible-galaxy', "if sys.argv == ['/usr/bin/ansible-galaxy', '--help']: sys.argv.insert(1, 'info')"]
end
config.vm.provision :ansible_local do |ansible|
ansible.sudo = true
ansible.playbook = 'server.yml'
end
end
note: Credit to MasonM for the
following snippet:
# Patch for https://github.com/mitchellh/vagrant/issues/6793
config.vm.provision "shell" do |s|
s.inline = '[[ ! -f $1 ]] || grep -F -q "$2" $1 || sed -i "/__main__/a \\ $2" $1'
s.args = ['/usr/bin/ansible-galaxy', "if sys.argv == ['/usr/bin/ansible-galaxy', '--help']: sys.argv.insert(1, 'info')"]
end
Or another option while waiting for the fix to be released is building vagrant from source.

Install Oh My Zsh on a Vagrant Box as part of the bootstrap process

I'd like to add Oh My Zsh to my Vagrant bootstrap process, but a straight install isn't working.
via curl:
curl -L http://install.ohmyz.sh | sh
via wget:
wget --no-check-certificate http://install.ohmyz.sh -O - | sh
Found the solution:
# Added zsh shell.
sudo apt-get install zsh
wget --no-check-certificate https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh
sudo chsh -s /bin/zsh vagrant
zsh
As an nice addition, so that your terminals don't look too similar on the different boxes
# Change the oh my zsh default theme.
sed -i 's/ZSH_THEME="robbyrussell"/ZSH_THEME="3den"/g' ~/.zshrc
Here's a complete Vagrantfile that installs Oh My Zsh on an Ubuntu 14.04.2 LTS box and sets it as the default shell for standard vagrant user.
This works with Vagrant 1.7.2. (Your milage may vary with different versions.) It uses the directions from the Manual Installation section of the Readme instead of trying to use the automatic scripts.
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Pick a box to use:
config.vm.box = "ubuntu/trusty64"
############################################################
# Oh My ZSH Install section
# Install git and zsh prerequisites
config.vm.provision :shell, inline: "apt-get -y install git"
config.vm.provision :shell, inline: "apt-get -y install zsh"
# Clone Oh My Zsh from the git repo
config.vm.provision :shell, privileged: false,
inline: "git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh"
# Copy in the default .zshrc config file
config.vm.provision :shell, privileged: false,
inline: "cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc"
# Change the vagrant user's shell to use zsh
config.vm.provision :shell, inline: "chsh -s /bin/zsh vagrant"
############################################################
end
As a bonus, you can do a one time copy of your host machine's .zshrc file to the vagrant box with:
config.vm.provision "file", source: "~/.zshrc", destination: ".zshrc"
(Keep in mind, You may have to figure things that don't work initially because of differences between the host machine and the vagrant box's setups.)
I came here because had a same issue. After seeing some answer and trying it, mostly the zsh & oh-my-zsh got installed as root. The root will set his $SHELL with zsh. What I want is they are installed as user vagrant. The bootstrap was done by root when provisioning. So the logic is try to run install zsh & oh-my-zsh as user. Here is what I did after trying many times until I got what I wanted :
## In Vagrantfile try to call bootstrap.sh
config.vm.provision "shell", path: "bootstrap.sh"
## This is the bootstrap.sh
aptInstl() {
DEBIAN_FRONTEND=noninteractive apt-get install -qq -y $1 > /dev/null
}
install_zsh() {
aptInstl "zsh"
su -l vagrant -s "/bin/sh" \
-c "curl -fsSO https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh; chmod 755 install.sh; ./install.sh --unattended"
chsh -s /bin/zsh vagrant
}
install_miscellaneous() {
apt-get update > /dev/null
apt-get upgrade > /dev/null
for i in curl git; do
aptInstl "$i"
done
}
main() {
install_miscellaneous
install_zsh
}
main
And It works perfectly :)
When you are done try to vagrant ssh it will automatically logged you in with zsh shell and oh-my-zsh. Here is the complete file.

Setting up Shell Script for Vagrant Setup

Trying to write a shell script to setup my server environment on Ubuntu through Vagrant and am running into a problem where the script ends unexpectedly. I added the path to the shell script in Vagrant's provision config option.
Vagrant:
# Specify our provision script
config.vm.provision "shell", path: "scripts/bootstrap.sh"
My script:
#!/bin/bash
# Install dependencies for Ruby
sudo apt-get update
sudo apt-get install -y git-core curl zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common
# Setting up rbenv
echo 'Setting up rbenv'
git clone git://github.com/sstephenson/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec $SHELL
After running, I expect the repository to be cloned into the .rbenv folder and to have rbenv added to $PATH in ~/.bashrc along with the rbenv init function evaluated and put into ~/.bashrc. However, when the script is executed on Vagrant's provision step I end up with the script just cloning the git repository and then terminating without executing anything else in my script.
Output:
==> default: Processing triggers for libc-bin (2.19-0ubuntu6) ...
==> default: Setting up rbenv
==> default: Cloning into '.rbenv'...
And then the script terminates and ~/.bashrc is left unchanged. I was wondering how I can change my shell script so that it will perform the action I want (which is adding rbenv to ~/.bashrc). Any ideas?
As mklement0 said, the script does not run as the vagrant user: it runs as root.
If you want to run the script as the vagrant user you need privileged: false.
config.vm.provision :shell, privileged: false, path: "scripts/bootstrap.sh"
As mklement0 said: use set -xv to debug your provisioning scripts.
If you want to run as another user, don't forget that su user won't work: How do I use su to execute the rest of the bash script as that user?
If you want execute some script like vagrant user, try this.
su vagrant -l -c "echo Hello world"

Resources