Im struggling with this Vagrantfile. My goal is to set up two virtual machines using Vagrant technology and also utilize Ansible to deploy a certain task in each machine after they had been created.
But how can execute provision with ansible after the two machines had been created successfuly?
# -*- mode: ruby -*-
# vi: set ft=ruby :
# variables
BOX_NAME = "debian/buster64"
PRIVATE_KEY_PATH_CONTROLLER = "~/.ssh/id_rsa"
PRIVATE_KEY_PATH_VAGRANT = "~/.vagrant.d/insecure_private_key"
PUBLIC_KEY_PATH_CONTROLLER = "~/.ssh/id_rsa.pub"
AUTHORIZED_KEYS_PATH = "~/.ssh/authorized_keys"
Vagrant.configure("2") do |config|
# configuracion general
config.vm.box = BOX_NAME
config.ssh.insert_key = false
config.ssh.private_key_path = [PRIVATE_KEY_PATH_CONTROLLER, PRIVATE_KEY_PATH_VAGRANT]
config.vm.provision "file", source: PUBLIC_KEY_PATH_CONTROLLER, destination: AUTHORIZED_KEYS_PATH
config.vm.synced_folder "./shared", "/vagrant"
# configuracion nodo 1
config.vm.define "nodo_uno" do |nodo|
nodo.vm.hostname = "nodo1"
nodo.vm.network "private_network", ip: "192.168.50.10"
nodo.vm.provider "virtualbox" do |vb|
vb.name = "nodo1(50.10)"
vb.memory = 512
vb.cpus = 1
end
end
# configuracion nodo 2
config.vm.define "nodo_dos" do |nodo|
nodo.vm.hostname = "nodo2"
nodo.vm.network "private_network", ip: "192.168.50.20"
nodo.vm.provider "virtualbox" do |vb|
vb.name = "nodo2(50.20)"
vb.memory = 512
vb.cpus = 1
end
end
# if nodo = "nodo_dos"
config.vm.provision "ansible" do |ansible|
# ansible.groups = {
# "nodo_uno" => ["nodos"],
# "nodo_dos" => ["nodos"]
# }
ansible.inventory_path = "./hosts"
ansible.limit = "nodos"
ansible.playbook = "grupos_usuarios.yml"
ansible.become = true
end
end
nodos is a group that involves nodo_uno and nodo_dos
so when I run vagrant up, ansible throws me an error because of noo2 has not been created yet. so it can't provision it.
I know I can use "vagrant up --no-provision" and then "vagant provision" but what I want is to avoid this system and use some conditional statement in my vagrantfile that triggers my playbook once node2 had been successfuly set up. Sorry for my bad english.
There's a multi-machine Vagrant setup (truncated here to two machines) like the following:
Vagrant.configure(2) do |config|
config.vm.define "xfcevm" do |xfcevm|
xfcevm.vm.box = "generic/ubuntu1904"
xfcevm.vm.hostname = "xfcevm"
end
config.vm.define "gnomevm" do |gnomevm|
gnomevm.vm.box = "generic/fedora30"
gnomevm.vm.hostname = "gnomevm"
end
config.vm.provider "virtualbox" do |vb|
vb.gui = true
vb.memory = "2048"
vb.cpus = 1
vb.customize ["modifyvm", :id, "--vram", "32"]
end
config.vm.provision "ansible" do |ansible|
ansible.verbose = "v"
ansible.compatibility_mode = "2.0"
ansible.playbook = "setup.yml"
end
config.vm.provision "ansible", run: 'always' do |ansible|
ansible.verbose = "v"
ansible.compatibility_mode = "2.0"
ansible.playbook = "tests.yml"
end
# halt here
end
If the tests playbook passes without errors then I want that machine to be halted just after the tests.yml playbook is finished. How I can do that from Vagrantfile or by creating another Ansible task?
You can issue a shutdown command at the end of your test playbook. It will only be played if the rest of the tasks were successful.
- name: shutdown machine
become: true
command: shutdown -h now
See shutdown --help to adapt the command to your specific need (e.g. using halt instead of poweroff)
I have a Vagrantfile that sets up two guests. I would like to provision different playbooks against each guest.
Vagrant.configure(2) do |config|
config.vm.define "awx" do |awx|
awx.vm.box = "centos/7"
awx.vm.hostname ="awx"
awx.vm.network "private_network", ip: "192.168.10.10"
config.vm.provision "ansible" do |master|
master.playbook = "awx.yml"
end
end
config.vm.define "test" do |test|
test.vm.box = "centos/7"
test.vm.hostname = "test"
test.vm.network "private_network", ip: "192.168.10.11"
config.vm.provision "ansible" do |slave|
slave.playbook = "httpd-server.yml"
end
end
end
The the first playbook executes against the first node as expected. However, both playbooks execute against the second node.
The problem here is that you are using the outer scope iteration variable config instead of the inner scope iteration variables for your method invocations. These would lock down the scope of your Ansible provisioner to only vagrant machines defined within that scope. For example, to rectify your problem we would do:
Vagrant.configure(2) do |config|
config.vm.define "awx" do |awx|
awx.vm.box = "centos/7"
awx.vm.hostname ="awx"
awx.vm.network "private_network", ip: "192.168.10.10"
awx.vm.provision "ansible" do |master| # inner scope iter var awx
master.playbook = "awx.yml"
end
end
config.vm.define "test" do |test|
test.vm.box = "centos/7"
test.vm.hostname = "test"
test.vm.network "private_network", ip: "192.168.10.11"
test.vm.provision "ansible" do |slave| # inner scope iter var test
slave.playbook = "httpd-server.yml"
end
end
end
I'd like to be able to spin up all of my Vagrant VMs for a project at once and then, at the very end, execute Ansible (using ansible_local) on one of those VMs. Is it possible to have a provisioner such as ansible_local run on a machine you've already previously defined?
Example of what I want to do:
# VM definitions
config.vm.define "control" do |control|
control.vm.hostname = "control.somedomain.local"
control.vm.network "private_network", ip: "172.28.128.3"
control.vm.provider "virtualbox" do |control_vbox|
control_vbox.name = "Ansible Controller"
control_vbox.cpus = 2
control_vbox.memory = 1024
end
end
config.vm.define "web01" do |web|
control.vm.hostname = "web01.somedomain.local"
control.vm.network "private_network", ip: "172.28.128.4"
control.vm.provider "virtualbox" do |web_vbox|
web_vbox.name = "Web Server 1"
web_vbox.cpus = 2
web_vbox.memory = 1024
end
end
# run ansible_local provisioner from the control VM
config.vm.provision "ansible_local" do |ansible|
ansible.run_on_vm = "control"
ansible.playbook = "some_playbook.yml"
end
You can make the following change in your Vagrantfile
# VM definitions
config.vm.define "control" do |control|
control.vm.hostname = "control.somedomain.local"
control.vm.network "private_network", ip: "172.28.128.3"
control.vm.provider "virtualbox" do |control_vbox|
control_vbox.name = "Ansible Controller"
control_vbox.cpus = 2
control_vbox.memory = 1024
end
# run ansible_local provisioner from the control VM
control.vm.provision "ansible_local" do |ansible|
ansible.run_on_vm = "control"
ansible.playbook = "some_playbook.yml"
end
end
config.vm.define "web01" do |web|
control.vm.hostname = "web01.somedomain.local"
control.vm.network "private_network", ip: "172.28.128.4"
control.vm.provider "virtualbox" do |web_vbox|
web_vbox.name = "Web Server 1"
web_vbox.cpus = 2
web_vbox.memory = 1024
end
end
so that the ansible provisioner will run only on the control VM
The other possibilities are
running the vagrant command in following order
$ vagrant up --no-provision // will spin up all the vms but will not provisiong
$ vagrant provision control // will provision the control vm
check the vagrant trigger plugin which can be used to run specific command, I have not tested though with multi machine environment
I've got a vagrant file that builds a local VM. I want to add the EC2 provider and have the option of either provisioning a local VM or one on EC2.
Can I create configs for multiple providers in the same Vagrantfile and somehow choose which to run when I do vagrant up?
You can use a multi-vm environment, where every VM can be provisioned with a different provider and you can choose on commandline which one you want to vagrant up <machine>.
add box for each provider
> vagrant box add precise64 http://file.vagrantup.com/precise64.box
> vagrant box add precise64 http://file.vagrantup.com/precise64_vmware_fusion.box
and your Vagrantfile should look like
Vagrant.configure(2) do |config|
config.vm.box="precise64"
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", "2048"]
end
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = "2048"
end
end
then create on each provider using following commands
> vagrant up --provider=virtualbox
> vagrant up --provider=vmware_fusion
You can choose which provider you want to run by --provider parameter.
Here is ruby code in Vagrantfile which can run different VM depending which provider you have chosen:
require 'getoptlong'
# Parse CLI arguments.
opts = GetoptLong.new(
[ '--provider', GetoptLong::OPTIONAL_ARGUMENT ],
)
provider='virtualbox'
begin
opts.each do |opt, arg|
case opt
when '--provider'
provider=arg
end # case
end # each
rescue
end
# Vagrantfile API/syntax version.
Vagrant.configure(2) do |config|
config.vm.hostname = "vagrant"
config.vm.define "default-#{provider}"
config.vm.provider "virtualbox" do |vbox, override|
vbox.customize ['modifyvm', :id, '--natdnshostresolver1', 'on']
vbox.name = "test.local"
override.vm.box = "ubuntu/wily64"
override.vm.network "private_network", ip: "192.168.22.22"
end
config.vm.provider :aws do |aws, override|
aws.ami = "ami-7747d01e"
aws.instance_type = "m3.medium"
override.vm.box = "dummy"
override.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
override.ssh.username = "ubuntu"
end
end
So by the default provider is virtualbox, but you can specify from the command line, like:
vagrant up --provider=aws
To run VM locally you can run:
vagrant up --provider=virtualbox
and if you'd like to run VM using different provider then you can use:
vagrant up --provider=aws
However, remember that you have to install appropriate provider plugin before you will use it.
Please check this gist posted by #tknerr which works with all providers such as virtualbox, AWS and managed in combination with the vagrant-omnibus plugin. Here is the code from Vagrantfile:
#
# Vagrantfile for testing
#
Vagrant::configure("2") do |config|
# the Chef version to use
config.omnibus.chef_version = "11.4.4"
def configure_vbox_provider(config, name, ip, memory = 384)
config.vm.provider :virtualbox do |vbox, override|
# override box url
override.vm.box = "opscode_ubuntu-13.04_provisionerless"
override.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-13.04_provisionerless.box"
# configure host-only network
override.vm.hostname = "#{name}.local"
override.vm.network :private_network, ip: ip
# enable cachier for local vbox vms
override.cache.auto_detect = true
# virtualbox specific configuration
vbox.customize ["modifyvm", :id,
"--memory", memory,
"--name", name
]
end
end
def configure_aws_provider(config)
config.vm.provider :aws do |aws, override|
# use dummy box
override.vm.box = "aws_dummy_box"
override.vm.box_url = "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box"
# override ssh user and private key
override.ssh.username = "ubuntu"
override.ssh.private_key_path = "#{ENV['HOME']}/.ssh/mccloud_rsa"
# aws specific settings
aws.access_key_id = "XXXX"
aws.secret_access_key = "XXXXX"
aws.ami = "ami-524e4726"
aws.region = "eu-west-1"
aws.availability_zone = "eu-west-1c"
aws.instance_type = "m1.small"
aws.security_groups = [ "mccloud", "http" ]
aws.keypair_name = "mccloud-key-tlc"
end
end
def configure_managed_provider(config, server)
config.vm.provider :managed do |managed, override|
# use dummy box
override.vm.box = "managed_dummy_box"
override.vm.box_url = "https://github.com/tknerr/vagrant-managed-servers/raw/master/dummy.box"
# link with this server
managed.server = server
end
end
#
# define a separate VMs for the 3 providers (vbox, aws, managed)
# because with Vagrant 1.2.2 you can run a VM with only one provider at once
#
[:aws, :vbox, :esx].each do |provider|
#
# Sample VM per provider
#
config.vm.define :"sample-app-#{provider}" do | sample_app_config |
case provider
when :vbox
configure_vbox_provider(sample_app_config, "sample-app", "33.33.40.10")
when :aws
configure_aws_provider(sample_app_config)
when :esx
configure_managed_provider(sample_app_config, "33.33.77.10")
end
sample_app_config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = [ './cookbooks/sample-app-0.1.0' ]
chef.add_recipe "sample-app"
chef.json = {
:sample_app => {
:words_of_wisdom => "Vagrant on #{provider} Rocks!"
}
}
end
end
end
end
From the Vagrant docs:
Multiple config.vm.provision methods can be used to define multiple provisioners. These provisioners will be run in the order they're defined.
eg.:
First install puppet in the machine and then run some puppet manifests:
$script = "
wget http://apt.puppetlabs.com/puppetlabs-release-precise.deb
sudo dpkg -i puppetlabs-release-precise.deb
sudo apt-get update
sudo aptitude -yy install puppet
"
config.vm.provision "shell", inline: $script
config.vm.provision "puppet" do |puppet|
puppet.manifests_path = "manifest/puppet"
puppet.manifest_file = "init.pp"
end
config.vm.provision "shell", inline: "echo Second shell provisioner"
Yes, you can specify multiple machines by using the config.vm.define method call, for example:
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: "echo Hello"
config.vm.define "web" do |web|
web.vm.box = "apache"
end
config.vm.define "db" do |db|
db.vm.box = "mysql"
end
end
See: Defining multiple machines at Vagranup Docs and Providers