diff --git a/changelogs/fragments/fix_yaml_inv_nulls.yml b/changelogs/fragments/fix_yaml_inv_nulls.yml new file mode 100644 index 0000000000..f9e831a367 --- /dev/null +++ b/changelogs/fragments/fix_yaml_inv_nulls.yml @@ -0,0 +1,2 @@ +bugfixes: + - correctly handle yaml inventory files when entries are null dicts https://github.com/ansible/ansible/issues/41692 diff --git a/lib/ansible/cli/inventory.py b/lib/ansible/cli/inventory.py index 4c7d4dfd49..78e562c497 100644 --- a/lib/ansible/cli/inventory.py +++ b/lib/ansible/cli/inventory.py @@ -42,6 +42,7 @@ INTERNAL_VARS = frozenset(['ansible_diff_mode', 'ansible_playbook_python', 'ansible_run_tags', 'ansible_skip_tags', + 'ansible_verbosity', 'ansible_version', 'inventory_dir', 'inventory_file', diff --git a/lib/ansible/plugins/inventory/yaml.py b/lib/ansible/plugins/inventory/yaml.py index 38d24fe0ce..5983ce0674 100644 --- a/lib/ansible/plugins/inventory/yaml.py +++ b/lib/ansible/plugins/inventory/yaml.py @@ -59,6 +59,7 @@ all: # keys must be unique, i.e. only one 'hosts' per group ''' import os + from collections import MutableMapping from ansible.errors import AnsibleParserError @@ -112,37 +113,38 @@ class InventoryModule(BaseFileInventoryPlugin): def _parse_group(self, group, group_data): - if isinstance(group_data, MutableMapping): + if isinstance(group_data, (MutableMapping, type(None))): self.inventory.add_group(group) - # make sure they are dicts - for section in ['vars', 'children', 'hosts']: - if section in group_data: - # convert strings to dicts as these are allowed - if isinstance(group_data[section], string_types): - group_data[section] = {group_data[section]: None} + if group_data is not None: + # make sure they are dicts + for section in ['vars', 'children', 'hosts']: + if section in group_data: + # convert strings to dicts as these are allowed + if isinstance(group_data[section], string_types): + group_data[section] = {group_data[section]: None} - if not isinstance(group_data[section], MutableMapping): - raise AnsibleParserError('Invalid "%s" entry for "%s" group, requires a dictionary, found "%s" instead.' % - (section, group, type(group_data[section]))) + if not isinstance(group_data[section], (MutableMapping, type(None))): + raise AnsibleParserError('Invalid "%s" entry for "%s" group, requires a dictionary, found "%s" instead.' % + (section, group, type(group_data[section]))) - for key in group_data: - if key == 'vars': - for var in group_data['vars']: - self.inventory.set_variable(group, var, group_data['vars'][var]) + for key in group_data: + if key == 'vars': + for var in group_data['vars']: + self.inventory.set_variable(group, var, group_data['vars'][var]) - elif key == 'children': - for subgroup in group_data['children']: - self._parse_group(subgroup, group_data['children'][subgroup]) - self.inventory.add_child(group, subgroup) + elif key == 'children': + for subgroup in group_data['children']: + self._parse_group(subgroup, group_data['children'][subgroup]) + self.inventory.add_child(group, subgroup) - elif key == 'hosts': - for host_pattern in group_data['hosts']: - hosts, port = self._parse_host(host_pattern) - self._populate_host_vars(hosts, group_data['hosts'][host_pattern] or {}, group, port) - else: - self.display.warning('Skipping unexpected key (%s) in group (%s), only "vars", "children" and "hosts" are valid' % (key, group)) + elif key == 'hosts': + for host_pattern in group_data['hosts']: + hosts, port = self._parse_host(host_pattern) + self._populate_host_vars(hosts, group_data['hosts'][host_pattern] or {}, group, port) + else: + self.display.warning('Skipping unexpected key (%s) in group (%s), only "vars", "children" and "hosts" are valid' % (key, group)) else: self.display.warning("Skipping '%s' as this is not a valid group definition" % group)