Discovering device configuration¶
The yang::NetconfDiscoveryResource scans a netconf device for the instances of one element —
the entries of a yang list, or a single container — and reports each instance as a discovered
resource on the orchestrator. Use it to explore the config and state of a device, and to
inventory existing config (e.g. before onboarding it into a service model).
Quick start¶
Discover every port configured on a Nokia SR OS device:
import yang
yang::NetconfDiscoveryResource(
name="ports",
device="router-east",
host="10.20.30.40",
port=830,
credentials=yang::Credentials(
username_env_var="ROUTER_EAST_USERNAME",
password_env_var="ROUTER_EAST_PASSWORD",
),
module_mapping={
"nokia-conf": "urn:nokia.com:sros:ns:yang:sr:conf",
},
filter="<filter xmlns='urn:ietf:params:xml:ns:netconf:base:1.0' type='subtree'><configure xmlns='urn:nokia.com:sros:ns:yang:sr:conf'><port><admin-state/><ethernet><mode/><encap-type/><mtu/></ethernet></port></configure></filter>",
discovery_target="/nokia-conf:configure/nokia-conf:port[port-id]",
discovered_name="port:{port_id}",
)
On every deploy of this resource, the handler sends a get rpc with the filter, splits the
reply in one item per port entry and reports one discovered resource per port, e.g.
yang::NetconfResource[router-east,name=port:1/1/c2/1] with values:
{
"name": "port:1/1/c2/1",
"device": "router-east",
"host": "10.20.30.40",
"port": 830,
"discovered_params": {"port_id": "1/1/c2/1"},
"filter": "<the subtree filter selecting only this port>",
"xml": "<the config of this port, as returned by the device>"
}
The discovered resources can be browsed in the web console and queried through the
GET /api/v2/discovered endpoint.
Attributes¶
Attribute |
Description |
|---|---|
|
Name of the discovery resource, unique per device |
|
Device name, used as agent name. Use the same value as for the |
|
Management address and netconf port of the device (default port: 830) |
|
Credentials used to open the netconf session, as for the other yang resources |
|
Mapping of module name to namespace uri, used to resolve the prefixes of the |
|
A netconf subtree filter (rfc 6241), sent as-is in the |
|
The path of the element whose instances are discovered (see below) |
|
A name template, resolved for each discovered instance (see below) |
|
Retry behaviour of the netconf requests, as for |
|
Enable XML huge tree support, for very large replies |
The discovery target¶
The discovery_target is a path of slash-separated, qualified tags pointing at the element
whose instances are discovered. The prefixes are module names, resolved through the
module_mapping. Every yang list on the path that is enumerated (rather than pinned to one
entry by the filter) declares the names of its key leaves with a bracket suffix:
/nokia-conf:configure/nokia-conf:port[port-id]
This is a plain path, not an xpath: the brackets declare key names, never values. A few rules:
Multi-key lists declare all their keys in one bracket, comma-separated:
dzs:rule[group-index,member-index].Nested lists: when the target list is nested inside another list, the enclosing list must either be pinned in the filter (a content match node selects one entry, e.g.
<service-name>vprn-1</service-name>— nothing to declare), or be enumerated as well, with its own bracket suffix. The keys of every enumerated level become template variables:/nokia-conf:configure/nokia-conf:service/nokia-conf:vprn[service-name]/nokia-conf:interface[interface-name]
Single container: when the last segment declares no keys, the target is a plain container and exactly one resource is discovered (e.g. expose the whole
/configure/systemsubtree of every device as one discovered resource):/nokia-conf:configure/nokia-conf:system
The filter must contain the target path (exactly one element per level). The selection leaves of the declared keys are added to the filter automatically when missing, so the device always returns the key values.
The discovered name¶
The discovered_name is a python format template, resolved for each discovered instance with
the key values of the entry (and of its enumerated enclosing entries). The variable names are
the key leaf names, normalized to valid identifiers: - and . are replaced by _
(port-id → port_id).
The resolved name becomes the id of the discovered resource:
yang::NetconfResource[<device>,name=<resolved discovered_name>]. It must be unique per
instance: use enough parameters in the template, the handler fails otherwise.
Everything is validated when the resource is exported: the target path syntax and its presence in the filter, the uniqueness of the (normalized) key names and the template variables. A compile/export fails early with an actionable message instead of failing on the agent.
Discovered resources lifecycle¶
Each run reports the current instances and deletes the resources reported by its previous runs: entries that disappeared from the device are cleaned up, entries still present are refreshed.
Several discovery resources can coexist on the same device (e.g. one for ports, one for vprns): each one only cleans up its own discoveries.
The discovered resource ids reuse the
yang::NetconfResourceentity type and the agent of the discovery resource. When a managed resource with the same id exists (the discovered entry got onboarded), the orchestrator links both: themanagedfilter of the discovered resources api and the web console rely on this.
Onboarding discovered config¶
The values of each discovered resource mirror the inputs of a yang::NetconfResource:
discovered_paramsholds the identity of the instance (the key values),filteris a subtree filter restricted to this single instance,xmlis the instance config as returned by the device.
A typical onboarding flow: discover the existing entries, match the discovered_params against
the inventory (or use them as service identifiers), and instantiate the service model for each
entry. Once the service deploys a yang::NetconfResource named after the same
discovered_name, the discovered resource shows up as managed.
Discovering state¶
Discovering the state of the devices works exactly like discovering their config. The get
rpc returns config and operational state: point the filter (and the discovery_target) at a
state subtree (the config false; part of the yang models) to inventory operational data.
For example, discover the interfaces of the Base router on a Nokia SR OS device, with their operational status:
module_mapping = {"nokia-state": "urn:nokia.com:sros:ns:yang:sr:state"}
filter = <filter xmlns='urn:ietf:params:xml:ns:netconf:base:1.0' type='subtree'>
<state xmlns='urn:nokia.com:sros:ns:yang:sr:state'>
<router><router-name>Base</router-name>
<interface><interface-name/><oper-state/></interface>
</router>
</state>
</filter>
discovery_target = /nokia-state:state/nokia-state:router[router-name]/nokia-state:interface[interface-name]
discovered_name = state:interface:{router_name}:{interface_name}
Each discovered resource then holds the operational leaves of one interface in its xml value
(e.g. <oper-state>up</oper-state>). Config and state subtrees can also be combined in one
inventory by deploying one discovery resource per subtree.
Limitations¶
Netconf only (no gnmi/restconf discovery yet).
One discovery resource discovers the instances of one element. Deploy several discovery resources to scan several lists.