Use host vars files for kolla ansible inventory

Kayobe writes out several host variables to the Kolla ansible inventory
files, etc/kolla/inventory/seed and etc/kolla/inventory/overcloud. These
include ansible_host, and network interfaces such as api_interface,
ironic_dnsmasq_interface, etc.

In Ansible, these should have a higher precedence than the kolla ansible
group variables in ansible/group_vars/all.yml that set the defaults.
However, in Ansible 2.4+, if the host has the same name as a group that
it is in, the group variables now take precedence, meaning that it is
not possible to override them.

This was observed when using the kayobe-config-dev repo for testing,
where the seed host is in the seed group.

Admittedly ansible does tell you not to do this: [WARNING]:
Found both group and host with same name: localhost

The solution used here is to use a separate host_vars file for each
host. Alternatively we could enforce that hostnames and groups do not
overlap.

Change-Id: I349c8279d85a591689ac8108bce14d96889440fe
Story: 2004418
Task: 28065
This commit is contained in:
Mark Goddard 2018-11-22 18:21:28 +00:00
parent 62aa5d015f
commit 8dc7ba7889
10 changed files with 167 additions and 31 deletions

View File

@ -1,4 +1,31 @@
---
# NOTE: We're not looping over the two inventory files to avoid having the file
# content displayed in the ansible-playbook output.
- name: Check whether the legacy Kolla overcloud inventory files exist
stat:
path: "{{ item }}"
get_attributes: no
get_checksum: no
get_mime: no
register: inventory_stat
with_items:
- "{{ kolla_seed_inventory_path }}"
- "{{ kolla_overcloud_inventory_path }}"
loop_control:
label: "{{ item | basename }}"
- name: Ensure the legacy Kolla overcloud inventory file is absent
file:
path: "{{ item.item }}"
state: absent
with_items: "{{ inventory_stat.results }}"
when:
- item.stat.exists
- item.stat.isreg
loop_control:
label: "{{ item.item | basename }}"
- name: Ensure the Kolla Ansible configuration directories exist
file:
path: "{{ item }}"
@ -9,7 +36,8 @@
become: True
with_items:
- "{{ kolla_config_path }}"
- "{{ kolla_config_path }}/inventory"
- "{{ kolla_seed_inventory_path }}/host_vars"
- "{{ kolla_overcloud_inventory_path }}/host_vars"
- "{{ kolla_node_custom_config_path }}"
- name: Ensure the Kolla global configuration file exists
@ -18,21 +46,42 @@
dest: "{{ kolla_config_path }}/globals.yml"
mode: 0640
# NOTE: We're not looping over the two inventory files to avoid having the file
# content displayed in the ansible-playbook output.
- name: Ensure the Kolla seed inventory file exists
copy:
content: "{{ kolla_seed_inventory }}"
dest: "{{ kolla_config_path }}/inventory/seed"
dest: "{{ kolla_seed_inventory_path }}/hosts"
mode: 0640
- name: Ensure the Kolla seed host vars files exist
template:
src: host-vars.j2
dest: "{{ kolla_seed_inventory_path }}/host_vars/{{ host }}"
mode: 0640
with_inventory_hostnames: "seed"
vars:
host_vars: "{{ kolla_seed_inventory_pass_through_host_vars }}"
host_vars_map: "{{ kolla_seed_inventory_pass_through_host_vars_map }}"
loop_control:
loop_var: host
- name: Ensure the Kolla overcloud inventory file exists
copy:
content: "{{ kolla_overcloud_inventory }}"
dest: "{{ kolla_config_path }}/inventory/overcloud"
dest: "{{ kolla_overcloud_inventory_path }}/hosts"
mode: 0640
- name: Ensure the Kolla overcloud host vars files exist
template:
src: host-vars.j2
dest: "{{ kolla_overcloud_inventory_path }}/host_vars/{{ host }}"
mode: 0640
with_inventory_hostnames: "{{ kolla_overcloud_top_level_groups }}"
vars:
host_vars: "{{ kolla_overcloud_inventory_pass_through_host_vars }}"
host_vars_map: "{{ kolla_overcloud_inventory_pass_through_host_vars_map }}"
loop_control:
loop_var: host
- name: Ensure the Kolla passwords file exists
kolla_passwords:
src: "{{ kolla_ansible_passwords_path }}"

View File

@ -0,0 +1,7 @@
---
{% for hv_name in host_vars %}
{% set host_hv=hostvars[host] %}
{% if hv_name in host_hv %}
{{ host_vars_map.get(hv_name, hv_name) }}: {{ host_hv[hv_name] | to_json }}
{% endif %}
{% endfor %}

View File

@ -4,26 +4,17 @@
# Components define groups of services, e.g. nova or ironic.
# Services define single containers, e.g. nova-compute or ironic-api.
{% set top_level_groups = kolla_overcloud_inventory_top_level_group_map.values() |
selectattr('groups', 'defined') |
map(attribute='groups') |
sum(start=[]) |
unique |
list %}
{% for group in top_level_groups %}
{% for group in kolla_overcloud_top_level_groups %}
# Top level {{ group }} group.
[{{ group }}]
# These hostnames must be resolvable from your deployment host
{% for host in groups.get(group, []) %}
{% set host_hv=hostvars[host] %}
{{ host }}{% for hv_name in kolla_overcloud_inventory_pass_through_host_vars %}{% if hv_name in host_hv %} {{ kolla_overcloud_inventory_pass_through_host_vars_map.get(hv_name, hv_name) }}='{{ host_hv[hv_name] | to_json }}'{% endif %}{% endfor %}
{{ host }}
{% endfor %}
{% endfor %}
[overcloud:children]
{% for group in top_level_groups %}
{% for group in kolla_overcloud_top_level_groups %}
{{ group }}
{% endfor %}

View File

@ -1,9 +1,7 @@
# Simple inventory for bootstrapping Kolla seed node.
[seed]
{% for seed in groups.get('seed', []) %}
{% set seed_hv=hostvars[seed] %}
{{ seed }}{% for hv_name in kolla_seed_inventory_pass_through_host_vars %}{% if hv_name in seed_hv %} {{ kolla_seed_inventory_pass_through_host_vars_map.get(hv_name, hv_name) }}='{{ seed_hv[hv_name] | to_json }}'{% endif %}{% endfor %}
{{ seed }}
{% endfor %}
[seed:vars]

View File

@ -1,7 +1,5 @@
---
# TODO:
# - Check inventory file.
# - Add hosts to inventory.
# - Seed custom inventory
# - Overcloud custom inventory
# - Group map

View File

@ -123,7 +123,9 @@
path: "{{ temp_path ~ '/etc/kolla/inventory/' ~ item }}"
with_items:
- seed
- seed/host_vars
- overcloud
- overcloud/host_vars
register: inventory_stat
- name: Validate inventory files

View File

@ -371,7 +371,7 @@
- name: Check whether inventory files exist
stat:
path: "{{ temp_path ~ '/etc/kolla/inventory/' ~ item }}"
path: "{{ temp_path ~ '/etc/kolla/inventory/' ~ item ~ '/hosts' }}"
with_items:
- seed
- overcloud
@ -398,7 +398,7 @@
assert:
that: item in inventory_lines
with_items:
- test-seed ansible_host='"1.2.3.4"' api_interface='"eth0"' bifrost_network_interface='"eth1"'
- test-seed
- name: Validate overcloud inventory file contents
vars:
@ -406,8 +406,72 @@
assert:
that: item in inventory_lines
with_items:
- test-controller ansible_host='"1.2.3.5"' network_interface='"eth0"' api_interface='"eth2"' storage_interface='"eth3"' cluster_interface='"eth4"' provision_interface='"eth8"' ironic_dnsmasq_interface='"eth9"' dns_interface='"eth5"' tunnel_interface='"eth10"' kolla_external_vip_interface='"eth1"' neutron_external_interface='"eth6,eth7"' neutron_bridge_name='"br0,br1"'
- test-compute ansible_host='"1.2.3.6"' network_interface='"eth0"' api_interface='"eth2"' storage_interface='"eth3"' tunnel_interface='"eth6"' neutron_external_interface='"eth4,eth5"' neutron_bridge_name='"br0,br1"'
- test-controller
- test-compute
- name: Check whether inventory host vars files exist
stat:
path: "{{ temp_path ~ '/etc/kolla/inventory/' ~ item }}"
with_items:
- seed/host_vars/test-seed
- overcloud/host_vars/test-controller
- overcloud/host_vars/test-compute
register: host_vars_stat
- name: Validate inventory host vars files
assert:
that:
- item.stat.exists
- item.stat.size > 0
msg: >
Inventory file {{ item.item }} was not found.
with_items: "{{ host_vars_stat.results }}"
- name: Read inventory host vars files
slurp:
src: "{{ item.stat.path }}"
with_items: "{{ host_vars_stat.results }}"
register: host_vars_slurp
- name: Validate inventory host vars file contents
assert:
that:
- host_vars_content is defined
- host_vars_content == item.1
with_together:
- "{{ host_vars_slurp.results }}"
- "{{ expected_contents }}"
vars:
host_vars_content: "{{ item.0.content | b64decode }}"
expected_contents:
- |
---
ansible_host: "1.2.3.4"
api_interface: "eth0"
bifrost_network_interface: "eth1"
- |
---
ansible_host: "1.2.3.5"
network_interface: "eth0"
api_interface: "eth2"
storage_interface: "eth3"
cluster_interface: "eth4"
provision_interface: "eth8"
ironic_dnsmasq_interface: "eth9"
dns_interface: "eth5"
tunnel_interface: "eth10"
kolla_external_vip_interface: "eth1"
neutron_external_interface: "eth6,eth7"
neutron_bridge_name: "br0,br1"
- |
---
ansible_host: "1.2.3.6"
network_interface: "eth0"
api_interface: "eth2"
storage_interface: "eth3"
tunnel_interface: "eth6"
neutron_external_interface: "eth4,eth5"
neutron_bridge_name: "br0,br1"
always:
- name: Ensure the temporary directory is removed

View File

@ -51,6 +51,21 @@ kolla_overcloud_inventory_default: |
# of the top level, component, and service inventories.
kolla_overcloud_inventory: "{{ kolla_overcloud_inventory_custom or kolla_overcloud_inventory_default }}"
# List of names of all top level groups in the inventory.
kolla_overcloud_top_level_groups: >
{{ kolla_overcloud_inventory_top_level_group_map.values() |
selectattr('groups', 'defined') |
map(attribute='groups') |
sum(start=[]) |
unique |
list }}
# Path to the kolla ansible seed inventory directory.
kolla_seed_inventory_path: "{{ kolla_config_path }}/inventory/seed"
# Path to the kolla ansible overcloud inventory directory.
kolla_overcloud_inventory_path: "{{ kolla_config_path }}/inventory/overcloud"
###############################################################################
# Feature configuration.

View File

@ -87,8 +87,13 @@ def _validate_args(parsed_args, inventory_filename):
sys.exit(1)
inventory = _get_inventory_path(parsed_args, inventory_filename)
result = utils.is_readable_file(inventory)
result = utils.is_readable_dir(parsed_args.kolla_venv)
if not result["result"]:
# NOTE(mgoddard): Previously the inventory was a file, now it is a
# directory to allow us to support inventory host_vars. Support both
# formats for now.
result_f = utils.is_readable_file(inventory)
if not result_f["result"]:
LOG.error("Kolla inventory %s is invalid: %s",
inventory, result["message"])
sys.exit(1)

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Fixes an issue where if a host has the same name as a group that it is in,
configuration of kolla ansible inventory host variables could fail to
override the defaults. See `story 2004418
<https://storyboard.openstack.org/#!/story/2004418>`__ for details.