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.

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.

xrm2m.sync(async_conn)

Return a Connection given a AsyncConnection.

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 a Connection.

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(), or sync(). 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 of Path 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:

pathPath 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:

pathPath 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:

pathPath 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:

pathPath 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 query

Parameters:

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:pathPath 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 of Path 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:
  • leaf_or_iter – A Path indicating the leaf being set, or a sequence of path, value pairs, each of which will be set accordingly.
  • value – The value to be set. This should only be provided when leaf_or_iter is a Path.
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:
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.

path

Path identifying the leaf whose value is altered.

op

Element of Change recording the operation performed on the leaf.

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. A Connection may move into this state from CONNECTING if the in-flight connect_async() or Connection.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(), or Connection.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(), or async(). 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 the Connection 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()).