Skip to content

awx.awx.inventory module input_inventories parameter fails when inventory names are duplicated across organisations #16393

@civillian

Description

@civillian

Please confirm the following

  • I agree to follow this project's code of conduct.
  • I have checked the current issues for duplicates.
  • I understand that AWX is open source software provided for free and that I might not receive a timely response.
  • I am NOT reporting a (potential) security vulnerability. (These should be emailed to security@ansible.com instead.)

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

  • UI
  • UI (tech preview)
  • API
  • Docs
  • Collection
  • CLI
  • Other

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:

  1. Update resolve_name_to_id to accept an optional data parameter and pass it through to the underlying lookup
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions