From 3bf5032d4ba4e9fced364cde42aa8952018bf0cb Mon Sep 17 00:00:00 2001 From: Mark Aaron Shirley Date: Sat, 1 Feb 2014 13:04:20 -0800 Subject: [PATCH 01/14] Update Ansible provisioner to only create a single inventory file The Ansible provisioner will now only create a single inventory file named, "vagrant_ansible_inventory". All defined Vagrant machines will be added to this inventory file. Provisioning will now include a "--limit=#{machine}" option to scope Ansible provisioning tasks to just the current machine. Setting the Ansible provisioner's "limit" config option will override the new default limit. Ansible provisioning scripts will now have access to all other defined machines and what groups they reside in. --- plugins/provisioners/ansible/provisioner.rb | 30 ++++++++++++++----- .../source/v2/provisioning/ansible.html.md | 20 ++++++------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index aae761f0a..9a27ae3ca 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -13,6 +13,14 @@ module VagrantPlugins # Joker! Not (yet) supported arguments can be passed this way. options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments + # By default we limit by the current machine. This can be + # overriden by the limit config option. + limit_option = if config.limit == nil + "--limit=#{@machine.name}" + elsif not config.limit.empty? + "--limit=#{as_list_argument(config.limit)}" + end + # Append Provisioner options (highest precedence): options << "--inventory-file=#{self.setup_inventory_file}" options << "--extra-vars=#{self.get_extra_vars_argument}" if config.extra_vars @@ -22,7 +30,7 @@ module VagrantPlugins options << "--ask-sudo-pass" if config.ask_sudo_pass options << "--tags=#{as_list_argument(config.tags)}" if config.tags options << "--skip-tags=#{as_list_argument(config.skip_tags)}" if config.skip_tags - options << "--limit=#{as_list_argument(config.limit)}" if config.limit + options << limit_option if limit_option options << "--start-at-task=#{config.start_at_task}" if config.start_at_task # Assemble the full ansible-playbook command @@ -64,25 +72,31 @@ module VagrantPlugins ssh = @machine.ssh_info generated_inventory_file = - @machine.env.root_path.join("vagrant_ansible_inventory_#{machine.name}") + @machine.env.root_path.join("vagrant_ansible_inventory") generated_inventory_file.open('w') do |file| file.write("# Generated by Vagrant\n\n") - file.write("#{machine.name} ansible_ssh_host=#{ssh[:host]} ansible_ssh_port=#{ssh[:port]}\n") - # Write out groups information. Only include current - # machine and its groups to avoid Ansible errors on - # provisioning. + @machine.env.active_machines.each do |am| + m = @machine.env.machine(*am) + file.write("#{m.name} ansible_ssh_host=#{m.ssh_info[:host]} ansible_ssh_port=#{m.ssh_info[:port]}\n") + end + + # Write out groups information. Only includes groups and + # machines which have been defined, otherwise Ansible will + # complain. groups_of_groups = {} included_groups = [] config.groups.each_pair do |gname, gmembers| if gname.end_with?(":children") groups_of_groups[gname] = gmembers - elsif gmembers.include?("#{machine.name}") + else included_groups << gname file.write("\n[#{gname}]\n") - file.write("#{machine.name}\n") + gmembers.each do |gm| + file.write("#{gm}\n") if @machine.env.active_machines.map { |m| m[0] }.include?(gm.to_sym) + end end end diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 9ad057116..f7fb36498 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -30,15 +30,15 @@ a single page of documentation. When using Ansible, it needs to know on which machines a given playbook should run. It does this by way of an inventory file which lists those machines. In the context of Vagrant, there are two ways to approach working with inventory files. The first and simplest option -is to not provide one to Vagrant at all. Vagrant will generate inventory files for each -virtual machine it manages, and use them for provisioning machines. Generated inventory files -are created adjacent to your Vagrantfile, named using the machine names set in your Vagrantfile. +is to not provide one to Vagrant at all. Vagrant will generate an inventory file encompassing +all of the virtual machine it manages, and use it for provisioning machines. The generated +inventory file is created adjacent to your Vagrantfile, named `vagrant_ansible_inventory`. -The second option is for situations where you'd like to have more than one virtual machine -in a single inventory file, perhaps leveraging more complex playbooks or inventory grouping. -If you provide the `ansible.inventory_path` option referencing a specific inventory file -dedicated to your Vagrant project, that one will be used instead of generating them. -Such an inventory file for use with Vagrant might look like: +The second option is for situations where you'd like to have more control over the inventory file, +perhaps leveraging more complex playbooks or inventory grouping. If you provide the +`ansible.inventory_path` option referencing a specific inventory file dedicated to your Vagrant +project, that one will be used instead of generating them. Such an inventory file for use with +Vagrant might look like: ``` [vagrant] @@ -153,8 +153,8 @@ by the sudo command. ansible.groups = { "group1" => ["machine1"], "group2" => ["machine2", "machine3"], - "all_groups:children" => ["group1", "group2"] + "all_groups:children" => ["group1", "group2", "group3"] } ``` - Note that only the current machine and its related groups will be added to the inventory file. + Note that undefined machines and groups are not added to the inventory. For example, `group3` in the above example would not be added to the inventory file. * `ansible.host_key_checking` can be set to `false` which will disable host key checking and prevent `"FAILED: (25, 'Inappropriate ioctl for device')"` errors from being reported during provisioner runs. The default value is `true`, which matches the default behavior of Ansible 1.2.1 and later. From 84308964e243f7f1bc6629c96211d0c49c29df91 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Sun, 2 Feb 2014 22:32:22 +0100 Subject: [PATCH 02/14] ansible generated inventory: deal with orphan VMs env.active_machines can potentiall return 'invalid' machines: - Ignore machines that are not declared in current Vagrantfile - Warn when machines are missing (it usually occurs when the VM is removed without `vagrant destroy` and some orphan metadata remains in .vagrant/machines/...) --- plugins/provisioners/ansible/provisioner.rb | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index 9a27ae3ca..d5c28f454 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -2,6 +2,7 @@ module VagrantPlugins module Ansible class Provisioner < Vagrant.plugin("2", :provisioner) def provision + @logger = Log4r::Logger.new("vagrant::provisioners::ansible") ssh = @machine.ssh_info # Connect with Vagrant user (unless --user or --private-key are @@ -71,6 +72,9 @@ module VagrantPlugins ssh = @machine.ssh_info + # Managed machines + inventory_machines = [] + generated_inventory_file = @machine.env.root_path.join("vagrant_ansible_inventory") @@ -78,8 +82,19 @@ module VagrantPlugins file.write("# Generated by Vagrant\n\n") @machine.env.active_machines.each do |am| - m = @machine.env.machine(*am) - file.write("#{m.name} ansible_ssh_host=#{m.ssh_info[:host]} ansible_ssh_port=#{m.ssh_info[:port]}\n") + begin + m = @machine.env.machine(*am) + if !m.ssh_info.nil? + file.write("#{m.name} ansible_ssh_host=#{m.ssh_info[:host]} ansible_ssh_port=#{m.ssh_info[:port]}\n") + inventory_machines << m + else + @logger.error("Auto-generated inventory: Impossible to get SSH information for machine '#{m.name} (#{m.provider_name})'. This machine should be recreated.") + # Let a note about this missing machine + file.write("# MISSING: '#{m.name}' machine was probably removed without using Vagrant. This machine should be recreated.\n") + end + rescue Vagrant::Errors::MachineNotFound => e + @logger.info("Auto-generated inventory: Skip machine '#{am[0]} (#{am[1]})', which is not configured for this Vagrant environment.") + end end # Write out groups information. Only includes groups and @@ -95,7 +110,7 @@ module VagrantPlugins included_groups << gname file.write("\n[#{gname}]\n") gmembers.each do |gm| - file.write("#{gm}\n") if @machine.env.active_machines.map { |m| m[0] }.include?(gm.to_sym) + file.write("#{gm}\n") if inventory_machines.map { |m| m.name }.include?(gm.to_sym) end end end From f564bf74109b95f1c6c5510b26ce3c210607de5d Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Sun, 2 Feb 2014 23:14:07 +0100 Subject: [PATCH 03/14] Ansible Groups: Accept single item as String Syntax errors in `ansible.groups` definition are not well handled: Error returned: undefined method `each' for "machine1":String (NoMethodError) Being tolerant here doesn't hurt and may avoid people get confused/annoyed. --- plugins/provisioners/ansible/provisioner.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index d5c28f454..33ccf3db3 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -104,6 +104,10 @@ module VagrantPlugins included_groups = [] config.groups.each_pair do |gname, gmembers| + # Require that gmembers be an array + # (easier to be tolerant and avoid error management of few value) + gmembers = [gmembers] if !gmembers.is_a?(Array) + if gname.end_with?(":children") groups_of_groups[gname] = gmembers else From 466cf58476816cb503f891fb185021cb3fe563ce Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Sun, 2 Feb 2014 23:28:04 +0100 Subject: [PATCH 04/14] ansible generated inventory: skip group variables Except ':children' for groups of groups, it is safer to avoid generating ':suffix' blocks. At the moment Ansible only supports (but doesn't recommend) group variables (:vars), and the Vagrant Ansible provisioner won't support this way to define variables. --- plugins/provisioners/ansible/provisioner.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index 33ccf3db3..0fea73fbd 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -110,7 +110,8 @@ module VagrantPlugins if gname.end_with?(":children") groups_of_groups[gname] = gmembers - else + elsif !gname.include?(':') + # skip group variables [:vars] and any other ":" suffixes included_groups << gname file.write("\n[#{gname}]\n") gmembers.each do |gm| From b723f0d43d25da25923496bc6600d69d07bf6015 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 3 Feb 2014 11:45:03 +0100 Subject: [PATCH 05/14] provisioners/ansible: Document new default limit - explain new default ansible.limit - shift `ansible.groups` part to Inventory section - change/add inventory examples --- .../source/v2/provisioning/ansible.html.md | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index f7fb36498..951099712 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -29,20 +29,54 @@ a single page of documentation. When using Ansible, it needs to know on which machines a given playbook should run. It does this by way of an inventory file which lists those machines. In the context of Vagrant, -there are two ways to approach working with inventory files. The first and simplest option -is to not provide one to Vagrant at all. Vagrant will generate an inventory file encompassing -all of the virtual machine it manages, and use it for provisioning machines. The generated -inventory file is created adjacent to your Vagrantfile, named `vagrant_ansible_inventory`. +there are two ways to approach working with inventory files. -The second option is for situations where you'd like to have more control over the inventory file, -perhaps leveraging more complex playbooks or inventory grouping. If you provide the -`ansible.inventory_path` option referencing a specific inventory file dedicated to your Vagrant -project, that one will be used instead of generating them. Such an inventory file for use with -Vagrant might look like: +The first and simplest option is to not provide one to Vagrant at all. Vagrant will generate an +inventory file encompassing all of the virtual machine it manages, and use it for provisioning +machines. The generated inventory file is created adjacent to your Vagrantfile, named +`vagrant_ansible_inventory`. + +The `ansible.groups` option can be used to pass a hash of group +names and group members to be included in the generated inventory file. For example: ``` -[vagrant] -192.168.111.222 +ansible.groups = { + "group1" => ["machine1"], + "group2" => ["machine2", "machine3"], + "all_groups:children" => ["group1", "group2", "group3"] +} +``` + +Note that undefined machines and groups are not added to the inventory. +For example, `group3` in the above example would not be added to the inventory file. + +A generated inventory might look like: + +``` +# Generated by Vagrant + +machine1 ansible_ssh_host=127.0.0.1 ansible_ssh_port=2200 +machine2 ansible_ssh_host=127.0.0.1 ansible_ssh_port=2201 + +[group1] +machine1 + +[group2] +machine2 + +[all_groups:children] +group1 +group2 +``` + +The second option is for situations where you'd like to have more control over the inventory file. +If you provide the `ansible.inventory_path` option referencing a specific inventory file dedicated +to your Vagrant project, that one will be used instead of generating it. + +Such an inventory file for use with Vagrant might look like: + +``` +default ansible_ssh_host=192.168.111.222 ``` Where the above IP address is one set in your Vagrantfile: @@ -51,6 +85,9 @@ Where the above IP address is one set in your Vagrantfile: config.vm.network :private_network, ip: "192.168.111.222" ``` +Note that machine names in `Vagrantfile` and `ansible.inventory_path` file should correspond, +unless you use `ansible.limit` option to reference the correct machines. + ## Playbook The second component of a successful Ansible provisioner setup is the Ansible playbook @@ -135,7 +172,7 @@ all of which get passed to the `ansible-playbook` command that ships with Ansibl * `ansible.sudo_user` can be set to a string containing a username on the guest who should be used by the sudo command. * `ansible.ask_sudo_pass` can be set to `true` to require Ansible to prompt for a sudo password. -* `ansible.limit` can be set to a string or an array of machines or groups from the inventory file to further narrow down which hosts are affected. +* `ansible.limit` can be set to a string or an array of machines or groups from the inventory file to further control which hosts are affected (e.g. useful to enable Ansible parallel execution). Note that as Vagrant 1.5, the machine name (taken from Vagrantfile) is set as default limit. * `ansible.verbose` can be set to increase Ansible's verbosity to obtain detailed logging: * `'v'`, verbose mode * `'vv'` @@ -147,14 +184,4 @@ by the sudo command. * `ansible.raw_arguments` can be set to an array of strings corresponding to a list of `ansible-playbook` arguments (e.g. `['--check', '-M /my/modules']`). It is an *unsafe wildcard* that can be used to apply Ansible options that are not (yet) supported by this Vagrant provisioner. Following precedence rules apply: * Any supported options (described above) will override conflicting `raw_arguments` value (e.g. `--tags` or `--start-at-task`) * Vagrant default user authentication can be overridden via `raw_arguments` (with custom values for `--user` and `--private-key`) -* `ansible.groups` can be used to pass a hash of group names and group members to be included in the generated inventory file. For example: - - ``` - ansible.groups = { - "group1" => ["machine1"], - "group2" => ["machine2", "machine3"], - "all_groups:children" => ["group1", "group2", "group3"] - } - ``` - Note that undefined machines and groups are not added to the inventory. For example, `group3` in the above example would not be added to the inventory file. * `ansible.host_key_checking` can be set to `false` which will disable host key checking and prevent `"FAILED: (25, 'Inappropriate ioctl for device')"` errors from being reported during provisioner runs. The default value is `true`, which matches the default behavior of Ansible 1.2.1 and later. From c2663f5d30f9d2ebd7a81eb41527fb62384f16fa Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Sun, 16 Feb 2014 11:20:00 +0100 Subject: [PATCH 06/14] provisioners/ansible: Fix Group Management - Support arbitrary depth of "groups of groups of ... groups" - Skip ':vars' suffix, but allow group names with ':' (yes, Ansible accepts this character) - Like for groups of machines, groups of groups can result "empty", but it is not an issue for Ansible. Recursive filter on the group tree is a bit hard to implement, and don't brind real added value at Vagrant level. --- plugins/provisioners/ansible/provisioner.rb | 30 +++++++++---------- .../source/v2/provisioning/ansible.html.md | 6 ++-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index 0fea73fbd..de5589e67 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -73,7 +73,7 @@ module VagrantPlugins ssh = @machine.ssh_info # Managed machines - inventory_machines = [] + inventory_machines = {} generated_inventory_file = @machine.env.root_path.join("vagrant_ansible_inventory") @@ -86,7 +86,7 @@ module VagrantPlugins m = @machine.env.machine(*am) if !m.ssh_info.nil? file.write("#{m.name} ansible_ssh_host=#{m.ssh_info[:host]} ansible_ssh_port=#{m.ssh_info[:port]}\n") - inventory_machines << m + inventory_machines[m.name] = m else @logger.error("Auto-generated inventory: Impossible to get SSH information for machine '#{m.name} (#{m.provider_name})'. This machine should be recreated.") # Let a note about this missing machine @@ -97,11 +97,12 @@ module VagrantPlugins end end - # Write out groups information. Only includes groups and - # machines which have been defined, otherwise Ansible will - # complain. + # Write out groups information. + # All defined groups will be included, but only supported + # machines and defined child groups will be included. + # Group variables are intentionally skipped. groups_of_groups = {} - included_groups = [] + defined_groups = [] config.groups.each_pair do |gname, gmembers| # Require that gmembers be an array @@ -110,22 +111,21 @@ module VagrantPlugins if gname.end_with?(":children") groups_of_groups[gname] = gmembers - elsif !gname.include?(':') - # skip group variables [:vars] and any other ":" suffixes - included_groups << gname + defined_groups << gname.sub(/:children$/, '') + elsif !gname.include?(':vars') + defined_groups << gname file.write("\n[#{gname}]\n") gmembers.each do |gm| - file.write("#{gm}\n") if inventory_machines.map { |m| m.name }.include?(gm.to_sym) + file.write("#{gm}\n") if inventory_machines.include?(gm.to_sym) end end end + defined_groups.uniq! groups_of_groups.each_pair do |gname, gmembers| - unless (included_groups & gmembers).empty? - file.write("\n[#{gname}]\n") - gmembers.each do |gm| - file.write("#{gm}\n") if included_groups.include?(gm) - end + file.write("\n[#{gname}]\n") + gmembers.each do |gm| + file.write("#{gm}\n") if defined_groups.include?(gm) end end end diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 951099712..7777ce7f2 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -37,7 +37,9 @@ machines. The generated inventory file is created adjacent to your Vagrantfile, `vagrant_ansible_inventory`. The `ansible.groups` option can be used to pass a hash of group -names and group members to be included in the generated inventory file. For example: +names and group members to be included in the generated inventory file. Group variables +are intentionally not supported, as this practice is not recommended. +For example: ``` ansible.groups = { @@ -47,7 +49,7 @@ ansible.groups = { } ``` -Note that undefined machines and groups are not added to the inventory. +Note that unmanaged machines and undefined groups are not added to the inventory. For example, `group3` in the above example would not be added to the inventory file. A generated inventory might look like: From 709f3f4e6f847690447bb3ecf4cd6451132f930a Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Sun, 16 Feb 2014 11:39:15 +0100 Subject: [PATCH 07/14] provisioners/ansible: Change --limit behaviours - The implicit default limit is always set - ansible.limit as an empty string won't disable the default limit, but will be passed as "--limit=" argument and ansible-playbook will return an error (provided host list is empty) --- plugins/provisioners/ansible/provisioner.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index de5589e67..d10fad7b8 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -11,17 +11,13 @@ module VagrantPlugins # TODO: multiple private key support options = %W[--private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] + # By default we limit by the current machine. + # This can be overridden by the limit config option. + options << "--limit=#{@machine.name}" + # Joker! Not (yet) supported arguments can be passed this way. options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments - # By default we limit by the current machine. This can be - # overriden by the limit config option. - limit_option = if config.limit == nil - "--limit=#{@machine.name}" - elsif not config.limit.empty? - "--limit=#{as_list_argument(config.limit)}" - end - # Append Provisioner options (highest precedence): options << "--inventory-file=#{self.setup_inventory_file}" options << "--extra-vars=#{self.get_extra_vars_argument}" if config.extra_vars @@ -31,7 +27,7 @@ module VagrantPlugins options << "--ask-sudo-pass" if config.ask_sudo_pass options << "--tags=#{as_list_argument(config.tags)}" if config.tags options << "--skip-tags=#{as_list_argument(config.skip_tags)}" if config.skip_tags - options << limit_option if limit_option + options << "--limit=#{as_list_argument(config.limit)}" if config.limit options << "--start-at-task=#{config.start_at_task}" if config.start_at_task # Assemble the full ansible-playbook command From 17a4d75fd583d9238b43685579840b493072b93f Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 17 Feb 2014 22:34:38 +0100 Subject: [PATCH 08/14] Ansible: Try to document the limit breaking change --- website/docs/source/v2/provisioning/ansible.html.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 7777ce7f2..3c28b260b 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -129,7 +129,6 @@ Vagrant.configure("2") do |config| end ``` -This causes Vagrant to run the `playbook.yml` playbook against all hosts in the inventory file. Since an Ansible playbook can include many files, you may also collect the related files in a directory structure like this: @@ -153,6 +152,13 @@ Vagrant.configure("2") do |config| end ``` +Vagrant will try to run the `playbook.yml` playbook against all machines defined in your Vagrantfile. + +**Backward Compatibility Note**: + +Up to Vagrant 1.4, the Ansible provisioner could potentially connect (multiple times) to all hosts from the inventory file. +This behaviour is still possible by setting `ansible.limit = 'all'` (see more details below). + ## Additional Options The Ansible provisioner also includes a number of additional options that can be set, @@ -174,7 +180,9 @@ all of which get passed to the `ansible-playbook` command that ships with Ansibl * `ansible.sudo_user` can be set to a string containing a username on the guest who should be used by the sudo command. * `ansible.ask_sudo_pass` can be set to `true` to require Ansible to prompt for a sudo password. -* `ansible.limit` can be set to a string or an array of machines or groups from the inventory file to further control which hosts are affected (e.g. useful to enable Ansible parallel execution). Note that as Vagrant 1.5, the machine name (taken from Vagrantfile) is set as default limit. +* `ansible.limit` can be set to a string or an array of machines or groups from the inventory file to further control which hosts are affected. Note that: + * As Vagrant 1.5, the machine name (taken from Vagrantfile) is set as **default limit** to ensure that `vagrant provision` steps only affect the expected machine. Setting `ansible.limit` will override this default. + * Setting `ansible.limit = 'all'` can be used to make Ansible connects to all machines from the inventory file. * `ansible.verbose` can be set to increase Ansible's verbosity to obtain detailed logging: * `'v'`, verbose mode * `'vv'` From 74c4ae06c1a7adf445248d0ea969048737f3053f Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 17 Feb 2014 22:36:46 +0100 Subject: [PATCH 09/14] Ansible Docs: Tip about Parallel Multi-Machine --- .../source/v2/provisioning/ansible.html.md | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 3c28b260b..606ae451c 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -195,3 +195,28 @@ by the sudo command. * Any supported options (described above) will override conflicting `raw_arguments` value (e.g. `--tags` or `--start-at-task`) * Vagrant default user authentication can be overridden via `raw_arguments` (with custom values for `--user` and `--private-key`) * `ansible.host_key_checking` can be set to `false` which will disable host key checking and prevent `"FAILED: (25, 'Inappropriate ioctl for device')"` errors from being reported during provisioner runs. The default value is `true`, which matches the default behavior of Ansible 1.2.1 and later. + +## Tips and Tricks + +### Ansible Parallel Execution + +Vagrant is designed to provision [multi-machine environments](/v2/multi-machine) in sequence, but the following configuration pattern can be used to take advantage of Ansible parallelism: + +``` + config.vm.define 'machine2' do |machine| + machine.vm.hostname = 'machine2' + machine.vm.network "private_network", ip: "192.168.77.22" + end + + config.vm.define 'machine1' do |machine| + machine.vm.hostname = 'machine1' + machine.vm.network "private_network", ip: "192.168.77.21" + + machine.vm.provision :ansible do |ansible| + ansible.playbook = "playbook.yml" + + # Disable default limit (required with Vagrant 1.5+) + ansible.limit = 'all' + end + end +``` \ No newline at end of file From d5055c6252299fb0bb68eab3da7be8bbdb1a4948 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 24 Feb 2014 16:47:10 +0100 Subject: [PATCH 10/14] provisioners/ansible: improve `inventory_path` doc Related to discussion held in #3004. --- website/docs/source/v2/provisioning/ansible.html.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 606ae451c..eb10b796d 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -28,7 +28,7 @@ a single page of documentation. ## Inventory File When using Ansible, it needs to know on which machines a given playbook should run. It does -this by way of an inventory file which lists those machines. In the context of Vagrant, +this by way of an [inventory](http://docs.ansible.com/intro_inventory.html) file which lists those machines. In the context of Vagrant, there are two ways to approach working with inventory files. The first and simplest option is to not provide one to Vagrant at all. Vagrant will generate an @@ -71,11 +71,10 @@ group1 group2 ``` -The second option is for situations where you'd like to have more control over the inventory file. -If you provide the `ansible.inventory_path` option referencing a specific inventory file dedicated -to your Vagrant project, that one will be used instead of generating it. +The second option is for situations where you'd like to have more control over the inventory management. +With the `ansible.inventory_path` option, you can reference a specific inventory resource (e.g. a static inventory file, a [dynamic inventory script](http://docs.ansible.com/intro_dynamic_inventory.html) or even [multiple inventories stored in the same directory](http://docs.ansible.com/intro_dynamic_inventory.html#using-multiple-inventory-sources)). Vagrant will then use this inventory information instead of generating it. -Such an inventory file for use with Vagrant might look like: +A very simple inventory file for use with Vagrant might look like: ``` default ansible_ssh_host=192.168.111.222 From 1cd2fe56a0cbcf65196d86fce215d48019e29b51 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 24 Feb 2014 16:52:38 +0100 Subject: [PATCH 11/14] ansible: generate inventory in .vagrant/... --- plugins/provisioners/ansible/provisioner.rb | 5 +++-- website/docs/source/v2/provisioning/ansible.html.md | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index d10fad7b8..f665fdb4a 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -71,8 +71,9 @@ module VagrantPlugins # Managed machines inventory_machines = {} - generated_inventory_file = - @machine.env.root_path.join("vagrant_ansible_inventory") + generated_inventory_dir = @machine.env.local_data_path.join(File.join(%w(provisioners ansible inventory))) + FileUtils.mkdir_p(generated_inventory_dir) unless File.directory?(generated_inventory_dir) + generated_inventory_file = generated_inventory_dir.join('vagrant_ansible_inventory') generated_inventory_file.open('w') do |file| file.write("# Generated by Vagrant\n\n") diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index eb10b796d..cf0d5d067 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -33,8 +33,7 @@ there are two ways to approach working with inventory files. The first and simplest option is to not provide one to Vagrant at all. Vagrant will generate an inventory file encompassing all of the virtual machine it manages, and use it for provisioning -machines. The generated inventory file is created adjacent to your Vagrantfile, named -`vagrant_ansible_inventory`. +machines. The generated inventory file is stored as part of your local Vagrant environment in `.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory`. The `ansible.groups` option can be used to pass a hash of group names and group members to be included in the generated inventory file. Group variables From f83f863d4dc5255c788c307ceb4874a34e77305f Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 24 Feb 2014 17:02:39 +0100 Subject: [PATCH 12/14] website/docs: Update Ansible URLs --- website/docs/source/v2/provisioning/ansible.html.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index cf0d5d067..4c2b09950 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -8,7 +8,7 @@ sidebar_current: "provisioning-ansible" **Provisioner name: `"ansible"`** The ansible provisioner allows you to provision the guest using -[Ansible](http://ansible.cc) playbooks. +[Ansible](http://ansible.com) playbooks. Ansible playbooks are [YAML](http://en.wikipedia.org/wiki/YAML) documents that comprise the set of steps to be orchestrated on one or more machines. This documentation @@ -92,9 +92,9 @@ unless you use `ansible.limit` option to reference the correct machines. The second component of a successful Ansible provisioner setup is the Ansible playbook which contains the steps that should be run on the guest. Ansible's -[playbook documentation](http://ansible.cc/docs/playbooks.html) goes into great +[playbook documentation](http://docs.ansible.com/playbooks.html) goes into great detail on how to author playbooks, and there are a number of -[best practices](http://ansible.cc/docs/bestpractices.html) that can be applied to use +[best practices](http://docs.ansible.com/playbooks_best_practices.html) that can be applied to use Ansible's powerful features effectively. A playbook that installs and starts (or restarts if it was updated) the NTP daemon via YUM looks like: @@ -112,7 +112,7 @@ if it was updated) the NTP daemon via YUM looks like: ``` You can of course target other operating systems that don't have YUM by changing the -playbook tasks. Ansible ships with a number of [modules](http://ansible.cc/docs/modules.html) +playbook tasks. Ansible ships with a number of [modules](http://docs.ansible.com/modules.html) that make running otherwise tedious tasks dead simple. ## Running Ansible From 84eb0d972c4751844895523f7805a562e8506ca7 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Tue, 25 Feb 2014 06:57:10 +0100 Subject: [PATCH 13/14] Ansible Docs: Tip to ship a local `ansible.cfg` Hint motivated by misleading situations reported in #2302. --- website/docs/source/v2/provisioning/ansible.html.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 4c2b09950..868258c02 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -217,4 +217,12 @@ Vagrant is designed to provision [multi-machine environments](/v2/multi-machine) ansible.limit = 'all' end end -``` \ No newline at end of file +``` + +### Provide a local `ansible.cfg` file + +Certain settings in Ansible are (only) adjustable via a [configuration file](http://docs.ansible.com/intro_configuration.html), and you might want to ship such a file in your Vagrant project. + +As `ansible-playbook` command looks for local [`ansible.cfg`] configuration file in its *current directory* (but not in the directory that contains the main playbook), you have to store this file adjacent to your Vagrantfile. + +Note that it is also possible to reference an Ansible configuration file via `ANSIBLE_CONFIG` environment variable, if you want to be flexible about the location of this file. From 49b5b6515d355fbcf47052f244df3b2011e3d7e9 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Tue, 25 Feb 2014 06:59:39 +0100 Subject: [PATCH 14/14] Ansible Docs: Tip about wrong remote user Hint motivated by misleading situations reported in #2710. --- .../source/v2/provisioning/ansible.html.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 868258c02..4f2ff5185 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -226,3 +226,22 @@ Certain settings in Ansible are (only) adjustable via a [configuration file](htt As `ansible-playbook` command looks for local [`ansible.cfg`] configuration file in its *current directory* (but not in the directory that contains the main playbook), you have to store this file adjacent to your Vagrantfile. Note that it is also possible to reference an Ansible configuration file via `ANSIBLE_CONFIG` environment variable, if you want to be flexible about the location of this file. + +### Why Ansible provisioner does connect with a wrong user ? + +It is good to know that following Ansible settings always override `config.ssh.username` option defined in [Vagrant SSH Settings](/v2/vagrantfile/ssh_settings.html): + +* `ansible_ssh_user` variable +* `remote_user` (or `user`) play attribute +* `remote_user` task attribute + +Be aware that copying snippets from Ansible documentation might lead to this problem, as `root` is used as remote user in many [examples](http://docs.ansible.com/playbooks_intro.html#hosts-and-users). + +Example of SSH error (with `vvv` log level), where an undefined remote user `xyz` has replaced `vagrant`: + +``` +TASK: [my_role | do something] ***************** +<127.0.0.1> ESTABLISH CONNECTION FOR USER: xyz +<127.0.0.1> EXEC ['ssh', '-tt', '-vvv', '-o', 'ControlMaster=auto',... +fatal: [ansible-devbox] => SSH encountered an unknown error. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue. +```