netviz GitHub

netviz edit

Change the inventory through typed operations rather than through a text editor: rename a switch and every reference to it, delete a device and the cables that terminate on it, set a field, cable two ports together. Each one is checked before it is written, is reversible exactly, and leaves every line it did not mean to change byte for byte as it was.

docs/editing.md explains the operation model — what an operation is, what its inverse is, and why the write path is built this way. This page is the reference for the command.

Contents


The operations

netviz edit set core-sw spec.model 'C9300'            # write a field
netviz edit unset core-sw spec.location               # remove one
netviz edit create switch sw-new --namespace sites/hq # declare an element
netviz edit delete sw-old --cascade                   # remove one, and its cables
netviz edit rename sw-old sw-new                      # and every reference to it
netviz edit move sw-new sites/hq/access/sw-new.yaml   # another file, another namespace
netviz edit connect sw-new:Gi1/0/1 pc-desk:eno1       # a cable between two ports
netviz edit disconnect cbl-sw-new-pc-desk             # and back out again
netviz edit add-interface sw-new Gi1/0/2              # a port
netviz edit remove-interface sw-new Gi1/0/2 --cascade # and what terminated on it

Each subcommand applies exactly one operation. netviz edit apply takes any number of them as JSON, which is how a script or an editor drives it.

One operation has no subcommand of its own: set-geometry, which writes one view of a kind: layout document. Coordinates are not something anybody types, so it is reached through netviz layout — or through apply, which is how a canvas will reach it when a node is dragged.

Addresses and field paths

An address is anything that names one element: a fully-qualified name (sites/hq/access/sw-01), or a short name when exactly one element in the inventory carries it (sw-01). It is resolved the way every reference in the inventory is resolved (§2.2), so a name that matches two elements is refused with both spelled out rather than guessed at.

A field path names a value inside a document, in the notation the diagnostics already use: spec.model, spec.interfaces[2].mtu, metadata.labels.site. Mappings on the way to the value are created if they are not there; a sequence entry is not, because spec.interfaces[7] on a device with three ports is a typo rather than an instruction.

A value is read as a YAML scalar, so 1500 is a number, true is a boolean and [10, 20] is a list — the same reading the value would have got had it been typed into the document by hand. --string switches that off for the times a model number really is 1500.

Three things it always does

It preserves everything it did not change. Comments, blank lines, key order and quoting style survive; a document nothing touched is written back as the exact bytes it was read as. A diff of an edit is the edit.

It refuses to break the tree. Before writing, the tree is loaded as it would be and validated. If the edit would introduce an error the inventory does not already have, nothing is written and the new problems are listed. Existing problems are not held against you — an inventory that fails validate is exactly when an editor is most useful — and --force overrides the check when you know better. Warnings never block a write.

It refuses to clobber. Every file it reads is hashed, and the hash is checked again immediately before the write. A file that changed on disk in between — your editor, a git checkout, another netviz — is reported and the edit is dropped. --force does not skip this: overwriting somebody else's work is not something a flag can mean.

--dry-run: see the diff first

-n/--dry-run writes nothing and prints the unified diff it would have written, with git's a//b/ prefixes so git apply accepts it:

$ netviz -i examples/home-lab edit set sw-home spec.model 'TL-SG108PE' --dry-run
--- a/switches/sw-home.yaml
+++ b/switches/sw-home.yaml
@@ -8,7 +8,7 @@
     role: access
 spec:
   vendor: TP-Link
-  model: TL-SG108E
+  model: TL-SG108PE
   location: Home / hallway cabinet
   interfaces:
     - name: br0

The validation gate still runs, so a dry run that would have been refused says so.

--json: the undo stack

--json prints the applied operations, the operations that undo them, and the files touched. Keeping the inverse list and feeding it back to netviz edit apply is a complete undo:

netviz edit rename sw-home sw-hall --json > /tmp/change.json
jq '.inverse' /tmp/change.json | netviz edit apply --force

Undo is byte-exact: after applying the inverses the tree is the tree you started with, comment for comment. docs/editing.md explains why some inverses are write-file rather than the obvious opposite operation.

Operations as JSON

netviz edit apply reads one JSON object or a list of them from stdin, or from -f/--file. Every object carries an op and the keys that operation takes:

netviz edit apply <<'JSON'
[{"op": "create", "kind": "switch", "name": "sw-new", "namespace": "sites/hq",
  "spec": {"interfaces": [{"name": "Gi1/0/1", "type": "ethernet"}]}},
 {"op": "connect", "a": "sw-new:Gi1/0/1", "b": "pc-desk:eno1"},
 {"op": "set", "address": "sites/hq/sw-new", "path": "spec.vendor", "value": "Cisco"}]
JSON

The list is applied in order and judged as one change, so an operation that is only valid once a later one has run — a cable to a device the previous operation created — is fine. netviz edit with no subcommand is the same thing.

The full set of operations and their keys is in docs/editing.md.

Where a new document goes

create and connect place their document themselves unless --file says otherwise, following the conventions in docs/inventory-layout.md:

--file is checked rather than obeyed blindly: it has to be a YAML file inside the inventory that the loader would actually read, and its folder has to be the namespace asked for, because a document's folder is its namespace.

Deleting the last document of a file deletes the file, and the folders that empty out under it.

Exit status

Code When
0 The edit was applied (or, with --dry-run, could have been).
1 It was refused: an unknown address, a dangling reference, a new validation error, or a file that changed on disk.
2 Usage error — an unknown flag, a malformed field path, unparseable JSON.

Nothing is ever half-written: a refusal writes no file at all.

Reference

netviz edit

netviz [GLOBAL OPTIONS] edit [OPTIONS] [COMMAND] [ARGS]...

No options of its own; the global options apply.

netviz edit set

netviz [GLOBAL OPTIONS] edit set [OPTIONS] ADDRESS PATH VALUE
Flag Value Default Meaning
--string off Take VALUE literally instead of reading it as YAML, so 1500 stays a string.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit unset

netviz [GLOBAL OPTIONS] edit unset [OPTIONS] ADDRESS PATH
Flag Value Default Meaning
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit create

netviz [GLOBAL OPTIONS] edit create [OPTIONS] {switch|router|firewall|hub|computer|server|cable|adapter|tunnel|patchpanel|pdu|user|group} NAME
Flag Value Default Meaning
--namespace TEXT Folder to declare it in, relative to the inventory root. The root by default.
--spec TEXT {} The element's spec, as JSON.
--metadata TEXT {} Description, labels and annotations, as JSON.
--file TEXT File to write it to, relative to the inventory root. Chosen by the layout conventions when absent.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit copy

Copies an element — or a whole namespace, subtree and all — into a new document. The copy keeps the original's comments, gets a free name (sw1sw1-copysw1-copy-2), and loses the fields two elements in one inventory cannot both have. A cable whose two ends are both in the copied set is cloned and rewired to the clones; one with only a single end in it is left behind and named. See the copy chapter of docs/editing.md for the whole table.

netviz [GLOBAL OPTIONS] edit copy [OPTIONS] ADDRESS
Flag Value Default Meaning
--to TEXT Namespace to write the copies into; the folder each original is in by default. The empty string is the inventory root.
--name TEXT metadata.name of the copy. Derived from the original's when absent; only meaningful when copying one element.
--suffix TEXT copy What a derived name gets before its counter: sw1 -> sw1-copy -> sw1-copy-2.
--keep-unique off Keep the MAC addresses, fixed IP addresses, serials and outlets a copy normally drops. The result usually fails validation; use it when the copy is a starting point you are about to edit.
--view [physical|l1|l2|l3|ipam|overlay|routing|rack|power|identity|netns|security] Place the copies in this view's stored geometry, offset from the originals. Nothing is written to a layout document when absent.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit duplicate

netviz edit copy with no --to: the copy lands in the namespace the original is in. The same operation under the name a diagram editor gives it — Ctrl-D in netviz web writes exactly this.

netviz [GLOBAL OPTIONS] edit duplicate [OPTIONS] ADDRESS
Flag Value Default Meaning
--name TEXT metadata.name of the copy. Derived from the original's when absent; only meaningful when copying one element.
--suffix TEXT copy What a derived name gets before its counter: sw1 -> sw1-copy -> sw1-copy-2.
--keep-unique off Keep the MAC addresses, fixed IP addresses, serials and outlets a copy normally drops. The result usually fails validation; use it when the copy is a starting point you are about to edit.
--view [physical|l1|l2|l3|ipam|overlay|routing|rack|power|identity|netns|security] Place the copies in this view's stored geometry, offset from the originals. Nothing is written to a layout document when absent.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit delete

netviz [GLOBAL OPTIONS] edit delete [OPTIONS] ADDRESS
Flag Value Default Meaning
--cascade off Also delete the cables and tunnels that terminate on it, and the notes and areas that cannot be drawn without it, and clear the optional references to it.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit rename

netviz [GLOBAL OPTIONS] edit rename [OPTIONS] ADDRESS NEW_NAME
Flag Value Default Meaning
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit move

netviz [GLOBAL OPTIONS] edit move [OPTIONS] ADDRESS FILE
Flag Value Default Meaning
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit connect

netviz [GLOBAL OPTIONS] edit connect [OPTIONS] A B
Flag Value Default Meaning
--medium [copper|fiber|wireless] copper What the link is made of.
--speed TEXT Negotiated link rate, e.g. 1Gbps.
--label TEXT The identifier printed on the cable.
--name TEXT metadata.name of the cable; derived from the endpoints when absent.
--namespace TEXT Folder to declare it in. The nearest folder containing both ends by default.
--file TEXT File to write it to, relative to the inventory root.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit disconnect

netviz [GLOBAL OPTIONS] edit disconnect [OPTIONS] ADDRESS
Flag Value Default Meaning
--cascade off Also delete the notes and areas that cannot be drawn without the cable.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit add-interface

netviz [GLOBAL OPTIONS] edit add-interface [OPTIONS] ADDRESS NAME
Flag Value Default Meaning
--type TEXT ethernet Interface type, as spec.interfaces[].type spells it.
--description TEXT What the port is for.
--field PATH=VALUE Any other key of the interface, e.g. --field mtu=9000. Repeatable.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit remove-interface

netviz [GLOBAL OPTIONS] edit remove-interface [OPTIONS] ADDRESS NAME
Flag Value Default Meaning
--cascade off Also remove the cables and tunnels that terminate on the interface.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

netviz edit apply

netviz [GLOBAL OPTIONS] edit apply [OPTIONS]
Flag Value Default Meaning
-f, --file FILE Read the operations from this file instead of from stdin.
-n, --dry-run off Write nothing; print the unified diff the edit would apply.
--json off Print the applied operations and their inverses as JSON, so a caller can keep an undo stack.
--force off Write even when the edit would introduce a new error. The check for files that changed on disk is never skipped.

See also