netviz query
netviz query answers two query languages, and reads the first word of the
argument to tell them apart.
A query beginning with select or with is
relational: it walks the schema, joins by following links and
returns whatever shape it is asked for — a value, an object, or an array of
nested objects.
Anything else is the selector: a predicate that prints the
elements it picks, and nothing else. That is the language's home but not its
only use — the same expression narrows a render with --select, grades a
network with assert: query, and drives the editor's search box.
docs/nql.md and docs/query.md are the two
references. This page is the command.
Synopsis
netviz [GLOBAL OPTIONS] query [OPTIONS] QUERY
Two languages, one command
$ netviz query 'kind = switch' # selector: which elements?
$ netviz query 'select switch.name' # relational: the same list
$ netviz query 'select switch { name, ports := count(.interfaces) }'
The selector is a predicate and answers with names. The relational language
joins and projects, so it answers with structure — and it takes -F json,
-F yaml and -F csv, which the selector does not.
--layer and --print scope a selector query. They have no meaning for a
relational one, which reads the whole inventory, so passing either with one is a
usage error rather than a silently ignored flag.
--describe prints the relational language: with no value its grammar, its
types and its functions; with a type name, that type's members and their
cardinalities. --explain does the same for the selector.
$ netviz query --describe address
address -- One configured IP address, and where it is configured.
also spelled: ip
…
What it is for
Three questions, and they are different:
"Which elements are these?" — the default. One fully-qualified name per
line, in load order, so the output pipes into xargs, grep -c or another
netviz invocation.
$ netviz query 'kind = router and label.site = north'
sites/north/core/rtr-north-core-01
"How many?" — --count prints the number alone.
$ netviz query 'kind = switch' --count
10
"Is this true?" — the exit status. netviz query exits 1 when nothing
matched, so a query is a check:
$ netviz query 'kind = switch and not has address' --count
0
An invariant is written as a search for its counterexamples, so no match is
the passing case — and a shell that wants it that way inverts the status, or
writes the claim as an assert: query and lets netviz test
report it.
Printing the sub-objects
A scope asks about interfaces, links, namespaces or zones, and answering with
the elements holding them loses the part of the answer that was asked for.
--print interfaces and --print links report the sub-objects that satisfied a
scope instead:
$ netviz query 'interface[type = loopback and has address]' --print interfaces
sites/north/core/rtr-north-core-01:lo0
sites/north/hosts/pc-north-01:lo
sites/north/hosts/srv-north-01:lo
sites/north/hosts/pc-north-02:lo
sites/south/core/rtr-south-core-01:lo0
sites/south/hosts/pc-south-01:lo
sites/south/hosts/srv-south-01:lo
sites/south/hosts/pc-south-02:lo
sites/west/core/rtr-west-core-01:lo0
sites/west/hosts/pc-west-01:lo
sites/west/hosts/srv-west-01:lo
sites/west/hosts/pc-west-02:lo
Only the sub-objects matched at positive polarity are reported: under a
not, a scope's being satisfied is what makes the surrounding term false, and
reporting those interfaces as if they had been selected would be a lie.
--json
The whole answer as data, carrying the query that produced it so a saved result says what it is:
$ netviz query 'kind = router and label.site = south' --json
{
"query": "kind = router and label.site = south",
"count": 1,
"subject": "elements",
"matches": [
{
"element": "sites/south/core/rtr-south-core-01"
}
]
}
With --print interfaces each record carries element and interface; with
--print links, element and link. --count --json drops the records and
keeps the number.
--param: a value the query does not carry
A relational query may leave a hole for a value, written $name, and take it
from --param. This is what a generated query wants — one written by a
script, a CI job or an Ansible template — because the value
never reaches the parser as query text:
$ netviz query 'select (device filter .name = $host).addresses.address' --param host=srv-north-01
ADDRESS
--------------------
127.0.0.1/8
::1/128
10.1.20.11/24
2001:db8:1:20::11/64
NAME=VALUE is text, whatever it looks like: a device called 0755 is a device
called 0755. NAME:=JSON is typed, which is how a number, a boolean or a list
is said on a command line that has no types of its own:
$ netviz query 'select vlan { id, name } filter .id in $ids' -p 'ids:=[10, 20]' -F csv
ID,NAME
10,staff
20,lab
The value is checked before the inventory is read, and it is checked as a
value: $ids above is a set of integers, so comparing it to a name would be
refused at parse time. Concatenating the same value into the text could not be —
which is the whole reason to have parameters at all.
A selector has no parameters, and --param with one is a usage error rather
than a flag that binds nothing.
The layer
--layer picks which view the query is answered against, exactly as it picks
which view render draws. It matters:
- at
l3the graph holds subnet nodes, sokind = subnetandprefix in 10.1.0.0/16have something to select and a traversal walks through prefixes; - at
netnsa machine's containers are nodes of their own, sonetns[depth > 0]finds them; - at
powera PDU is a node and a feed is a link.
$ netviz query --layer l3 'kind = subnet and prefix in 10.1.0.0/16' --count
4
Given several --layer flags the last wins: a query has one answer, and a
command that quietly unioned three views would not be able to say which layer a
match came from.
The filter flags scope the question
netviz query takes the same --kind, --namespace, --name, --vlan,
--neighbors-of and --depth every command that draws the whole inventory
does. Here they narrow the graph the query is answered against — "among the
switches, which match this" — rather than being AND-ed into the expression
afterwards. That is what makes --neighbors-of useful: it says which part of
the network the question is about.
$ netviz query --namespace sites/west 'has address' --count
7
--explain
Prints the grammar and the whole attribute vocabulary, generated from the same
tables the parser checks against, so --explain cannot drift from what is
accepted. With the filter flags it also prints the query those flags are sugar
for:
$ netviz query --explain --neighbors-of sw-north-acc-01 --depth 3
# the filter flags, as the query they are sugar for
within 3 hops of (fqn = sw-north-acc-01 or name = sw-north-acc-01)
...
Errors
A query that does not parse is a usage error — exit status 2 — reported before the inventory is read, with the offending column underlined:
$ netviz query 'kind = switch and interface[interface[x]]'
Usage: netviz query [OPTIONS] QUERY
Try 'netviz query --help' for help.
Error: Invalid value for 'QUERY': query:1:29: a scope cannot be written inside another scope
kind = switch and interface[interface[x]]
^^^^^^^^^
help: an interface has no interfaces; write the terms side by side
An inventory with errors in it refuses the query the way every other reading
command does, unless --force is given: an answer computed from a broken
inventory is an answer about a network that is not the one described.
Exit status
| Status | Means |
|---|---|
| 0 | The query matched at least one element. |
| 1 | It matched nothing, or the inventory was rejected. |
| 2 | The query is not a query, or an option is wrong. |
Arguments
| Argument | Required | Count | Default |
|---|---|---|---|
QUERY |
no | 1 | — |
Options
| Flag | Value | Default | Meaning |
|---|---|---|---|
--layer |
[physical|l1|l2|l3|ipam|overlay|routing|rack|power|identity|netns|security] |
l1 |
l1 draws the physical topology; l2 annotates it with VLANs; l3 draws IP subnets and the elements addressed in them; ipam draws the address plan — the same prefixes without the devices, nested inside the blocks they came out of and showing how full each is; overlay draws the tunnels; routing draws the BGP sessions and OSPF adjacencies, clustered by VRF; physical adds the patch panels l1 splices out; rack draws a front elevation per rack; power draws the PDUs and the feeds into everything they power; identity draws the users and groups; netns opens each machine up into the network stacks inside it, joined by their veth pairs; security draws the firewall zones and what the policy lets cross between them. Repeatable for -f html, which draws each layer and puts a switcher over them. |
--print |
[elements|interfaces|links] |
elements |
elements prints what the query selected; interfaces and links print the sub-objects an interface[...] or link[...] scope matched inside them. |
-F, --output-format |
[table|json|yaml|csv] |
table |
How to print a relational answer. table and csv flatten a nested field into one cell; json and yaml carry it whole. |
--json |
— | off | Report as JSON. |
-p, --param |
NAME=VALUE |
— | Bind a '$NAME' in a relational query. NAME=VALUE is text; NAME:=JSON is a number, a boolean or a list. Repeatable. A value is never parsed as query text, so a name with a quote in it cannot change what the query asks. |
--count |
— | off | Print how many matched, and nothing else. |
--explain |
— | off | Print the selector grammar and the attribute vocabulary instead of running a query, and — with the filter flags — the query they are sugar for. |
--describe |
[TYPE] |
— | Print the relational language instead of running a query: with no value its grammar, types and functions; with a type name, that type's members. |
--namespace |
NS |
— | Keep only elements in this namespace or below it. Repeatable. |
--vlan |
VID |
— | Keep only elements participating in this VLAN. Repeatable. |
--kind |
[switch|router|firewall|hub|computer|server|adapter|patchpanel|pdu|user|group] |
— | Keep only elements of this kind. Repeatable. |
--name |
GLOB |
— | Keep only elements whose name matches this glob. Repeatable. |
--neighbors-of |
NAME |
— | Keep only the neighbourhood of this element. |
--depth |
INTEGER, >= 0 |
1 |
How many hops --neighbors-of reaches. |
--select |
QUERY |
— | Keep only the elements this query selects, e.g. "kind = switch and not has vrf". The flags above are sugar for the equivalent query and are combined with it; 'netviz query --explain' prints which. See docs/query.md. |
--strict |
— | off | Treat warnings as errors. |
--force |
— | off | Proceed even when validation failed. The result may not match the files. |
See also
docs/nql.md— the relational language: why it looks like this, its grammar, its type graph and a cookbook.docs/query.md— the selector: the grammar, the attributes and a cookbook.netviz list— the same--select, over the tabular subjects.netviz render—--selectbeside the other view filters.netviz test— the same query as an executable assertion.