Steve Childs
Steve Childs

Reputation: 1872

Vagrant - how to have host platform specific provisioning steps

We've got a diverse dev team, one on Windows, another on Ubuntu and another on OSX. Being windows boy, I setup the first version of the vagrant setup script which works fabulously ;)

However, when running it on the Ubuntu host, the first time it gets to a provision step that calls a bash script, it fails due to permissions.

On windows, this doesn't matter as the samba share automatically has sufficient permissions to run the bash script (which resides within the project hierarchy, so is present in the /vagrant share on the VM), but with ubuntu I need to set the permissions on this file in the provision script before I call it.

This isn't the problem and to be honest I suspect even with the extra "chmod" step it would still work fine under windows, but, is there a way in the vagrant file to flag certain provisioning steps as 'Windows Only', 'Linux Only' or 'Mac Only'?

i.e. in pseduo code, something like.

.
.
if (host == windows) then
  config.vm.provision : shell, : inline => "/vagrant/provisioning/only_run_this_on_windows.sh"
else if (host == linux) then
  config.vm.provision : shell, : inline => "/vagrant/provisioning/only_run_this_on_linux.sh"
else if (host == osx) then
  config.vm.provision : shell, : inline => "/vagrant/provisioning/only_run_this_on_osx.sh"
end if
.
.

Thanks in advance.

Upvotes: 48

Views: 18471

Answers (4)

Felix Eve
Felix Eve

Reputation: 3864

Here is a version using the Vagrant utils that checks for mac and windows:

    if Vagrant::Util::Platform.windows?
        # is windows
    elsif Vagrant::Util::Platform.darwin?
        # is mac
    else
        # is linux or some other OS
    end

Upvotes: 6

Peter de Zwart
Peter de Zwart

Reputation: 71

When I read the original question according to me it is not how to find out on which OS vagrant it self runs, but which OS do the virtual machines to be provisioned have. That is why you want to run a different provision script depending on the diffent OSses of the new VMs, eg: "/vagrant/provisioning/only_run_this_on_${OS_OF_NEW_VM}.sh".

Unfortunately Vagrant does not have this capability (yet), so this is my solution: I define my VMs on top of my vagrant file:

   cluster = {
  "control.ansible.RHEL76" => { :ip => "192.168.1.31", :type => 0, :cpus => 1, :mem => 1024, :box_image => "centos/7" },
  "app01.ansible.RHEL76"   => { :ip => "192.168.1.32", :type => 1, :cpus => 1, :mem => 1024, :box_image => "centos/7" },
  "app02.ansible.RHEL76"   => { :ip => "192.168.1.33", :type => 1, :cpus => 1, :mem => 1024, :box_image => "centos/7" },
  "winserver"          => { :ip => "192.168.1.34", :type => 2, :cpus => 1, :mem => 1024, :box_image => "mwrock/Windows2016" },
}

Then these conditions in my code can provision different ways depending on the OS of the VM's:

if "#{info[:box_image]}" == "mwrock/Windows2016" then
  puts "is_windows_host: #{info[:box_image]}"
  config.vm.provision : shell, inline => "/vagrant/provisioning/only_run_this_on_windows.psl"
end
if "#{info[:box_image]}" == "centos/7" then
  puts "is_linux_host: #{info[:box_image]}"
  config.vm.provision : shell, inline => "/vagrant/provisioning/only_run_this_on_linux.sh"
end

By the way, only the ansible controller should have ansible installed, because in real life (yes the office) I do not use vagrant but an ansible controller, which I also want in my lab (OK Virtual Box on both my Windows 10 desktop as well as my Ubuntu laptop). I use a condition to test "type = 0" (which I use for a ansible "controller"). Only the ansible controller starts ansible_local to provision the cluster of VMs with ansible.

   if info[:type]  == 0 then
     cfg.vm.provision "shell", inline: "if [ `which ansible` ] ; then echo \"ansible available\"; else sudo  yum -y update; sudo yum -y install epel-release; sudo yum -y install ansible; fi"
     cfg.vm.provision "ansible_local" do |ansible|
        ansible.extra_vars = { ansible_ssh_user: 'vagrant' }
        ansible.inventory_path = "./production"
        ansible.playbook = "rhelhosts.yml"
        ansible.limit = "local"
     end # ansible_local

This is displayed during a vagrant provision:

PS D:\Documents\vagrant\top> vagrant provision control.top.RHEL76 is_linux_host: centos/7 is_linux_host: centos/7 is_linux_host: centos/7 is_windows_host: mwrock/Windows2016

This is displayed during a vagrant provision:

PS D:\Documents\vagrant\ansible> vagrant provision control.ansible.RHEL76

is_linux_host: centos/7

is_linux_host: centos/7

is_linux_host: centos/7

is_windows_host: mwrock/Windows2016

--- many more lines, not relevant ---

Have fun experimenting and deploying your multimachine / multi OS labs!

Upvotes: 0

Tomas Creemers
Tomas Creemers

Reputation: 2715

Note that Vagrant itself, in the Vagrant::Util::Platform class already implements a more advanced version of the platform checking logic in the answer by BernardoSilva.

So in a Vagrantfile, you can simply use the following:

if Vagrant::Util::Platform.windows? then
    myHomeDir = ENV["USERPROFILE"]
else
    myHomeDir = "~"
end

Upvotes: 66

Bernardo Silva
Bernardo Silva

Reputation: 960

Find out current OS inside Vagrantfile.

Add this into your Vagrantfile:

module OS
    def OS.windows?
        (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
    end

    def OS.mac?
        (/darwin/ =~ RUBY_PLATFORM) != nil
    end

    def OS.unix?
        !OS.windows?
    end

    def OS.linux?
        OS.unix? and not OS.mac?
    end
end

Then you can use it as you like.

if OS.windows? [then]
    code...
end

Edit: was missing the ? on if condition.

Example used to test:

is_windows_host = "#{OS.windows?}"
puts "is_windows_host: #{OS.windows?}"
if OS.windows?
    puts "Vagrant launched from windows."
elsif OS.mac?
    puts "Vagrant launched from mac."
elsif OS.unix?
    puts "Vagrant launched from unix."
elsif OS.linux?
    puts "Vagrant launched from linux."
else
    puts "Vagrant launched from unknown platform."
end

Execute:

# Ran provision to call Vagrantfile.
$ vagrant provision
is_windows_host: false
Vagrant launched from mac.

Upvotes: 52

Related Questions