Skip to content

5. Invoking a method

Roshan Joyce edited this page Apr 16, 2015 · 6 revisions

In this page we will discuss how to invoke a method on Junos Space using SpaceEZ. First of all, what do we mean by methods here? A method is a REST resource with its own URI and it encapsulates some kind of an action that can be performed on Junos Space. Following are some examples:

  • Device discovery. In order to bring one or more devices under the management of Junos Space, we need to perform a device discovery by specifying the IP address, hostname, (or IP subnet or IP range) of the device(s) to be discovered, credentials for the devices, etc. This functionality is encapsulated as a method at the URI /api/space/device-management/discover-devices.

  • Execute an XML RPC on a managed device. Junos devices expose all (well, almost all) CLI commands as XML RPCs. Junos Space allows you to invoke these XML RPCs on managed devices and this is encapsulated as the exec-rpc method contained by each device resource. This method is available at the URI {device-uri}/exec-rpc.

Let's take these two examples and see how we can invoke them using SpaceEZ.

Discovering devices

Let's say we want to discover the following device into our Junos Space cluster.

  • host-name: router1
  • ssh userid: root
  • ssh password: root123

The first thing to do is to instantiate a rest.Space object pointing to the Junos Space cluster as shown below.

from jnpr.space import rest

space = rest.Space('https://my-space.com', 'myuserid', 'mypassword')

Now, from the space object, we can navigate down to the discover-devices method contained by the device-management service. Once we have accessed this method, we need to perform a post() call on it as shown below.

result = space.device_management.discover_devices.post()

But, what parameters do we need to pass to this post() call. In order to find this, let's call describe() on this method as shown below in a Python shell and this gives a listing of all named parameters that can be supplied to the post() call.

>>> space.device_management.discover_devices.describe()

    Method at URL: /api/space/device-management/discover-devices
    Following named parameters may be supplied to the post() call:
       Parameters used:
          - hostName
          - ipAddress
          - upperIp
          - lowerIp
          - baseIp
          - subnetMask
          - usePing = True
          - useSnmp = True
          - snmpV1Setting
             - communityName
          - snmpV2CSetting
             - communityName
          - snmpV3Setting
             - userName
             - authenticationType
             - privacyType
             - authenticationPassword
             - privacyPassword
          - manageDiscoveredSystemsFlag
          - sshCredential
             - userName
             - password
>>> 

Note that all the above parameters are not mandatory and we can use a combination of them. In our example, we can pass hostName='router1, userName='root', and password='root123' as shown below:

result = space.device_management.discover_devices.post(hostName='router1', 
                                                       userName='root', 
                                                       password='root123')

If we consult the Space API documentation for the discover-devices method, we will see that this API has asynchronous semantics. This means that when we invoke POST on this method, it will create a job on Space to perform device discovery and the call will return a data structure that contains the id of the job. In the snippet above, we can access the job id as result.id.

Now, how do we monitor the progress of this job and come to know when this job completes? We can use the async.TaskMonitor class of the SpaceEZ package for this. Usage of this class is illustrated below:

# Import the async module
from jnpr.space import async 

#
# 1. Create a TaskMonitor object. First parameter is the `rest.Space` object.
#    Second parameter is the name of a hornet-q that needs to be created on Space.
#    The TaskMonitor object 'tm' encapsulates this hornet-q.
#
tm = async.TaskMonitor(space, 'queue1')

#
# 2. Now pass task_monitor=tm kwarg to the post() call on the method.
#
result = space.device_management.discover_devices.post(task_monitor=tm,
                                                       hostName='router1', 
                                                       userName='root', 
                                                       password='root123')

#
# 3. This call will block till the specified job completes and returns the final 
#    progress update message for the job.
#
progress = tm.wait_for_task(result.id)

# Check and print success
if progress.status == "SUCCESS":
    print('router1 successfully discovered')

Executing an RPC on a managed device

Now let's look at the case of invoking an XML RPC on a device managed by Junos Space. We will take the example of invoking the RPC on the device router1 that we discovered in the previous example.

First, we need to get the resource object for the device that we're interested in. As shown below, we do a filtered get on the device_management.devices collection with the filter criteria matching the name field.

devices = space.device_management.devices.get(filter_={'name': 'router1'})
my_router = devices[0]

Using a Python shell we can invoke the my_router.describe() to find out more about various methods contained by this resource:

>>> my_router.describe()

	Resource at URL: /api/space/device-management/devices/458783
	Contains following collections:
		associated_scripts (.../associated-scripts)
		associated_softwares (.../associated-softwares)
		change_requests (.../change-requests)
		configurations (.../configurations)
		managed_elements (.../managed-elements)
		view_customized_attributes (.../view-customized-attributes)
	Contains following methods:
		apply_cli_configlet (.../apply-cli-configlet)
		exec_resync (.../exec-resync)
		exec_rpc (.../exec-rpc)
		exec_rpc_async (.../exec-rpc)
>>> 

We see that it contains a method named exec_rpc. Let's do a describe() on this as well:

>>> my_router.exec_rpc.describe()

	Method at URL: /api/space/device-management/devices/458783/exec-rpc
	Following named parameters may be supplied to the post() call:
 	   Parameters used:
	      - rpcCommand
>>> 

It tells us that this method accepts just one kwarg - rpcCommand. So we can invoke this method as:

result = my_router.exec_rpc.post(rpcCommand = '<get-system-uptime-information/>')

This method executes synchronously and we have the results inside the Python object result. But how do we access the information inside it? The post() method has already parsed the XML response using lxml.objectify into a Python object now pointed to by the variable result. So we can use lxml.objectify.dump() to explore its contents. Again, from our Python shell:

>>> from lxml import objectify
>>> print objectify.dump(result)
netconf = None [ObjectifiedElement]
    status = 'Success' [StringElement]
    rpcCommands = None [ObjectifiedElement]
        rpcCommand = None [ObjectifiedElement]
            get-system-uptime-information = u'' [StringElement]
    netConfReplies = None [ObjectifiedElement]
        netConfReply = None [ObjectifiedElement]
            status = 'Success' [StringElement]
            replyMsgData = None [ObjectifiedElement]
                system-uptime-information = None [ObjectifiedElement]
                    current-time = None [ObjectifiedElement]
                        date-time = '2015-04-15 22:09:52 PDT' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '1429160992'
                    system-booted-time = None [ObjectifiedElement]
                        date-time = '2015-01-24 17:30:14 PST' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '1422149414'
                        time-length = '11w4d 03:39' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '7011578'
                    protocols-started-time = None [ObjectifiedElement]
                        date-time = '2015-01-24 17:33:37 PST' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '1422149617'
                        time-length = '11w4d 03:36' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '7011375'
                    last-configured-time = None [ObjectifiedElement]
                        date-time = '2015-03-20 09:48:53 PDT' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '1426870133'
                        time-length = '3w5d 12:20' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '2290859'
                        user = 'root' [StringElement]
                    uptime-information = None [ObjectifiedElement]
                        date-time = '\n10:09PM\n' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '1429160992'
                        up-time = '\n81 days,  3:40\n' [StringElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}seconds = '7011608'
                        active-user-count = 1 [IntElement]
                          * {http://xml.juniper.net/junos/12.1X46/junos}format = '1 user'
                        load-average-1 = 0.14 [FloatElement]
                        load-average-5 = 0.3 [FloatElement]
                        load-average-15 = 0.32 [FloatElement]
    deviceFamily = 'junos' [StringElement]
    isCluster = False [BoolElement]
    enableDiscardChanges = False [BoolElement]
    netconfConfirmedCommit = False [BoolElement]
>>> 

With this knowledge, we see that the following logic can be employed to check the result and extract the uptime from it:

if result.netconf.status == 'Success':
    # Get to the 'replyMsgData' element
    reply_msg = result.netConfReplies.netConfReply.replyMsgData

    # Get the 'system-uptime-information' element
    info = reply_msg['system-uptime-information']

    # Get the 'up-time' field
    uptime = info['uptime-information']['up-time']

    # Print uptime
    print(uptime)

The above code will print uptime as follows:

81 days,  3:40
Clone this wiki locally