The Future of Ansible Resource Management: Help Shape our New Standardized Taxonomy

Hello everyone, for those I haven’t met yet, I’m Steve Fulmer, a Product Manager for Ansible here at Red Hat. I work closely with community leaders like Don Naro, Gundalow Barker, Anwesha Das, Daniel Brennand, and Andrei Klychkov. My primary focus is collaborating with Partner and Community Engineering to grow our certified and community content, ensuring it delivers real value to both our community and Red Hat customers. I’m reaching out today to introduce an exciting new Ansible feature focused on enhanced resource reporting and management.

Today, Ansible modules often interact with external systems, such as clouds, hypervisors, network controllers to manage resources that aren’t declared in your inventory. Until now, there hasn’t been a standard way for collections to expose structured metadata about what they’re actually touching.

Red Hat has developed a mechanism for Ansible collections that maps module return values to a standardized resource taxonomy. We’re calling this resource reporting, and we want to share it with you to get your thoughts.

Resource reporting lets you declare resource types in a minimal YAML file inside your collection using lightweight jq expressions to query module return values at runtime, no special dependencies required. It’s entirely optional for community collections, but we think it brings massive value to the ecosystem.

Why are we building this?

For collection developers, resource reporting is like having excellent return-value documentation, except it’s machine-readable.

It allows users to understand exactly what their playbooks are touching, even for resources that never appear in the inventory. Ultimately, it creates a consistent, unified picture of automation activity across different vendors and platforms.

How it works

Adding resource reporting to your collection is straightforward:

  1. Check the taxonomy. Resources are mapped to standard names across vendors. For example, a VMware VM and an AWS EC2 instance are both considered a virtual_machine. (See the full taxonomy reference at the bottom of this post).
  2. Add a query file. Create an extensions/audit/event_query.yml file in your collection. Each entry maps a module FQCN (Fully Qualified Collection Name) to a jq expression.
  3. Write your jq expression. The expression runs against your module’s return values and outputs a JSON object with three fields:
    • name (required) — A human-readable resource name.
    • canonical_facts (required) — Stable, unique identifiers for deduplication (e.g., UUIDs, serial numbers, permanent MAC addresses).
    • facts (optional) — Categorization metadata, including the device_type.

Vendor-Specific Query Examples

Different platforms require slightly different querying strategies based on how their APIs are structured. Here is how you can handle a few common scenarios:

VMware (Flat Structure)

VMware has a flat return structure where the top-level key typically defines the node type. You can map directly to the returned keys.

# extensions/audit/event_query.yml  
community.vmware.vmware_guest:  
  query: >-  
    {  
      name: .instance.hw_name,  
      canonical_facts: {  
        host_name: .instance.hw_name,  
        uuid: .instance.hw_product_uuid  
      },  
      facts: {  
        device_type: "virtual_machine",  
        guest_id: .instance.hw_guest_id  
      }  
    }

Azure (Hierarchical Structure)

Azure resources are hierarchical and use verbose Resource IDs. Because the full ID contains the resource type, you can use a jq regex to dynamically capture and categorize it.

azure.azcollection.azure_rm_virtualmachine:  
  query: >-  
    {  
      name: .name,  
      canonical_facts: {  
        id: .id  
      },  
      facts: {  
        device_type: "virtual_machine",  
        # Dynamically extract "compute" using regex capture on the Azure ID  
        azure_type: ((.id | capture("/providers/[Mm]icrosoft.(?<resourcetype>[^/]+)/")? | .resourcetype) | ascii_downcase)  
      }  
    }

AWS (Implied Types & Lists)

AWS info modules often return a list of resources (like .instances), so your jq query will need to iterate over them. The type is implied entirely by the module you are querying.

amazon.aws.ec2_instance_info:  
  query: >-  
    .instances[] | {  
      name: (.tags.Name // .instance_id),  
      canonical_facts: {  
        instance_id: .instance_id  
      },  
      facts: {  
        device_type: "virtual_machine",  
        status: .state.name  
      }  
    }

Testing your expression locally:

You can easily test your jq expressions locally via the CLI before publishing your collection updates:

# Capture module output into a file, then pipe it to jq  
cat module_output.json | jq '{  
  name: .instance.hw_name,  
  canonical_facts: {  
    uuid: .instance.hw_uuid  
  },  
  facts: {  
    device_type: "virtual_machine"  
  }  
}'

When defining your resource, use the snake_case value in the facts.device_type field.

Compute

Resource device_type value
Virtual Machines virtual_machine
Containers (Managed) container
Hypervisors hypervisor
Bare Metal bare_metal
Serverless Functions serverless_function
Auto Scaling Groups auto_scaling_group

Networking

Resource device_type value
Switches switch
Routers router
Firewalls firewall
Load Balancers load_balancer
Virtual Private Clouds vpc
Subnets subnet
VPNs vpn
Gateways gateway
DNS Services dns_service
Wireless Access Points wireless_access_point
SD-WAN sd_wan

Storage

Resource device_type value
Object Storage object_storage
Block Storage block_storage
File Storage file_storage
Archive Storage archive_storage

Database

Resource device_type value
Relational (SQL) database_relational
NoSQL database_nosql
Data Warehouse data_warehouse
In-Memory/Cache database_cache

DevOps and App Integration

Resource device_type value
CI/CD Platforms ci_cd_platform
Container Registries container_registry
Message Queues message_queue
API Endpoints api_endpoint

We’d love your feedback!

It’s early days for this feature, and community input will shape where this goes next. We’d love to hear your thoughts, particularly on the following:

  • Use cases: Do you have scenarios where structured visibility into off-inventory resources would be useful to you?
  • Adoption: Would you consider adding resource reporting to a collection you maintain? What would make it easier (or harder) to adopt?
  • Tooling: What kind of tooling or integrations would you want to see built around this data?
  • Taxonomy: Are there resource types missing from the taxonomy lists above that you’d like us to add?

Drop your thoughts, questions, or concerns in the thread below!

3 Likes

Hi

  1. Can you use

    Preformated text
    

    for given examples (jq queries) because I think they are badly indented and hard to read.

  2. What does this change from the user perspective? How is this info exposed to the user?

  3. Beside device_type, what does everything else in extensions/audit/event_query.yml represent?

Thanks

EDIT:

OK so this is something that’s been around for some time and can already be found in some collections like vmware.vmware, azure.azcollection etc. Related to AAP and not so publicly known or documented.

Just to get this clear, this is about return values… right?

Just asking because it feels weird to define hosts in the inventory, even if the “host” is a cluster, switch, resource pool, namespace or something else that very clearly is not a host.

I think I’ve asked this already somewhere years ago, but can’t find it right now. IIRC the answer was more or less “in hindsight host might have been a bad decision, but changing this would be breaking or at least very hard”.

  1. Yes, that should be ok.
  2. It can be gathered and exported to a BI of choice. Or would be shown in the platform if using the subscription.
  3. vmware , azure, and google were the first three to get added as a testing ground. We have added several others to collections that use a controller.

We have documentation that Don will be publishing in the near future in community docs. But Documentation is available in partner connect and as a kbase article now.

The idea here is to get a better idea of what you actually automate in your environment from a resource perspective. Ignore term “host” think of it as any resource that gets automated. We are not defining “hosts” in this query it is gathering what is automated and putting an industry standard taxonomy behind that item with a unique identifier so it can be counted once, and deduped if it comes up again. So you can see what exactly is being automated behind, what in many times, is a black hole.
Again for stuff such as RHEL, Windows (not AD), networking automation without going to a controller first, etc… this would not be pertinent. This is just for items going through a controller or potentially a blind api call.

Can you provide links to these? TIA.

KCS ARticle is here Mastering Indirect Node Counting in Ansible: Taming the Multi-Cloud Taxonomy - Red Hat Customer Portal
Guide is here: http://connect.redhat.com/sites/default/files/2026-03/Indirect-Node-Counting-Taxonomy-Guide-v2.pdf

We are in the process of publishing an updated certification and validated content workflow guide with this data as part of it with links to the docs.

In 2.2 Standard Device TypesCompute device_type , you might want to add Resource: FreeBSD Jail and Standard device_type Value: jail

we can add that to the community docs. the doc i shared is more for certified content. but there is overlap.

Is there some tooling that is using these files? Manually having to copy module output and then manually creating a command from the YAML file’s content to see whether it works seems quite annoying. I guess having a module that you can provide the registered output of another module + the name of the query YAML file (or even make it find that one by itself given the name of the module) that returns the output would be helpful.

In the community, how do I get this “enhanced resource reporting”?

I want to follow up on Felix’s question directly because it deserves a
straight answer rather than vague gestures toward “future integration.”

Right now, the only thing that reads extensions/audit/event_query.yml is
AWX/AAP.

Specifically, AWX’s indirect_instance_count.py scrapes these files from
installed collections and uses the jq expressions to count indirectly
managed nodes — resources that modules automate but that aren’t represented
in your inventory. That data flows into AAP’s resource auditing. If you’re
running AWX (which is open source), you get this. If you’re a pure community
user without AWX, these files currently do nothing for you.

I should have been clearer about that in the original post, and I appreciate
Felix pushing on it. The community.vmware README actually puts it bluntly:
“This directory, and the event_query.yml file, are used by AAP (RedHat) to
capture metadata about certain module usage.” That’s accurate, and it means
the value proposition for a collection maintainer who isn’t targeting AAP
users is thin today.

What exists, what doesn’t:

:white_check_mark: AAP parses these files and surfaces resource counts in AAP
:white_check_mark: amazon.aws has integration tests to validate jq correctness
:white_check_mark: ansible-zuul-jobs detects file changes to trigger CI
:cross_mark: No ansible-lint rules to validate event_query.yml structure or jq
expressions
:cross_mark: The implementation documentation is behind the Red Hat KCS paywall, not
publicly accessible

That last point is something I can fix. I’m committing to getting the
implementation guide published publicly so it’s not gated behind a
subscription.

Why I still think this taxonomy effort is worth the community’s time:

The standardized resource taxonomy — device types, canonical facts, the jq
expression pattern — doesn’t have to stay AAP-exclusive. The schema is
simple. Any tool could consume it. EDA, Insights, third-party CMDB
integrations, community-built dashboards — if we get the taxonomy right and
collections adopt it consistently, the tooling story can grow. But that only
works if the taxonomy is shaped by people who actually maintain collections
across the full breadth of what Ansible automates, not just cloud and
VMware.

What I’m asking:

  1. If you maintain a collection and would add event_query.yml — what would
    make that practical? A local jq validator? An antsibull-nox session? An
    ansible-lint rule? I want to understand where the friction is before we ask
    maintainers to do more work.
  2. Are there community tools or projects (EDA community, CMDB connectors) where you’d want to see this data surfaced? That informs where
    we focus integration work.
  3. For the taxonomy itself — what resource types are you managing that don’t
    fit the current device type list? FreeBSD jails came up; I suspect that’s
    just the start.

The honest goal here is to make this useful beyond AAP customers. I don’t
want to ship a standard that only matters if you pay for a subscription. But
I need the community’s input to get the tooling and taxonomy right. Thanks
for holding me accountable on the current state.

1 Like

Having the implementation documentation out in the open would be great. (I haven’t been able to read it yet due to it being behind a login.)

I think having some basic linting (right structure of the file) and a way to effectively test it would be great. Whether that’s part of ansible-lint, antsibull-nox, or ansible-test doesn’t matter much, as long as it’s not yet another tool :wink: (I guess the chances of getting this into ansible-test is pretty much zero, I just listed it for completeness’ sake.)

For testing, I was thinking that having a “apply event query” module that you can pass in the name of the module and the module’s output, and that returns the result of the query for that module name applied to the module output. Then you can integrate this into the module’s integration tests by using that “apply event query” module to transform the module’s result (if that fails it will already tell you that the query failed to apply to actual module output).

In fact, instead of a module, this could also be a Jinja2 filter - or both module and Jinja2 filter. Having the same code also exposed as importable Python code so you can use it in unit tests would be even better.

So maybe a collection ansible.event_query_test_tools such that you have:

  1. A module ansible.event_query_test_tools.apply_query;
  2. A filter plugin ansible.event_query_test_tools.apply_query;
  3. Maybe also a lookup ansible.event_query_test_tools.apply_query?
  4. You can import a function apply_query(module_name: str, module_output: dict[str, t.Any]) -> dict[str, t.Any] from ansible_collections.ansible.event_query_test_tools.plugins.module_utils.apply_query.

(Basically 1-3 would be implemented through the function in 4.)

2 Likes

Great breakdown! You’re totally right about the dev experience—making maintainers install a whole new tool just to check one metadata file is the fastest way to kill adoption.

Here’s what I’m thinking on these points:

1. Opening up the docs

100% agree. Hiding the specs behind a login is a huge roadblock. Step one has to be getting those docs out in the open (like a public repo or normal Sphinx docs) so people actually know what we’re building.

2. Linting (structural validation)

Hooking basic schema validation into ansible-lint is definitely the easiest way to go. Most maintainers already use it in CI, so a new rule would catch syntax errors right away without messing with their current workflow.

3. The ansible.event_query_test_tools collection

Love this idea. It totally fixes the “black box” issue where a maintainer writes a query but has no clue if it actually maps to their module’s output properly.

Making a dedicated utility collection for testing lets us move fast without bloating ansible-core or ansible.utils. Your setup is spot on—having a single source of truth in module_utils to run everything is super clean:

  • module_utils: The core Python logic for unit testing (pytest).
  • Filter Plugin: Awesome for quick checks in tasks.
  • Module: Perfect for ad-hoc testing or standard integration test tasks.

If we do this, a maintainer’s integration test (tests/integration/targets/*/tasks/main.yml) feels really natural. They just run their module, register the result, and feed it right into our tool:

- name: Run the module being tested
my_namespace.my_col.my_module:
state: present
register: module_result

- name: Verify the event query maps correctly to the output
ansible.event_query_test_tools.apply_query:
module_name: “my_namespace.my_col.my_module”
module_output: “{{ module_result }}”
register: query_result

- name: Assert the query output extracted the correct data
assert:
that:
- query_result.summary == “Resource created successfully”

Since this completely piggybacks on ansible-test integration, maintainers can start checking their queries right away without waiting on upstream changes to ansible-test itself. Let me get to work on that from our side.

Even better: this also works the same way with Molecule based tests :slight_smile:

1 Like

Hey everybody,

I’ve created a PR in the community docs for resource reporting. Here are some links: