Awx.awx.inventory is failing to create constructed inventories - potential edge case?

hello!

I dug a bit in the code and found this edge case for collection awx.awx.inventory
The function make_request is used for creating new/updating awx resource AND also used for retrieving existing associations.

So, when a new resource is created and has associations with it, the code will check for existing associations and it will exit right away if it gets a 404 because the self.fail_json() is called when a 404 is received. awx/awx_collection/plugins/module_utils/controller_api.py at a70b0c1ddc35a03701372d0a921fba5bb14264f5 · ansible/awx · GitHub

For example, when I create a new constructed inventory,

  • It first makes a POST to create the constructed inventory
  • Makes a get request to retrieve all endpoints (existing associations)
    Fails with error below

“msg”: “The requested object could not be found at /api/v2/constructed_inventories/24/input_inventories/”

args used below: (with AWX → UI version=22.0.0, Operator=2.0.0)

{
    "ANSIBLE_MODULE_ARGS": {
        "_ansible_check_mode": false,
        "_ansible_debug": false,
        "_ansible_diff": false,
        "_ansible_ignore_unknown_opts": false,
        "_ansible_keep_remote_files": true,
        "_ansible_module_name": "awx.awx.inventory",
        "_ansible_no_log": false,
        "_ansible_remote_tmp": "~/.ansible/tmp",
        "_ansible_selinux_special_fs": [
            "fuse",
            "nfs",
            "vboxsf",
            "ramfs",
            "9p",
            "vfat"
        ],
        "_ansible_shell_executable": "/bin/sh",
        "_ansible_socket": null,
        "_ansible_string_conversion_action": "warn",
        "_ansible_syslog_facility": "LOG_USER",
        "_ansible_target_log_info": null,
        "_ansible_tmpdir": "REDACTED",
        "_ansible_verbosity": 3,
        "_ansible_version": "2.17.1",
        "controller_host": "REDACTED",
        "input_inventories": [
            "REDACTED"
        ],
        "organization": "REDACTED",
        "kind": "constructed",
        "name": "REDACTED",        
        "controller_username": "REDACTED",        
        "controller_password": "REDACTED"
    }
}

OR

Maybe the edge case is that builds the url wrong when retrieving the existing associations for a constructed inventory. When I reverse engineer the api call from the UI, it makes a POST request to
https://.com/api/v2/inventories/24/input_inventories/
NOT
https://.com/api/v2/constructed_inventories/24/input_inventories/

Can someone help me with this please with a course of action to take?

Did the inventory ID change or have a mismatch? Or did you typo 21/24? From what I can tell, all inventories, constructed or not, appear in the inventories api endpoint. However, only constructed inventories will have inventories/<id>/input_inventories. Since you’re getting a 404 at that endpoint, I would think that the inventory name to id resolver found an existing regular or smart inventory by that name instead of updating or creating a constructed inventory.

hello Caleb, sorry this ID was a typo ( as i was building and deleting inventories a few time for testing, must have miscopied)

Checking further in the code: awx/awx_collection/plugins/module_utils/controller_api.py at a70b0c1ddc35a03701372d0a921fba5bb14264f5 · ansible/awx · GitHub
, I think its because AWX return the item_url for constructed inventories as /api/v2/constructed_inventories/<id> which is used here: awx/awx_collection/plugins/module_utils/controller_api.py at a70b0c1ddc35a03701372d0a921fba5bb14264f5 · ansible/awx · GitHub

so when it tries to get all endpoints for input_inventories with the URL built wrong it will throw the 404:
code at L718 ( i can’t add more than two links per post)

ah thanks for confirming inventories/<id>/input_inventories
so the url is indeed built wrong for constructed inventories when adding input_inventories to constructed_inventories

for reference this is the call with the data

'https://<REDACTED>.com/api/v2/inventories/'
'{"name": "REDACTED", "organization": 2, "kind": "constructed", "host_filter": null, "input_inventories": [2]}'

@Denney-tech i’ve raised this issue: The module awx.awx.inventory is failing to create constructed inventories - Edge case uncaught · Issue #15310 · ansible/awx (github.com)

1 Like

And you’re certain that the inventory “name” doesn’t match an existing inventory of a different “kind”? (normal or smart inventories)

yes, it doesn’t match an existing inventory of a different kind

1 Like

I’ll see if I can try and reproduce this later this week. The 404 for the constructed_inventory endpoint makes me think there’s a problem with the name-to-id resolver or that the inventory kind isn’t defined properly when the constructed inventory is created.

i’ve pinpoint the issue in a few code snippets with the issue that I linked.
tldr
1- it returns the url constructed_inventories/<id> after the inventory is created
2- when it checks for associations in this case the input_inventories, it uses the url above to build the irl, so you get <awx-endpoint>.com/api/v2/constructed_inventories/<id>/input_inventories instead of <awx-endpoint>.com/api/v2/inventories/<id>/input_inventories

But both of those should be valid for a constructed inventory…

Edit: OH… I see where I’m getting confused. Both the inventories/<ID> and constructed_inventories/<ID> mention inventories/<id>/input_inventories in the related objects, but there is no constructed_inventories/<id>/input_inventories endpoint specifically. Which makes me wonder why the constructed_inventories exists at all.

exactly you got it right, its a bug in the code, mind giving a thumbs up to my issue please?

I think your bug was already identified and fixed in AWX 22.1.0. Please upgrade and try again.

that’s actually contributing to the bug Only use constr. inv URL when req comes from it by relrod · Pull Request #13797 · ansible/awx · GitHub
what this PR does for version AWX 22.1.0 is returning construced_inventories/<id> in the response instead of inventories/<id> as the URL

but the issue is not with awx itself. It is with the ansible module using that construced_inventories/<id> url that is returned in the response for querying the input_inventories which only exists under inventories/<id>/input_inventories and not construced_inventories/<id>/input_inventories

Prior to the change, the API always returns the constructed_inventories prefix for kind=="constructed", which is what you’re seeing. That PR changes it to match the request, so when you’re posting the constructed inventory to inventories , the API won’t redirect you unexpectedly to constructed_inventories.

I will give it a go and get back with my findings

I think that should solve it because I cannot replicate your issue on 24.6.0.

- hosts: localhost
  gather_facts: false
  vars:
    awx_username: redacted
    awx_password: redacted
    awx_host: redacted
  tasks:
    - awx.awx.inventory:
        controller_host: "https://{{ awx_host }}"
        controller_username: "{{ awx_username }}"
        controller_password: "{{ awx_password }}"
        name: foobar
        organization: Linux
        kind: constructed
        input_inventories:
          - Inventory
PLAY [localhost] *************************************************************************************************************************************************************************************

TASK [awx.awx.inventory] *****************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP *******************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

upgrading to the latest version worked, thanks for the suggestion Caleb that fixed my issue.

1 Like