Please confirm the following
Bug Summary
When using input_inventories on a constructed inventory, the module internally calls resolve_name_to_id('inventories', item) without scoping the lookup to any organisation. If the same inventory name exists in multiple organisations, the lookup returns more than one result and the module fails with:
Request to /api/v2/inventories/?name=<inventory_name> returned 2 items, expected 1
This occurs despite the organization parameter being correctly set on the constructed inventory itself. The organization parameter scopes the constructed inventory lookup correctly (as seen in module.get_one with data={'organization': org_id}) but this org scope is not passed to the resolve_name_to_id call for input_inventories.
AWX version
24.6.1
Select the relevant components
Installation method
kubernetes
Modifications
no
Ansible version
2.19.4 with awx.awx collection 24.6.1
Operating system
Debian
Web browser
No response
Steps to reproduce
Create two organisations — org-a and org-b
Create an inventory named my-inventory in both org-a and org-b
Create a constructed inventory in org-a referencing my-inventory as an input inventory:
- name: Create constructed inventory
awx.awx.inventory:
name: my-constructed-inventory
organization: org-a
kind: constructed
input_inventories:
- my-inventory
state: present
controller_host: "{{ awx_host }}"
controller_oauthtoken: "{{ awx_token }}"
Expected results
The module should scope the input_inventories lookup to the same organisation as the constructed inventory, or provide a parameter to specify the lookup organisation for input inventories.
Actual results
Request to /api/v2/inventories/?name=my-inventory returned 2 items, expected 1
Additional information
Workaround
Pass inventory IDs instead of names in input_inventories:
- name: Get inventory IDs scoped to org
set_fact:
input_inventory_ids: "{{ query('awx.awx.controller_api', 'inventories',
query_params={'organization__name': 'org-a'},
host=awx_host,
oauth_token=awx_token,
return_all=true,
max_objects=2000)
| selectattr('name', 'equalto', 'my-inventory')
| map(attribute='id')
| map('string')
| list }}"
- name: Create constructed inventory using IDs
awx.awx.inventory:
name: my-constructed-inventory
organization: org-a
kind: constructed
input_inventories: "{{ input_inventory_ids }}"
state: present
controller_host: "{{ awx_host }}"
controller_oauthtoken: "{{ awx_token }}"
Root cause
In inventory.py, the input_inventories resolution loop does not pass org scoping data to resolve_name_to_id:
for item in input_inventory_names:
association_fields['input_inventories'].append(module.resolve_name_to_id('inventories', item))
Compare to the correctly scoped inventory lookup earlier in the same file:
inventory = module.get_one('inventories', name_or_id=name, **{'data': {'organization': org_id}})
Suggested fix
Pass org_id as a data filter to resolve_name_to_id for input_inventories:
for item in input_inventory_names:
association_fields['input_inventories'].append(
module.resolve_name_to_id('inventories', item, data={'organization': org_id})
)
Note on suggested fix:
resolve_name_to_id is defined in controller_api.py at line 488 and does not currently accept additional keyword arguments or data filters. The fix therefore requires two changes:
- Update
resolve_name_to_id to accept an optional data parameter and pass it through to the underlying lookup
- Update the
input_inventories loop in inventory.py to pass data={'organization': org_id}
Alternatively the input_inventories loop could be refactored to use get_one directly instead of resolve_name_to_id, since get_one already supports the data parameter for scoped lookups as demonstrated elsewhere in the same file.
Please confirm the following
security@ansible.cominstead.)Bug Summary
When using
input_inventorieson a constructed inventory, the module internally callsresolve_name_to_id('inventories', item)without scoping the lookup to any organisation. If the same inventory name exists in multiple organisations, the lookup returns more than one result and the module fails with:Request to /api/v2/inventories/?name=<inventory_name> returned 2 items, expected 1This occurs despite the organization parameter being correctly set on the constructed inventory itself. The organization parameter scopes the constructed inventory lookup correctly (as seen in
module.get_onewithdata={'organization': org_id})but this org scope is not passed to theresolve_name_to_idcall forinput_inventories.AWX version
24.6.1
Select the relevant components
Installation method
kubernetes
Modifications
no
Ansible version
2.19.4 with awx.awx collection 24.6.1
Operating system
Debian
Web browser
No response
Steps to reproduce
Create two organisations —
org-aandorg-bCreate an inventory named
my-inventoryin bothorg-aandorg-bCreate a constructed inventory in
org-areferencingmy-inventoryas an input inventory:Expected results
The module should scope the
input_inventorieslookup to the same organisation as the constructed inventory, or provide a parameter to specify the lookup organisation for input inventories.Actual results
Request to /api/v2/inventories/?name=my-inventory returned 2 items, expected 1Additional information
Workaround
Pass inventory IDs instead of names in input_inventories:
Root cause
In
inventory.py, theinput_inventoriesresolution loop does not pass org scoping data toresolve_name_to_id:Compare to the correctly scoped inventory lookup earlier in the same file:
Suggested fix
Pass
org_idas a data filter toresolve_name_to_idforinput_inventories:Note on suggested fix:
resolve_name_to_idis defined incontroller_api.pyat line 488 and does not currently accept additional keyword arguments or data filters. The fix therefore requires two changes:resolve_name_to_idto accept an optional data parameter and pass it through to the underlying lookupinput_inventoriesloop ininventory.pyto passdata={'organization': org_id}Alternatively the
input_inventoriesloop could be refactored to useget_onedirectly instead ofresolve_name_to_id, sinceget_onealready supports thedataparameter for scoped lookups as demonstrated elsewhere in the same file.