commit
dde7f4697f
|
@ -55,6 +55,8 @@ IMPROVEMENTS:
|
|||
scripts [GH-6185]
|
||||
- provisioners/shell: add `env` option [GH-6588, GH-6516]
|
||||
- provisioners/ansible+ansible_local: add support for ansible-galaxy [GH-2718]
|
||||
- provisioners/ansible+ansible_local: add support for group and host variables
|
||||
in the generated inventory [GH-6619]
|
||||
- provisioners/ansible: add support for WinRM settings [GH-5086]
|
||||
- provisioners/ansible: add new `force_remote_user` option to control whether
|
||||
`ansible_ssh_user` parameter should be applied or not [GH-6348]
|
||||
|
|
|
@ -9,6 +9,7 @@ module VagrantPlugins
|
|||
attr_accessor :galaxy_role_file
|
||||
attr_accessor :galaxy_roles_path
|
||||
attr_accessor :galaxy_command
|
||||
attr_accessor :host_vars
|
||||
attr_accessor :groups
|
||||
attr_accessor :inventory_path
|
||||
attr_accessor :limit
|
||||
|
@ -27,6 +28,7 @@ module VagrantPlugins
|
|||
@galaxy_role_file = UNSET_VALUE
|
||||
@galaxy_roles_path = UNSET_VALUE
|
||||
@galaxy_command = UNSET_VALUE
|
||||
@host_vars = UNSET_VALUE
|
||||
@groups = UNSET_VALUE
|
||||
@inventory_path = UNSET_VALUE
|
||||
@limit = UNSET_VALUE
|
||||
|
@ -46,6 +48,7 @@ module VagrantPlugins
|
|||
@galaxy_role_file = nil if @galaxy_role_file == UNSET_VALUE
|
||||
@galaxy_roles_path = nil if @galaxy_roles_path == UNSET_VALUE
|
||||
@galaxy_command = GALAXY_COMMAND_DEFAULT if @galaxy_command == UNSET_VALUE
|
||||
@host_vars = {} if @host_vars == UNSET_VALUE
|
||||
@groups = {} if @groups == UNSET_VALUE
|
||||
@inventory_path = nil if @inventory_path == UNSET_VALUE
|
||||
@limit = nil if @limit == UNSET_VALUE
|
||||
|
|
|
@ -70,11 +70,29 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
def get_inventory_host_vars_string(machine_name)
|
||||
# In Ruby, Symbol and String values are different, but
|
||||
# Vagrant has to unify them for better user experience.
|
||||
vars = config.host_vars[machine_name.to_sym]
|
||||
if !vars
|
||||
vars = config.host_vars[machine_name.to_s]
|
||||
end
|
||||
s = nil
|
||||
if vars.is_a?(Hash)
|
||||
s = vars.each.collect{ |k, v| "#{k}=#{v}" }.join(" ")
|
||||
elsif vars.is_a?(Array)
|
||||
s = vars.join(" ")
|
||||
elsif vars.is_a?(String)
|
||||
s = vars
|
||||
end
|
||||
if s and !s.empty? then s else nil end
|
||||
end
|
||||
|
||||
def generate_inventory
|
||||
inventory = "# Generated by Vagrant\n\n"
|
||||
|
||||
# This "abstract" step must fill the @inventory_machines list
|
||||
# and return the list of supported host(s)
|
||||
# This "abstract" step must fill the @inventory_machines list
|
||||
# and return the list of supported host(s)
|
||||
inventory += generate_inventory_machines
|
||||
|
||||
inventory += generate_inventory_groups
|
||||
|
@ -88,21 +106,31 @@ module VagrantPlugins
|
|||
# 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.
|
||||
def generate_inventory_groups
|
||||
groups_of_groups = {}
|
||||
defined_groups = []
|
||||
group_vars = {}
|
||||
inventory_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.is_a?(Symbol)
|
||||
gname = gname.to_s
|
||||
end
|
||||
|
||||
if gmembers.is_a?(String)
|
||||
gmembers = gmembers.split(/\s+/)
|
||||
elsif gmembers.is_a?(Hash)
|
||||
gmembers = gmembers.each.collect{ |k, v| "#{k}=#{v}" }
|
||||
elsif !gmembers.is_a?(Array)
|
||||
gmembers = []
|
||||
end
|
||||
|
||||
if gname.end_with?(":children")
|
||||
groups_of_groups[gname] = gmembers
|
||||
defined_groups << gname.sub(/:children$/, '')
|
||||
elsif !gname.include?(':vars')
|
||||
elsif gname.end_with?(":vars")
|
||||
group_vars[gname] = gmembers
|
||||
else
|
||||
defined_groups << gname
|
||||
inventory_groups += "\n[#{gname}]\n"
|
||||
gmembers.each do |gm|
|
||||
|
@ -119,6 +147,12 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
|
||||
group_vars.each_pair do |gname, gmembers|
|
||||
if defined_groups.include?(gname.sub(/:vars$/, ""))
|
||||
inventory_groups += "\n[#{gname}]\n" + gmembers.join("\n") + "\n"
|
||||
end
|
||||
end
|
||||
|
||||
return inventory_groups
|
||||
end
|
||||
|
||||
|
|
|
@ -128,6 +128,8 @@ module VagrantPlugins
|
|||
else
|
||||
machines += "#{machine_name}\n"
|
||||
end
|
||||
host_vars = get_inventory_host_vars_string(machine_name)
|
||||
machines.sub!(/\n$/, " #{host_vars}\n") if host_vars
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -151,12 +151,15 @@ module VagrantPlugins
|
|||
# Call only once the SSH and WinRM info computation
|
||||
# Note that machines configured with WinRM communicator, also have a "partial" ssh_info.
|
||||
m_ssh_info = m.ssh_info
|
||||
host_vars = get_inventory_host_vars_string(m.name)
|
||||
if m.config.vm.communicator == :winrm
|
||||
m_winrm_net_info = CommunicatorWinRM::Helper.winrm_info(m) # can raise a WinRMNotReady exception...
|
||||
machines += get_inventory_winrm_machine(m, m_winrm_net_info)
|
||||
machines.sub!(/\n$/, " #{host_vars}\n") if host_vars
|
||||
@inventory_machines[m.name] = m
|
||||
elsif !m_ssh_info.nil?
|
||||
machines += get_inventory_ssh_machine(m, m_ssh_info)
|
||||
machines.sub!(/\n$/, " #{host_vars}\n") if host_vars
|
||||
@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.")
|
||||
|
|
|
@ -30,6 +30,7 @@ describe VagrantPlugins::Ansible::Config::Host do
|
|||
galaxy_roles_path
|
||||
groups
|
||||
host_key_checking
|
||||
host_vars
|
||||
inventory_path
|
||||
limit
|
||||
playbook
|
||||
|
@ -62,6 +63,7 @@ describe VagrantPlugins::Ansible::Config::Host do
|
|||
expect(subject.tags).to be_nil
|
||||
expect(subject.skip_tags).to be_nil
|
||||
expect(subject.start_at_task).to be_nil
|
||||
expect(subject.host_vars).to eq({})
|
||||
expect(subject.groups).to eq({})
|
||||
expect(subject.host_key_checking).to be_false
|
||||
expect(subject.raw_arguments).to be_nil
|
||||
|
|
|
@ -234,42 +234,110 @@ VF
|
|||
end
|
||||
end
|
||||
|
||||
describe "with host_vars option" do
|
||||
it_should_create_and_use_generated_inventory
|
||||
|
||||
it "adds host variables (given in Hash format) to the generated inventory" do
|
||||
config.host_vars = {
|
||||
machine1: {"http_port" => 80, "maxRequestsPerChild" => 808}
|
||||
}
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
inventory_content = File.read(generated_inventory_file)
|
||||
expect(inventory_content).to match("^" + Regexp.quote(machine.name) + ".+http_port=80 maxRequestsPerChild=808")
|
||||
}
|
||||
end
|
||||
|
||||
it "adds host variables (given in Array format) to the generated inventory" do
|
||||
config.host_vars = {
|
||||
machine1: ["http_port=80", "maxRequestsPerChild=808"]
|
||||
}
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
inventory_content = File.read(generated_inventory_file)
|
||||
expect(inventory_content).to match("^" + Regexp.quote(machine.name) + ".+http_port=80 maxRequestsPerChild=808")
|
||||
}
|
||||
end
|
||||
|
||||
it "adds host variables (given in String format) to the generated inventory " do
|
||||
config.host_vars = {
|
||||
:machine1 => "http_port=80 maxRequestsPerChild=808"
|
||||
}
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
inventory_content = File.read(generated_inventory_file)
|
||||
expect(inventory_content).to match("^" + Regexp.quote(machine.name) + ".+http_port=80 maxRequestsPerChild=808")
|
||||
}
|
||||
end
|
||||
|
||||
it "retrieves the host variables by machine name, also in String format" do
|
||||
config.host_vars = {
|
||||
"machine1" => "http_port=80 maxRequestsPerChild=808"
|
||||
}
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
inventory_content = File.read(generated_inventory_file)
|
||||
expect(inventory_content).to match("^" + Regexp.quote(machine.name) + ".+http_port=80 maxRequestsPerChild=808")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
describe "with groups option" do
|
||||
it_should_create_and_use_generated_inventory
|
||||
|
||||
it "adds group sections to the generated inventory" do
|
||||
config.groups = {
|
||||
"group1" => "#{machine.name}",
|
||||
"group1:children" => 'bar',
|
||||
"group1" => "machine1",
|
||||
"group1:children" => 'bar group3',
|
||||
"group2" => [iso_env.machine_names[1]],
|
||||
"group3" => ["unknown", "#{machine.name}"],
|
||||
group4: [machine.name],
|
||||
"bar" => ["#{machine.name}", "group3"],
|
||||
"bar:children" => ["group1", "group2", "group3", "group4"],
|
||||
"bar:vars" => ["myvar=foo"],
|
||||
"bar:children" => ["group1", "group2", "group3", "group5"],
|
||||
}
|
||||
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
inventory_content = File.read(generated_inventory_file)
|
||||
|
||||
# Group variables are intentionally not supported in generated inventory
|
||||
expect(inventory_content).not_to match(/^\[.*:vars\]$/)
|
||||
|
||||
# Accept String instead of Array for group that contains a single item
|
||||
expect(inventory_content).to include("[group1]\n#{machine.name}\n")
|
||||
expect(inventory_content).to include("[group1:children]\nbar\n")
|
||||
# Accept String instead of Array for group member list
|
||||
expect(inventory_content).to include("[group1]\nmachine1\n\n")
|
||||
expect(inventory_content).to include("[group1:children]\nbar\ngroup3\n\n")
|
||||
|
||||
# Skip "lost" machines
|
||||
expect(inventory_content).to include("[group2]\n\n")
|
||||
|
||||
# Skip "unknown" machines
|
||||
expect(inventory_content).to include("[group3]\n#{machine.name}\n")
|
||||
expect(inventory_content).to include("[group3]\n#{machine.name}\n\n")
|
||||
|
||||
# Accept Symbol datatype for group names
|
||||
expect(inventory_content).to include("[group4]\n#{machine.name}\n\n")
|
||||
|
||||
# Don't mix group names and host names
|
||||
expect(inventory_content).to include("[bar]\n#{machine.name}\n")
|
||||
expect(inventory_content).to include("[bar]\n#{machine.name}\n\n")
|
||||
|
||||
# A group of groups only includes declared groups
|
||||
expect(inventory_content).not_to match(/^group4$/)
|
||||
expect(inventory_content).to include("[bar:children]\ngroup1\ngroup2\ngroup3\n")
|
||||
expect(inventory_content).not_to include("group5")
|
||||
expect(inventory_content).to match(Regexp.quote("[bar:children]\ngroup1\ngroup2\ngroup3\n") + "$")
|
||||
}
|
||||
end
|
||||
|
||||
it "adds group vars to the generated inventory" do
|
||||
config.groups = {
|
||||
"group1" => [machine.name],
|
||||
"group2" => [machine.name],
|
||||
"group3" => [machine.name],
|
||||
"group1:vars" => {"hashvar1" => "hashvalue1", "hashvar2" => "hashvalue2"},
|
||||
"group2:vars" => ["arrayvar1=arrayvalue1", "arrayvar2=arrayvalue2"],
|
||||
"group3:vars" => "stringvar1=stringvalue1 stringvar2=stringvalue2",
|
||||
}
|
||||
|
||||
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
|
||||
inventory_content = File.read(generated_inventory_file)
|
||||
|
||||
# Hash syntax
|
||||
expect(inventory_content).to include("[group1:vars]\nhashvar1=hashvalue1\nhashvar2=hashvalue2\n")
|
||||
|
||||
# Array syntax
|
||||
expect(inventory_content).to include("[group2:vars]\narrayvar1=arrayvalue1\narrayvar2=arrayvalue2\n")
|
||||
|
||||
# Single string syntax
|
||||
expect(inventory_content).to include("[group3:vars]\nstringvar1=stringvalue1\nstringvar2=stringvalue2\n")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,6 +31,23 @@ Some of these options are for advanced usage only and should not be used unless
|
|||
```
|
||||
These variables take the highest precedence over any other variables.
|
||||
|
||||
- `host_vars` (hash) - Set of inventory host variables to be included in the [auto-generated inventory file](http://docs.ansible.com/ansible/intro_inventory.html#host-variables).
|
||||
|
||||
Example:
|
||||
|
||||
```ruby
|
||||
ansible.host_vars = {
|
||||
"host1" => {"http_port" => 80,
|
||||
"maxRequestsPerChild" => 808},
|
||||
"host2" => {"http_port" => 303,
|
||||
"maxRequestsPerChild" => 909}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- This option has no effect when the `inventory_path` option is defined.
|
||||
|
||||
- `groups` (hash) - Set of inventory groups to be included in the [auto-generated inventory file](/v2/provisioning/ansible_intro.html).
|
||||
|
||||
Example:
|
||||
|
@ -41,6 +58,15 @@ Some of these options are for advanced usage only and should not be used unless
|
|||
"db" => ["vm3"]
|
||||
}
|
||||
```
|
||||
Example with [group variables](http://docs.ansible.com/ansible/intro_inventory.html#group-variables):
|
||||
|
||||
```ruby
|
||||
ansible.groups = {
|
||||
"atlanta" => ["host1", "host2"],
|
||||
"atlanta:vars" => {"ntp_server" => "ntp.atlanta.example.com",
|
||||
"proxy" => "proxy.atlanta.example.com"}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
|
|
|
@ -107,9 +107,39 @@ default ansible_connection=local
|
|||
|
||||
Note that the generated inventory file is uploaded to the guest VM in a subdirectory of [`tmp_path`](/v2/provisioning/ansible_local.html), e.g. `/tmp/vagrant-ansible/inventory/vagrant_ansible_local_inventory`.
|
||||
|
||||
**Host variables:**
|
||||
|
||||
As of Vagrant 1.8.0, the [`host_vars`](/v2/provisioning/ansible_common.html) option can be used to set [variables for individual hosts](http://docs.ansible.com/ansible/intro_inventory.html#host-variables) in the generated inventory file (see also the notes on group variables below).
|
||||
|
||||
```
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.define "host1"
|
||||
config.vm.define "host2"
|
||||
config.vm.provision "ansible" do |ansible|
|
||||
ansible.playbook = "playbook.yml"
|
||||
ansible.host_vars = {
|
||||
"host1" => {"http_port" => 80,
|
||||
"maxRequestsPerChild" => 808},
|
||||
"host2" => {"http_port" => 303,
|
||||
"maxRequestsPerChild" => 909}
|
||||
}
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Generated inventory:
|
||||
|
||||
```
|
||||
# Generated by Vagrant
|
||||
|
||||
host1 ansible_ssh_host=... http_port=80 maxRequestsPerChild=808
|
||||
host2 ansible_ssh_host=... http_port=303 maxRequestsPerChild=909
|
||||
```
|
||||
|
||||
**How to generate Inventory Groups:**
|
||||
|
||||
The [`groups`](/v2/provisioning/ansible_common.html) option can be used to pass a hash of group names and group members to be included in the generated inventory file.
|
||||
As of Vagrant 1.8.0, it is also possible to specify [group variables](http://docs.ansible.com/ansible/intro_inventory.html#group-variables).
|
||||
|
||||
With this configuration example:
|
||||
|
||||
|
@ -126,7 +156,9 @@ Vagrant.configure(2) do |config|
|
|||
ansible.groups = {
|
||||
"group1" => ["machine1"],
|
||||
"group2" => ["machine2"],
|
||||
"all_groups:children" => ["group1", "group2"]
|
||||
"all_groups:children" => ["group1", "group2"],
|
||||
"group1:vars" => {"variable1" => 9,
|
||||
"variable2" => "example"}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -149,22 +181,25 @@ machine2
|
|||
[all_groups:children]
|
||||
group1
|
||||
group2
|
||||
|
||||
[group1:vars]
|
||||
variable1=9
|
||||
variable2=example
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
- Prior to Vagrant 1.7.3, the `ansible_ssh_private_key_file` variable was not set in generated inventory, but passed as command line argument to `ansible-playbook` command.
|
||||
- The generation of group variables blocks (e.g. `[group1:vars]`) are intentionally not supported, as it is [not recommended to store group variables in the main inventory file](http://docs.ansible.com/intro_inventory.html#splitting-out-host-and-group-specific-data). A good practice is to store these group (or host) variables in `YAML` files stored in `group_vars/` or `host_vars/` directories in the playbook (or inventory) directory.
|
||||
- The generation of group variables blocks (e.g. `[group1:vars]`) is only possible since Vagrant 1.8.0. Note however that setting variables directly in the inventory is not the [preferred practice in Ansible](http://docs.ansible.com/intro_inventory.html#splitting-out-host-and-group-specific-data). If possible, group (or host) variables should be set in `YAML` files stored in the `group_vars/` or `host_vars/` directories in the playbook (or inventory) directory instead.
|
||||
- Unmanaged machines and undefined groups are not added to the inventory, to avoid useless Ansible errors (e.g. *unreachable host* or *undefined child group*)
|
||||
|
||||
For example, `machine3`, `group3` and `group1:vars` in the example below would not be added to the generated inventory file:
|
||||
For example, `machine3` and `group3` in the example below would not be added to the generated inventory file:
|
||||
|
||||
```
|
||||
ansible.groups = {
|
||||
"group1" => ["machine1"],
|
||||
"group2" => ["machine2", "machine3"],
|
||||
"all_groups:children" => ["group1", "group2", "group3"],
|
||||
"group1:vars" => { "variable1" => 9, "variable2" => "example" }
|
||||
"all_groups:children" => ["group1", "group2", "group3"]
|
||||
}
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in New Issue