Repository: ansible/ansible-runner

Issue:
No option to use multiple inventory files (and thus constructed inventories)
 a singular parameter:

https://github.com/ansible/ansible-runner/blob/94f58c7c3667102dbafbf3b2349322c594deeccc/ansible_runner/runner_config.py#L249-L250

To be consistent with how Ansible core has operated since 2.4, it needs some way to process a list of inventory sources. The use case of constructed inventories need multiple `-i` flags in order to be usable. See the full documentation here:

https://docs.ansible.com/ansible/latest/plugins/inventory.html

A faster example here:

https://gist.github.com/halberom/e7791aa22c7dd1ef3f1ece3c815b4af8

```
ansible host5 -i hosts -i dynamic.config -m debug -a 'var=groups'
```

Any software that integrates Ansible via runner will be blocked from using any of these features unless runner changes its API to take multiple inventories somehow.

Discussion:

Patch:
diff --git a/ansible_runner/__main__.py b/ansible_runner/__main__.py
index 1a4ffb7..8e61dc3 100644
--- a/ansible_runner/__main__.py
+++ b/ansible_runner/__main__.py
@@ -281,11 +281,6 @@ def main(sys_args=None):
 
         with context:
             with role_manager(args) as args:
-                if args.inventory:
-                    with open(args.inventory) as f:
-                        inventory_data = f.read()
-                else:
-                    inventory_data = None
                 run_options = dict(private_data_dir=args.private_data_dir,
                                    ident=args.ident,
                                    binary=args.binary,
@@ -298,7 +293,7 @@ def main(sys_args=None):
                                    rotate_artifacts=args.rotate_artifacts,
                                    ignore_logging=False,
                                    json_mode=args.json,
-                                   inventory=inventory_data,
+                                   inventory=args.inventory,
                                    roles_path=[args.roles_path] if args.roles_path else None,
                                    process_isolation=args.process_isolation,
                                    process_isolation_executable=args.process_isolation_executable,
diff --git a/ansible_runner/interface.py b/ansible_runner/interface.py
index a1c69b7..032533d 100644
--- a/ansible_runner/interface.py
+++ b/ansible_runner/interface.py
@@ -90,6 +90,7 @@ def run(**kwargs):
       - Path to the inventory file in the ``private_data_dir``
       - Native python dict supporting the YAML/json inventory structure
       - A text INI formatted string
+      - A list of inventory sources, or an empty list to disable passing inventory
     :param roles_path: Directory or list of directories to assign to ANSIBLE_ROLES_PATH
     :param envvars: Environment variables to be used when running Ansible. Environment variables will also be
                     read from ``env/envvars`` in ``private_data_dir``
diff --git a/ansible_runner/runner_config.py b/ansible_runner/runner_config.py
index 5667478..2bbe1b2 100644
--- a/ansible_runner/runner_config.py
+++ b/ansible_runner/runner_config.py
@@ -262,8 +262,13 @@ class RunnerConfig(object):
         except ConfigurationError:
             pass
 
-        exec_list.append("-i")
-        exec_list.append(self.inventory)
+        if isinstance(self.inventory, list):
+            for i in self.inventory:
+                exec_list.append("-i")
+                exec_list.append(i)
+        else:
+            exec_list.append("-i")
+            exec_list.append(self.inventory)
 
         if self.limit is not None:
             exec_list.append("--limit")


Test patch:
diff --git a/test/unit/test_runner_config.py b/test/unit/test_runner_config.py
index 243bdb3..6e291b3 100644
--- a/test/unit/test_runner_config.py
+++ b/test/unit/test_runner_config.py
@@ -171,6 +171,9 @@ def test_prepare_inventory():
     rc.inventory = '/tmp/inventory'
     rc.prepare_inventory()
     assert rc.inventory == '/tmp/inventory'
+    rc.inventory = 'localhost,anotherhost,'
+    rc.prepare_inventory()
+    assert rc.inventory == 'localhost,anotherhost,'
 
 
 def test_generate_ansible_command():
@@ -193,7 +196,21 @@ def test_generate_ansible_command():
         assert cmd == ['ansible-playbook', '-i', '/inventory', '-e', '@/env/extravars', 'main.yaml']
     rc.extra_vars = None
 
+    rc.inventory = "localhost,"
+    cmd = rc.generate_ansible_command()
+    assert cmd == ['ansible-playbook', '-i', 'localhost,', 'main.yaml']
+
+    rc.inventory = ['thing1', 'thing2']
+    cmd = rc.generate_ansible_command()
+    assert cmd == ['ansible-playbook', '-i', 'thing1', '-i', 'thing2', 'main.yaml']
+
+    rc.inventory = []
+    cmd = rc.generate_ansible_command()
+    assert cmd == ['ansible-playbook', 'main.yaml']
+    rc.inventory = None
+
     rc.verbosity = 3
+    rc.prepare_inventory()
     cmd = rc.generate_ansible_command()
     assert cmd == ['ansible-playbook', '-i', '/inventory', '-vvv', 'main.yaml']
     rc.verbosity = None