I am using the Ansible (local) provisioner for my Vagrant setup. Is there a recommended way to pass an environment variable to the provisioner?
For example, I want to run ENV=development vagrant up and have Vagrant pass the environment variable ENV to Ansible.
I tried using extra_vars, taken from the Vagrant documentation:
Vagrant.configure(2) do |vagrant|
# other configuration
vagrant.vm.provision :ansible_local do |ansible|
ansible.playbook = "ansible/server.yml"
ansible.extra_vars = {
env: ENV.fetch("ENV", "development")
}
end
end
However, when I run vagrant provision (without even using the env variable in Ansible), I get the following:
$ vagrant provision
==> default: Running provisioner: ansible_local...
default: Running ansible-playbook...
ERROR: Expecting property name: line 1 column 2 (char 1)
Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.
Removing ansible.extra_vars fixes this error, but then I can't accomplish what I wanted to.
You need to install the plugin for Vagrant:
vagrant plugin install vagrant-env
I hope my code snippets will help:
config.vm.define "k8s-master" do |master|
master.vm.box = IMAGE_NAME
master.env.enable # Enable vagrant-env(.env)
master.vm.network "private_network", ip: "192.168.50.10"
master.vm.hostname = "k8s-master"
master.vm.provision "ansible" do |ansible|
ansible.playbook = "./playbooks/master.yml"
ansible.compatibility_mode = "2.0"
ansible.extra_vars = {
env: development,
}
end
end
With config.env.enable added whenever you run a Vagrant command it’ll load .env into ENV which will allow your customizations.
And you can use this inside playbook as {{ variable_name }}
.
To access development environment variable, use: ENV['development'] syntax.
You can also assign it to the variable at the beginning of the file:
development = ENV['development']
and use variable instead:
ansible.extra_vars = {
env: development
}
Check the following Vagrantfile as example.
What is it that requires the environment variable be set?
I would try to use a different approach if possible. If you are expecting to act on the environment variable in ansible, you could instead set the value in an inventory group_vars file which would only be in effect for local provisioning vagrant. Other environments could use different values for the same variable by updating the appropriate inventory group_vars file.
Related
I have a vagrant job to create new VMs. Depending on the provider I pass to it, this could be created locally on Virtualbox, or on a Vsphere cluster with the vagrant-vsphere plugin.
Because of this, there are times when I want to run certain tasks on Virtualbox, and certain tasks on Vsphere. I figured the easiest way to do so would be to just pass a variable from Vagrant to ansible based on the provider. Roughly, this is what I have in my Vagrantfile so far.
$ansible_provider = ''
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define vmconf[:name] do |vagrantconf|
vagrantconf.vm.provider :virtualbox do |vb|
$ansible_provider = "virtualbox"
end
vagrantconf.vm.provider :vsphere do |vb|
$ansible_provider = "vsphere"
end
end
config.vm.provision :ansible do |ansible|
ansible.playbook = "provision.yml"
ansible.extra_vars = { ansible_ssh_user: 'test',
ansible_provider: $ansible_provider }
end
end
I added a print statement that shows the two extra_vars and ansible_ssh_user works correctly, but ansible_provider is just blank. When I remove the first line and change it to a local variable, I get the following error:
Message: undefined local variable or method 'ansible_provider'
I haven't used ruby all that much, so I figured I'm doing something wrong there. Any help with this would be greatly appreciated.
For this specific case, I think there is an easier way of achieving what you want. Ansible creates a series of facts for each host it runs against, which includes collecting virtualisation information for guests.Try adding the following task in one of your playbooks to see what I mean:
- name: Display Virtualisation Type fact
debug:
var: ansible_virtualization_type
That should mean you don't need to pass the variable in from Vagrant. If you want to see all the facts, in the directory containing your Vagrantfile, just run (you can add '-l host' to limit to one of your VM's):
ansible -m setup all
To answer your specific question, I think this will work for you:
# In this case I don't believe you need the '$' prefix for your variables
ansible_provider = ''
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define vmconf[:name] do |vagrantconf|
vagrantconf.vm.provider :virtualbox do |vb|
ansible_provider = "virtualbox"
end
vagrantconf.vm.provider :vsphere do |vb|
ansible_provider = "vsphere"
end
end
config.vm.provision :ansible do |ansible|
ansible.playbook = "provision.yml"
ansible.extra_vars = { ansible_ssh_user: "test",
ansible_provider: "#{ansible_provider}" }
end
end
I'm using an ansible remote server to provision my production server, that works well.
Now I thought about using this ansible server to provision my vagrant VMs.
Is this possible somehow? I thought about a shell script provision for the vagrant file that logs into the ansible server via ssh and executes the playbook command towards the VM on the local machine.
I don't have too much experience with shell scripts. Has anybody tried this or can tell me a better way to do it?
As Mxx wrote the best way would be to configure Vagrant box in a way to provision it using Ansible from the local machine. Then you would just need to type vagrant up [name of the box] and this would start the machine and provision it. Below I'am attaching a simple example of provisioning Vagrant box using Ansible, you can find all details concerning Ansible provisioner here.
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# Example of vagrant box provisioned using Ansible
# Start box: "vagrant up dev"
config.vm.define "dev" do |dev|
dev.vm.box = "Centos-6.5-minimal-x86_64-20140116"
dev.vm.box_url = "https://github.com/2creatives/vagrant-centos/releases/download/v6.5.3/centos65-x86_64-20140116.box"
dev.vm.provider :virtualbox do |vb|
vb.customize [
"modifyvm", :id,
"--name", "example-vagrant-box",
"--memory", 1024,
"--cpus", 2,
]
end
dev.vm.network :private_network, ip: "10.0.0.1"
dev.vm.hostname = "vagrant.local"
# Provision the box using Ansible provisioner
dev.vm.provision "ansible" do |ansible|
# Path to the inventory file
ansible.inventory_path = "./inventories/local"
# Path to playbook that should be run against the machine
ansible.playbook = "someplaybook.yml"
# Provisioning verbosity level
# "v", "vv", "vvv", "vvvv". 4 x v for the most verbose debugging info
ansible.verbose = "vvvv"
# Limit provisioning to the following groups
# This defines all the servers (or server groups) which should be provisioned to
# These are defined in the inventory file.
ansible.limit = ["db_servers"]
# Determines whether Ansible ask for Ansible Vault password when provisioner encounter encrypted file
# ansible.ask_vault_pass = "true"
# Optionally Ansible Vault password can be stored in the seperate file and passed like this
ansible.vault_password_file = "./vault-password"
end
end
I'm new to vagrant/homestead, and I'm trying to debug the box that was created using vagrant up as the connection is on a timeout loop. I'm trying to enable the GUI. I've tried adding the config from the vagrant site and every variation of it to my vagrantfile:
config.vm.provider "virtualbox" do |v|
v.gui = true
end
But whenever this is in there and I run vagrant up or reload, it just returns "Message: undefined local variable or method 'config' for main:Object"
Any ideas? Thanks in advance!
Recently I had the same problem, in my case this is because I put this code outside the main vagrant config block, try to put in the proper place like in example. First line define local variable config which used inside the block:
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
// other configs
config.vm.provider "virtualbox" do |v|
v.gui = true
end
end
I am writing a cookbook which will be run on Ubuntu. It will create a directory in home of the default user.
directory "/home/<default-user>/my-directory" do
owner <default-user>
end
The problem is, this default user is different across environments:
It is vagrant when running on virtual machine using Vagrant.
And it is ubuntu when running on EC2 instance.
What is a good practice to solve this kind of problem? And how to do it?
Thank you!
Make the user an attribute and set that according to your environment.
directory "/home/#{node[:my_app][:default_user]}/my-directory" do
owner node[:my_app][:default_user]
end
Then, on your attributes/default.rb file:
default[:my_app][:default_user] = 'ubuntu'
and on your Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.provision "chef_solo" do |chef|
# ...
chef.json = {
"my_app" => {
"default_user" => "vagrant"
}
}
end
end
This will set your default user to ubuntu, but that will be overridden when running in the Vagrant VM.
Checkout the configuration entry config.ssh.username: http://docs-v1.vagrantup.com/v1/docs/config/ssh/username.html
I want puppet to look for hiera.yaml in /etc but it's looking for it in /etc/puppet. I put a line into puppet.conf:
hiera_config = /etc/hiera.yaml
But still gives me the hiera.yaml update warning when I run the script.
I'm running the script from Vagrant 1.2.2. Using puppet 3.2.2
I'm running Centos 6.4 in a vm.
I found that the puppet provisioner in vagrant now support hiera_config_path which does exactly what is desired.
config.vm.provision :puppet do |puppet|
# path on host machine to hiera.yaml
puppet.hiera_config_path = '/Users/me/vms/hiera/hiera.yaml'
# This sets the relative path for hiera data directories
puppet.working_directory = '/Users/me/vms/hiera'
end
This is documented in Vagrant: Up and Running but I didn't find it until I started looking into the vagrant source to implement this feature myself.
Hmmm... On Vagrant 1.2.2 and Puppet 3.2.3, I am able to set hiera_config in puppet.conf without problems. I would double-check that you are editing /etc/puppet.conf on the Vagrant vm, not on the host machine, and that the hiera_config line is the [main] block, not just in the [master] block.
If both of those conditions are true and it is still not working, you might try explicitly setting hiera_config in your Vagrantfile:
config.vm.provision :puppet do |puppet|
...
puppet.options = '--hiera_config=/etc/hiera.yaml'
end
Good luck!
Puppet provisioning runs as root user, not vagrant, so that's why it doesn't take notice of your puppet.conf in /vagrant.
If you run puppet config print inside the vm from user vagrant and root you see ALL puppet config settings per user and compare.