Connections and transports¶
Connections¶
Connections to an IOS-XR router are created with xrm2m.connect()
or
xrm2m.connect_async()
.
-
xrm2m.
connect
(transport=None, loop=None)¶ Connect to a router, via the given transport.
Parameters: - transport – The
Transport
to connect to the router with. If running on an IOS-XR router this argument may be omitted, in which case the connection will be made locally. - loop – Optional event loop to use for any internal async calls that may be made. If not provided the default event loop will be used. See Event Loops for more details.
Returns: A
Connection
object representing the new connection.Raises: ConnectionError
if the connection could not be made.- transport – The
-
xrm2m.
connect_async
(transport=None, loop=None)¶ Asynchronously connect to a router, via the given transport.
See
connect()
for details on when a transport can be re-used.Parameters: - transport – The
Transport
to connect to the router with. If running on an IOS-XR router this argument may be omitted, in which case the connection will be made locally. - loop – The event loop with which the future returned by this function will be
associated. It is also the event loop that will be associated with
the futures returned by the methods of the resulting
AsyncConnection
object. See Event Loops for more details.
Returns: A
AsyncConnection
representing the new connection.Raises: ConnectionError
if the connection could not be made.- transport – The
-
xrm2m.
sync
(async_conn)¶ Return a
Connection
given aAsyncConnection
.The returned object uses the same underlying connection as the input connection.
Parameters: conn – The AsyncConnection
connection whose synchronous equivalent is to be sought.Returns: A Connection
representing the synchronous version of conn.
-
xrm2m.
async
(sync_conn)¶ Return a
AsyncConnection
given aConnection
.The returned object uses the same underlying connection as the input connection.
Parameters: conn – The Connection
connection whose asynchronous equivalent is to be sought.Returns: A AsyncConnection
representing the asynchronous version of conn.
-
class
xrm2m.
Connection
¶ Connection to a router, with synchronous methods.
Connections are created with
connect()
, orsync()
. See the corresponding documentation for more information.Note: Connection objects are not thread-safe: No two threads should concurrently call a single Connection object’s methods.
-
cli_exec
(command)¶ Execute a CLI comand and return the resulting string.
Parameters: command – CLI command to fetch data for.
Returns: The string returned when the command was executed.
Raises:
-
cli_get
(command)¶ Retrieve data given a CLI command.
The command is equivalent to doing a
get()
call for each path that the command fetches, and concatenating the results.Example:
>>> c.cli_get("show foo interfaces") ... [["RootOper.Foo.Interface({'IntfName': 'GigE0'})", {"a": 1, "b": 2}], ... ["RootOper.Foo.Interface({'IntfName': 'GigE1'})", {"a": 5, "b": 6}]]
Parameters: command – CLI command to fetch data for.
Returns: Iterable of
Path
, value pairs.Raises:
-
cli_get_nested
(command)¶ Retrieve structured data given a CLI command.
The command is equivalent to doing a
get_nested()
call for each path that the command fetches, and combining the results.Example:
>>> c.cli_get_nested("show foo interfaces") ... { ... "RootOper": { ... "Foo": { ... "Interface": [{ ... "IntfName": "GigE0", ... "a": 1, ... "b": 2 ... }, { ... "IntfName": "GigE1", ... "a": 6, ... "b": 7 ... }] ... } ... } ... }
Parameters: command – CLI command to fetch data for.
Returns: Return a nested dict/list containing the retreived values. The information retrieved is equivalent to that returned by
get()
. Leaves in the structures correspond with the values returned by get_nested. See example for how the dict is formatted.Raises:
-
cli_replace
(command)¶ Replace the subtree corresponding with a config CLI command.
Example:
>>> c.cli_replace("int GE0/0/0/0")
Parameters: command – Config CLI command. Raises: DisconnectedError
if the connection was lost.
-
cli_set
(command)¶ Set/delete data corresponding with a config CLI command.
Example:
>>> c.cli_set("int GE/0/0/0 shut")
Parameters: command – Config CLI command.
Raises:
-
commit
()¶ Commit the config changes made using this connection.
Raises:
-
commit_replace
()¶ Commit the config changes made using this connection, replacing all existing config.
Raises:
-
delete
(path_or_iter)¶ Delete the contents of one or more leaves/subtrees.
Parameters: path_or_iter – Either a
Path
or an iterable ofPath
to be deleted.Raises:
-
discard_changes
()¶ Discard any uncommitted config changes made using this connection.
Raises:
-
disconnect
()¶ Disconnect the connection.
Raises: NotConnected
if the connection is already disconnected.
-
get
(path)¶ Read paths and values under a given path.
Example:
>>> c.get(RootOper.Foo.Interface) ... [[RootOper.Foo.Interface({'IntfName': 'GigE0'}), {"a": 1, "b": 2}], ... [RootOper.Foo.Interface({'IntfName': 'GigE1'}), {"a": 5, "b": 6}]]
Parameters: path –
Path
identifying which paths and values should be returned.Returns: Iterable of
Path
, value pairs.Raises:
-
get_changes
()¶ Return the changes in running config built up (but not yet commited) on this connection.
This method can be used to examine the changes that would be made if
commit()
were called:>>> for change in conn.get_changes(): ... print(change.path) ... print(change.op.name, change.value) ... print("--") ... Path(RootCfg.Hostname) SET R1-BOS -- Path(RootCfg.InterfaceConfiguration("act", "HundredGigE0/0/0/0").Shutdown) DELETE None --
Returns: Sequence of
ChangeDetails
for every change that would be made if the config changes on this connection were committed.Raises:
-
get_children
(path)¶ Read key/index information (in the form of paths) under a given path.
Example:
>>> vrfs = RootCfg.VRF >>> for path in get_children(vrfs): ... print(path) ... Path(RootCfg.VRF('bar')) Path(RootCfg.VRF('foo'))
Parameters: path –
Path
for which key/index information is being sought.Returns: Iterable of
Path
.Raises:
-
get_nested
(path)¶ Read paths and values under a given path, returning structured data.
Example:
>>> c.get_nested(RootOper.Foo.Interface) ... { ... "RootOper": { ... "Foo": { ... "Interface": [{ ... "IntfName": "GigE0", ... "a": 1, ... "b": 2 ... }, { ... "IntfName": "GigE1", ... "a": 6, ... "b": 7 ... }] ... } ... } ... }
Parameters: path –
Path
identifying which paths and values should be returned.Returns: Return a nested dict/list containing the retreived values. The information retrieved is equivalent to that returned by
get()
. Leaves in the structures correspond with the values returned by get. See example for how the dict is formatted.Raises:
-
get_parent
(path)¶ Get the parent of a data path.
Parameters: path – A
Path
whose parent is to be found.Returns: A
Path
which is the parent of the path being found.Raises:
-
get_schema
(path)¶ Return the schema meta-data for a path.
This method returns a
SchemaClass
describing the last element of the path:>>> schema = conn.get_schema(RootCfg.InterfaceConfiguration) >>> print(schema) SchemaClass(InterfaceConfiguration) >>> schema.description 'The configuration for an interface' >>> for child in schema.children[:5]: ... print(child) Path(RootCfg.InterfaceConfiguration.PseudowireEther) Path(RootCfg.InterfaceConfiguration.IPv6Neighbor) Path(RootCfg.InterfaceConfiguration.MACAccounting) Path(RootCfg.InterfaceConfiguration.IPV6PacketFilter) Path(RootCfg.InterfaceConfiguration.PTP)
The input
Path
identifies the point of interest in the schema hierarchy.Any key values in the path are ignored. In particular, it’s ok to omit key values even where they’d usually be mandatory:
>>> cls = conn.get_schema(RootCfg.InterfaceConfiguration.VRF) >>> print(cls) SchemaClass(VRF)
If the path doesn’t identify a valid sequence of classes in the schema,
PathHierarchyError
is raised:>>> conn.get_schema(RootOper.Missing.Interface) PathHierarchyError: 'Missing' is not a child of 'RootOper'
Parameters: path –
Path
identifying the point in the hierarchy of interest.Returns: A
SchemaClass
object, as above.Raises:
-
get_value
(path)¶ Retrieve the value of a given path.
The functionality is equivalent to that of
get()
where the path identifies a single leaf, except only the value is returned.A
AmbiguousPathError
is raised if the path matches multiple leaves. Note that the request may still succeed even if the path is not inherently unambiguous (ie. it contains wildcards or missing keys), in the case that the queryParameters: path – A
Path
to be fetched.Returns: Scalar value of the leaf.
Raises:
-
get_version
()¶ Return the current M2M API version number.
Returns: A major,`minor` pair of ints, representing the API major and minor version number, respectively.
Raises:
-
normalize_path
(path)¶ Return a validated copy of a path in the canonical format.
Parameters: path – Path
to be normalized.Returns: Copy of this path, in the standard format returned from the M2M API. The returned path is compatible with all standard path functions, e.g. Path.key()
.This method validates the contents of the path against the schema.
It raises
PathHierarchyError
if the sequence of element names in this path doesn’t match the schema:>>> path = RootOper.Missing.Interface >>> conn.normalize_path(path) PathHierarchyError: 'Missing' is not a child of 'RootOper'
It raises
PathKeyStructureError
if (for example) the key values in this path don’t include a value for a mandatory key:>>> path = RootCfg.InterfaceConfiguration("TenGigE0/2/0/0").VRF >>> conn.normalize_path(path) PathKeyStructureError: Too few key values for 'InterfaceConfiguration': need 2, have 1
It raises
PathKeyContentError
if one of the key values is incompatible with the data type defined by the schema.Raises:
-
reconnect
()¶ Reconnect to the router.
If already connected, disconnect first and then connect. If connecting, wait for connection to complete, then disconnect, then connect.
See
state
for the current connection state.
-
replace
(subtree_or_iter)¶ Mark one or more subtrees for atomic replacement.
Parameters: subtree_or_iter – Either a
Path
or an iterable ofPath
to be marked for replacement.Raises:
-
set
(leaf_or_iter, value=None)¶ Set the value of one or more leaves.
Example:
>>> intf = RootCfg.InterfaceConfiguration >>> set(intf("act", "HundredGigE0/0/0/0").VRF, "barvrf") >>> set(intf("act", "HundredGigE0/0/0/1").VRF, "bazvrf")
Or equivalently:
>>> intf = RootCfg.InterfaceConfiguration >>> set([(intf("act", "HundredGigE0/0/0/0").VRF, "barvrf"), ... (intf("act", "HundredGigE0/0/0/1").VRF, "bazvrf")])
Parameters: Raises:
-
state
¶ The connection’s state.
Returns: A ConnectionState
.
-
write_file
(data, filename)¶ Writes the given string to the router’s filesystem.
Parameters: - data – A string which will be written to a file on the router’s filesystem.
- filename – Path of the file on the router to which the file is to be written.
Raises: FileExistsError
PermissionError
CiscoError
DisconnectedError
-
-
class
xrm2m.
Change
¶ Enumeration of data-modifying operations.
-
SET
¶ Value set for a leaf (that may or may not have already existed).
-
DELETE
¶ Existing value for a leaf deleted.
-
-
class
xrm2m.
ChangeDetails
¶ Description of a data-modifying operation.
-
value
¶ For non-delete operations, the (new) value for the leaf. This is represented in the standard output format (and so may not exactly match the input representation).
For delete operations, this is None.
-
-
class
xrm2m.
ConnectionState
¶ Representation of a
Connection
‘s state.-
DISCONNECTED
¶ Not connected to the router, and not connecting. A
Connection
may move into this state from CONNECTED if the transport fails, or if a connection-wide error condition is hit. AConnection
may move into this state from CONNECTING if the in-flightconnect_async()
orConnection.reconnect()
call fails.Any in-flight requests will fail with
DisconnectedError
when the corresponding connection transitions to this state.
-
CONNECTING
¶ In the process of connecting to the router, ie.
connect_async()
,connect()
, orConnection.reconnect()
has been called but has not yet returned.
-
CONNECTED
¶ Connected to the router. This is the only state in which request methods can be made.
-
-
class
xrm2m.
AsyncConnection
¶ A connection to a router, with asynchronous methods.
Async connections are created with
connect_async()
, orasync()
. See the corresponding documentation for more information.Objects of this type are equivalent to those of
Connection
, except the request methods are synchronous: They return the result directly rather than returning a future. See theConnection
documentation for more details.Note: AsyncConnection objects are not thread-safe: No two threads should concurrently call a single AsyncConnection object’s methods.
Transports¶
Transports are a mechanism for sending and receiving raw bytes from a router,
with connection semantics. Its methods and attributes should not be used
directly by the user (other than construction), instead the transport is used
by calling methods on a Connection
, which in turn is created by
connect()
or connect_async()
.
A given Transport
object may only be passed to connect()
or
connect_async()
once. To reconnect a disconnected Connection
,
Connection.reconnect()
should be used.
-
class
xrm2m.
Transport
¶ Abstract transport definition.
-
class
xrm2m.
SSHTransport
(hostname, username, key_filename=None, password=None, port=22, look_for_keys=True, allow_agent=True)¶ Transport that defines a connection to a router over SSH.
-
__init__
(hostname, username, key_filename=None, password=None, port=22, look_for_keys=True, allow_agent=True)¶ Initialize the SSHTransport.
The transport authenticates using the following steps:
Parameters: - hostname – Host being connected to.
- port – Port to connect to.
- username – Username to authenticate as.
- key_filename – The filename, or list of filenames of optional private key(s) to try for authentication
- password – Optional password. This will be used if key_filename is not passed, or if the private key is protected by a pass-phrase.
- look_for_keys – Search for discoverable private key files in ~/.ssh/.
- allow_agent – Allow connecting to an SSH agent.
-
Event Loops¶
connect()
and connect_async()
accept an event loop argument,
which is used for executing asynchronous operations.
The type of loop that must be passed depends on the Python version, and platform being used:
- On box, with Python 3: A
cisco.sdk.EventContext
should be passed. - Off box, with Python 2.7.x: A trollius event loop should be passed.
- Off box, with Python 3.4 or later: A asyncio event loop should be passed.
All other configurations are unsupported.
If the parameter is omitted then relevent async library’s default event loop will be used (eg. asyncio.get_event_loop()).