diff --git a/changelogs/fragments/ansible-test-inventory-json.yml b/changelogs/fragments/ansible-test-inventory-json.yml new file mode 100644 index 00000000000..98bff49de6d --- /dev/null +++ b/changelogs/fragments/ansible-test-inventory-json.yml @@ -0,0 +1,4 @@ +minor_changes: + - >- + ansible-test - add ``.winrm`` and ``.networking`` as valid JSON/YAML inventory file extensions. This should not + affect any public facing code as it is used internally for inventories generated by ``ansible-test``. diff --git a/test/lib/ansible_test/_internal/ansible_util.py b/test/lib/ansible_test/_internal/ansible_util.py index 1c42ccae951..16eb8bdf8de 100644 --- a/test/lib/ansible_test/_internal/ansible_util.py +++ b/test/lib/ansible_test/_internal/ansible_util.py @@ -93,6 +93,7 @@ def ansible_environment(args: CommonConfig, color: bool = True, ansible_config: ansible = dict( ANSIBLE_PYTHON_MODULE_RLIMIT_NOFILE=str(SOFT_RLIMIT_NOFILE), + ANSIBLE_INVENTORY_PLUGIN_EXTS='.yaml, .yml, .json, .winrm, .networking', # allows the yaml/json inventory format for windows and networking ANSIBLE_FORCE_COLOR='%s' % 'true' if args.color and color else 'false', ANSIBLE_FORCE_HANDLERS='true', # allow cleanup handlers to run when tests fail ANSIBLE_HOST_PATTERN_MISMATCH='error', # prevent tests from unintentionally passing when hosts are not found diff --git a/test/lib/ansible_test/_internal/host_profiles.py b/test/lib/ansible_test/_internal/host_profiles.py index c72733f814a..fcfb88f5eb9 100644 --- a/test/lib/ansible_test/_internal/host_profiles.py +++ b/test/lib/ansible_test/_internal/host_profiles.py @@ -202,31 +202,24 @@ class Inventory: def write(self, args: CommonConfig, path: str) -> None: """Write the given inventory to the specified path on disk.""" - # NOTE: Switching the inventory generation to write JSON would be nice, but is currently not possible due to the use of hard-coded inventory filenames. - # The name `inventory` works for the POSIX integration tests, but `inventory.winrm` and `inventory.networking` will only parse in INI format. - # If tests are updated to use the `INVENTORY_PATH` environment variable, then this could be changed. - # Also, some tests detect the test type by inspecting the suffix on the inventory filename, which would break if it were changed. - - inventory_text = '' + inventory_data: dict[str, dict[str, dict[str, dict[str, object]]]] = dict() for group, hosts in self.host_groups.items(): - inventory_text += f'[{group}]\n' + group_data = inventory_data.setdefault(group, dict()) + hosts_data = group_data.setdefault('hosts', dict()) for host, variables in hosts.items(): - kvp = ' '.join(f"{key}={value!r}" for key, value in variables.items()) - inventory_text += f'{host} {kvp}\n' - - inventory_text += '\n' + host_entry = hosts_data.setdefault(host, dict()) + host_entry.update(variables) for group, children in (self.extra_groups or {}).items(): - inventory_text += f'[{group}]\n' + group_data = inventory_data.setdefault(group, dict()) + group_children = group_data.setdefault('children', dict()) for child in children: - inventory_text += f'{child}\n' - - inventory_text += '\n' + group_children[child] = dict() - inventory_text = inventory_text.strip() + inventory_text = json.dumps(inventory_data, indent=4) if not args.explain: write_text_file(path, inventory_text + '\n') @@ -1380,7 +1373,7 @@ class NetworkRemoteProfile(RemoteProfile[NetworkRemoteConfig]): env = ansible_environment(self.args) module_name = f'{self.config.collection + "." if self.config.collection else ""}{self.config.platform}_command' - with tempfile.NamedTemporaryFile() as inventory_file: + with tempfile.NamedTemporaryFile(suffix='.json') as inventory_file: inventory.write(self.args, inventory_file.name) cmd = ['ansible', '-m', module_name, '-a', 'commands=?', '-i', inventory_file.name, 'all'] @@ -1636,7 +1629,7 @@ class WindowsRemoteProfile(RemoteProfile[WindowsRemoteConfig]): env = ansible_environment(self.args) module_name = 'ansible.windows.win_ping' - with tempfile.NamedTemporaryFile() as inventory_file: + with tempfile.NamedTemporaryFile(suffix='.json') as inventory_file: inventory.write(self.args, inventory_file.name) cmd = ['ansible', '-m', module_name, '-i', inventory_file.name, 'all'] diff --git a/test/lib/ansible_test/_internal/inventory.py b/test/lib/ansible_test/_internal/inventory.py index 26f8f8bd650..4aa2fd008f1 100644 --- a/test/lib/ansible_test/_internal/inventory.py +++ b/test/lib/ansible_test/_internal/inventory.py @@ -109,9 +109,7 @@ def create_windows_inventory(args: EnvironmentConfig, path: str, target_hosts: l # The `testhost` group is needed to support the `binary_modules_winrm` integration test. # The test should be updated to remove the need for this. extra_groups={ - 'testhost:children': [ - 'windows', - ], + 'testhost': ['windows'], }, ) @@ -145,7 +143,7 @@ def create_network_inventory(args: EnvironmentConfig, path: str, target_hosts: l # see: https://github.com/ansible/ansible/pull/34661 # see: https://github.com/ansible/ansible/pull/34707 extra_groups={ - 'net:children': sorted(host_groups), + 'net': list(sorted(host_groups)), }, )