jaque import -from nautobot reads the devices of a Nautobot and writes
them as a CUE file of hosts. It runs once, when you run it, and what it
writes is an ordinary config file: you commit it next to your own, and
jaque loads it like any other. Nautobot knows what exists; the import
puts that list into jaque, and the services that say what to watch on
each device stay in your own files.
1. Running it
From a response you saved earlier:
jaque import -from nautobot -o inventory.cue response.json
Or by asking a Nautobot directly, with the token in the environment:
NAUTOBOT_TOKEN=... jaque import -from nautobot -url https://nautobot.example -o inventory.cue
Flags go before the path. Flag parsing stops at the first argument that is
not a flag, so a -o after response.json is counted as a second path and
the command fails. -url and a path exclude each other.
Without -o, the CUE goes to stdout. The report goes to stderr either
way, so jaque import ... > inventory.cue captures only the CUE. The
token is read from NAUTOBOT_TOKEN and from nowhere else: there is no
flag for it, so it does not end up in a shell history or a process list.
With -url and no token set, the command stops before it sends anything.
2. What is read
The import sends one GraphQL query to /api/graphql/ and maps the
response it gets back. Nothing is paged: the whole device list comes in a
single response.
query {
devices {
id
name
status { name }
role { name }
location { name parent { name parent { name parent { name parent { name } } } } }
platform { name }
tenant { name }
device_type { model }
tags { name }
primary_ip4 { address }
_custom_field_data
}
}
A response that carries GraphQL errors, or that is not valid JSON, fails the import and writes nothing.
3. What becomes what
Each imported device becomes one host, named after the device, with an ICMP check on its address.
| Nautobot | jaque |
|---|---|
name |
the host name |
primary_ip4.address |
address, without the prefix length, and the host of the ICMP check |
role |
label role |
location |
label site |
| the top of the location chain | label region, when the location has a parent |
platform |
label platform |
tenant |
label tenant |
device_type.model |
label device_type |
status |
label status |
| each tag | label tag.<name> with the value true |
_custom_field_data.jaque_parent |
parents, see section 5 |
The location chain is read up to four levels above the device's own
location. A device in AMS 01, inside the region Europe, gets
site: ams-01 and region: europe.
Nautobot names are free text and a label value is not, so each name is
turned into a value: lowercase, with every run of characters outside
a-z, 0-9, _ and . replaced by a single -, and leading and
trailing separators trimmed. Core Switch becomes core-switch and
AMS 01 becomes ams-01. Two different names in the same category can
turn into the same value; the first is kept as it is, and each later one
is listed in the report as approximated, naming both. A name that leaves
nothing after the conversion is dropped and listed the same way.
4. What is left out
Only devices that are Active and have a primary IPv4 address are
imported. Each device left out is listed in the report as unsupported,
with the reason and the Nautobot id of the device:
- the status is anything but
Active, or the device has no status; - the device has no primary IPv4 address;
- the address does not parse as an address;
- the name is empty;
- the name is shared by several Active devices with a primary IPv4: all of them are left out, since a host name has to be unique.
The report header says how many of the devices in the response made it into the file, the same figure the Nagios importer reports. Read the unsupported lines before deciding the inventory is complete.
5. Parents
A device whose jaque_parent custom field holds the name of another
imported device gets that device as its parents. The field is a text
field on the device; Nautobot cables are not read to work out a topology.
When jaque_parent names a device that is not in the import, because it
is not Active or has no address, the host is emitted without a parent and
the report lists it as approximated. The same happens when the field names
the device itself or holds something other than text. An empty field means
no parent.
6. Attaching services
The import writes hosts and labels and no services, because Nautobot does not know what should be watched on a device. The generated file is not edited. A file of your own unifies with it, and attaches services through the labels:
hosts: {
for name, h in hosts if (*h.labels.role | "") == "core-switch" {
(name): services: ssh: check: {type: "tcp", address: "\(h.address):22"}
}
"core-sw01": check: check_interval: "30s"
}
The comprehension adds an ssh service to every host whose role label is
core-switch. The *... | "" default is what lets a host without that
label pass: a bare h.labels.role is an error on the first host that has
no role. The last line overrides one host's check interval from your
layer, which is where an override belongs; a change made in the generated
file is lost at the next import.
7. Keeping it current
Run the import from cron or from a CI job, write the file with -o, and
commit it. When the file changes, the reload picks it up; see hot
reload. A device that left Nautobot, or stopped being
Active, is absent from the next file.
Rolling back is reverting that commit: jaque keeps no history of imported inventory of its own, and the diff in the repository is the record of what changed between two imports.