Infrastructure Resources Skill
Use this skill to discover and inspect infrastructure resources — what exists, whether it is healthy, and what its raw data contains.
CLI Commands
| Command | Purpose | Key flags |
|---|---|---|
cx infra resources types | List available resource types (category/type pairs) | - |
cx infra resources list | List resources, narrowed by any filterable attribute | all optional: --match-all NAME=VALUE, --match-any NAME=VALUE, --category, --type, --start-row, --end-row |
cx infra resources filters | List the attributes resources can be filtered by, with their accepted values | --category, --type |
cx infra resources health-history <resource-id> | Daily health samples for one resource, oldest first | - |
cx infra resources raw-data <resource-id> | Raw resource document as JSON | - |
- All commands are read-only and support
-o json/-o toonfor structured output. - Multi-profile fan-out applies to
types,filtersandlistonly. Repeat-p <profile>on those to compare fleets across accounts.health-historyandraw-datatake a resource id, which is scoped to one team, so they reject more than one-p— run them once per profile instead. - Filtering takes two flags. Every
--match-allmust match; at least one--match-anymust match; the two groups combine with AND. So--match-all OS=linux --match-any Health=Critical --match-any Region=eu-west-1meansOS=linux AND (Health=Critical OR Region=eu-west-1). - A comma lists several values for one attribute, and the flag decides what
that means. In
--match-anythey are alternatives — any one matches:--match-any Region=eu-west-1,us-east-2. In--match-allevery one must match, which is how to narrow on two substrings at once:--match-all 'Name=*alert*,*processing*'finds the names holding both. An attribute that carries a single value cannot equal two of them, so for either value, reach for--match-any. - An attribute belongs to exactly one flag. Repeating it within a flag, or naming it in both, is refused — list its values after the comma instead.
- Nothing is required except one narrowing input.
--categoryand--typeare ordinary filters, not prerequisites, so--match-all Health=Criticalalone works. A request naming none of--match-all,--match-any,--categoryor--typeis rejected. CategoryandTypeare not filterable attributes. They select which resource types a request covers, have their own flags, and never appear infiltersoutput — so there is no--match-all Category=Hosts, use--category Hosts.- An exact value is case-sensitive; a wildcard one is not.
OS=linuxmatches andOS=Linuxreturns nothing, butName=*checkout*andName=*Checkout*are the same query.filterslists values only for a fixed set, so for free text either take the spelling from a row'scolumnsor use a wildcard. Astatusvalue is matched case-insensitively either way. - 0 rows is an answer, not a failure. A valid attribute that is simply unpopulated matches nothing; do not retry or reword the query. A misspelled attribute or an out-of-set value is rejected outright, naming what is accepted.
filterstells you three things per attribute.kindis what the value looks like —stringmeans free text,statusmeans a fixed set, andnumber,boolanddatemean themselves.valueslists the accepted values of a fixed set — pass one of those, spelled asfiltersreports it.wildcardsays whether a*is accepted in the value — onlystringattributes accept one, and it matches anywhere in the value:--match-all 'Name=*checkout*'— quote it, or the shell expands the*.--name-filterand--scopeare the legacy flags and stand apart. Both require--categoryand--type, and neither can be combined with--match-allor--match-any. Use--scopeto narrow byservice,environmentorteam; use the filter flags for everything else —--match-all 'Name=*web*'is the same query as--name-filter web.- Pagination:
--start-row/--end-rowdefine a row window (--end-rowis exclusive); the default is the first 100 rows, and omitting only--end-rowgives 100 rows from--start-row. Page through large fleets in windows (0-100, 100-200, …).listnever pages for you — fleets can run to hundreds of thousands of resources, so it returns one window and reports the total. - The window cannot reach past row 10,000. The API rejects any request whose
start-row + rowsexceeds 10,000, so paging cannot enumerate a fleet larger than that even thoughtotal_countreports its true size. In any case, narrow until the result fits — add--match-allattributes, or a--type— and page within each subset rather than trying to walk the whole list. listwraps its rows in an envelope (total_count,returned_count,resources) — the other subcommands return bare arrays.total_countis the fleet-wide match count, independent of the window. Check it before reasoning over the rows: keep paging whilestart_row + returned_count < total_count, and if it exceeds what you can page to, narrow the query rather than trusting a partial answer.- Pass resource IDs exactly as returned by
list(quote them — they contain:and=); the CLI percent-encodes them for you.
Inspection Workflow
Three steps, and only because each one supplies an input the next one requires:
filters gives the attribute names and their accepted values, list gives the
resource_id. Answering "is web-server-1 healthy?" is these three calls —
nothing more.
-
Discover what can be filtered — attribute names and their accepted values are per resource type and dynamic, so never guess. Omit both flags for the union across every type:
cx infra resources filters -o jsoncx infra resources types -o jsonlists the(category, type)pairs, when you need those rather than the attributes. -
List resources, narrowing by any attribute
filtersoffered:cx infra resources list --category Hosts --type EC2_Instances \ --match-all Health=Critical -o json -
Inspect one resource using a
resource_idfrom step 2. Statuses areHealthy,Critical, orUnmonitored, one sample per day, oldest first:cx infra resources health-history "1001234:host_id=i-abc123" -o jsonraw-datais the alternative to this step, not a follow-on — use it instead when you need source-specific detail rather than health.
Examples
Unhealthy hosts in one region
# Health is a fixed set, so `filters` first for the accepted values
cx infra resources filters --category Hosts -o json | jq '.[] | select(.name == "Health")'
cx infra resources list --category Hosts \
--match-all Health=Critical --match-all Region=eu-west-1 -o json \
| jq '.resources[] | {name, type}'
Every resource whose name contains a substring
# `filters` reports wildcard: true for Name, so `*` is accepted
cx infra resources list --match-all 'Name=*checkout*' -o json \
| jq '.resources[] | {name, category, type}'
Either of two attributes, any resource type
# --match-any ORs across attributes; no category or type needed
cx infra resources list \
--match-any Name=coredns --match-any Namespace=kube-system -o json \
| jq '.resources[] | {name, category, type}'
# Two values of the *same* attribute take the comma form, not a second flag
cx infra resources list --match-any Namespace=kube-system,observability -o json
# The same comma in --match-all requires *all* the values: names holding both
cx infra resources list --match-all 'Name=*alert*,*processing*' -o json
Just the ids and names
# Rows live under .resources — `list` returns an envelope
cx infra resources list --category Hosts --type EC2_Instances -o json \
| jq '[.resources[] | {resource_id, name}]'
Check fleet size, and whether one window covered it
cx infra resources list --category Hosts --type EC2_Instances -o json \
| jq '{total_count, returned_count}'
# Next window, if there is one
cx infra resources list --category Hosts --type EC2_Instances \
--start-row 100 --end-row 200 -o json
Find when a resource went critical
# health-history returns a bare array, so no .resources here
cx infra resources health-history "1001234:host_id=i-abc123" -o json \
| jq '[.[] | select(.status == "Critical")]'
Read the raw resource document
# Source-specific detail: tags, instance metadata, configuration
cx infra resources raw-data "1001234:host_id=i-abc123" -o json
Key Principles
- Discover before filtering — never guess an attribute name or a status
value; start from
cx infra resources filters, which lists both. - Quote resource IDs and pass them verbatim — they embed
:,|, and=; the CLI handles URL encoding. - A missing raw document is not an error —
raw-dataexits 0 and emits an empty result on stdout:[]injson,[0]:inagents, andNo raw data found.in text. Only the noteno raw data for this resourcegoes to stderr. Parse the empty stdout result as a cleanly absent document, not a failure — and do not expect stdout to be blank. - Use
-o jsonwithjqfor filtering; use-o toonfor token-efficient output in agent contexts. - The row window applies per profile — a multi-profile
listadds acounts_by_profilebreakdown, so page each profile against its owntotal_count, not the aggregate. - A resource id never crosses profiles — it embeds the team id
(
1001234:host_id=…), so an id from one account cannot resolve in another. When a multi-profilelistturns up something worth inspecting, note itsprofilefield and query that single profile for its health or raw data. - Infra health is its own concept — the
Healthy/Critical/Unmonitoredstatuses are computed by the infrastructure domain and are not the same as Service Catalog health. Correlate them with telemetry signals; do not treat them as interchangeable. resource_idnever leaves this skill — pass it only tohealth-historyandraw-data. For every other command, pivot on the resourcenameor theServiceattribute value.
Related Skills
Bridge to these skills using the resource name or the Service attribute value — never the resource id, which only this skill understands:
cx-telemetry-querying—cx search-fields "<name>" -s valuediscovers which log/span fields contain the resource name;cx logs "filter $l.subsystemname == '<service>'"queries the service's telemetry. Correlate aCriticalhealth day with error logs or CPU metrics.cx-alerts—cx alerts list --name "<name-or-service>"finds alert definitions matching the resource or its service by substring.cx-dashboards—cx dashboards search "<name-or-service> ..."andcx dashboards query-search --description "..."find dashboards semantically; pair withsearch-fields -s valueto thenquery-search --fieldthe exact field holding the resource name.