14. Java classes that can be accessed from Python scripts

14.1. Summary

Java classes that can be accessed from Python scripts that build monitoring variables, process monitoring data or build reports.

Even though these are Java classes, they have method __getattr__() that provides standard “Pythonic” way to access their properties as class attributes. That is, you can call both Java “getter” method:

device.getName()

and access the same property as an attribute:

device.name

We also provide method get() that works exactly like __getattr__() and is intended for Velocity templates used to build reports. This means you can write:

$device.name

in the report template instead of:

$device.getName()

both methods will work though.

Since these wrapper classes are intended to be used with Python scripts, some attributes were given alternative names to conform with PEP8. For example, attribute PyDevice.sys_name is mapped to the Java getter method PyDevice.getSytsName(). This document lists only attribute names.

14.2. Classes and Functions

14.2.1. MonitoringVariable

class net.happygears.nw2.py.MonitoringVariable

This class represents single instance of a monitoring variable. An object of this class holds information about one interface, hardware component, a protocol counter or any other entity that we monitor.

14.2.1.1. Attributes

device

The name of the device this variable instance collects monitoring data for

component

The name if the interface or hardware component this variable collects monitoring data for.

iface

This attribute returns the same value as MonitoringVariable.component. This attribute is deprecated and will be removed in future versions, please use MonitoringVariable.component instead.

ds

Reference to an instance of class DataSource (see below)

statistics

net.happygears.nw2.py.Statistics object (see below)

timeseries

net.happygears.nw2.time_series_buffer.TimeSeries object (see below)

tags

Tags: unmodifiable set of strings, each string is in the form “TagFacet.TagWord” Use this attribute to check if the variable has a tag using Python in operator:

1
2
if 'Vendor.Cisco' in mvar.tags:
    # do something if this is Cisco device

To add new tag to the variable use method addTag()

14.2.1.2. Instance Methods

Not all methods of the Java class MonitoringVariable are accessible from Python. Here are few that can be useful:

addTag(tag_string)

Add tag to the variable. Tag should be in the form of a two-component string, speparated with a dot: Facet.Word. Examples:

1
2
3
Vendor.Cisco
ColorLevel.1
ifOperStatus.Up

For example:

mvar.addTag('Aggregate.PaidPeering')
removeTag(tag_string)

Remove given tag from the set of tags of the variable. Note that this does not nothing if the tag belongs to the device or its component (those are read-only).

getTags(facet)

return unmodifiable set of tags that belong to the specified tag facet. This is different from the attribute tags: or method getTags() (with no arguments) that returns full set of tags of the variable, call to getTags() returns only subset of tags that belong to the specified tag facet. For example, you can get ifIndex of the parent interface this way:

1
2
3
4
assert isinstance(var, MonitoringVariable)
for tag in var.getTags('ifParent'):
    # tag looks like 'ifPArent.5', where the number is ifIndex of parent interface
    parent_if_index = int(tag.split('.')[1])
add(observation)

Append new observation to the end of the list MonitoringVariable.timeseries

add(observations)

Merge observations from the list observations with observations in the list MonitoringVariable.timeseries. This method sorts observations by the time stamp and makes sure new ones are inserted in the right position. Old and new observations with identical timestamp are deduplicated.

double getMinValue()

calculates and returns minimum value by comparing values of all observations in the time series of this monitoring variable stored in the memory buffer. Returns result as a number

double getMaxValue()

calculates and returns maximum value by comparing values of all observations in the time series of this monitoring variable stored in the memory buffer. Returns result as a number

__cmp__(other)

compare values of the latest data points in time series of self and other. This makes it possible to sort lists of MonitorngVariable instances or use built-in Python functions max() and min().

__cmp__(value)

compare value of the latest data point in the time series of self with constant.

__add__(other)
__sub__(other)
__mul__(other)
__div__(other)

Arithmetic operations between latest values of the time series of two MonitoringVariable objects this and other. All these functions return copy of this with time series modified so it has just one data point with calculated value. tags in the variable retain their values only if they are the same in this and other (in other words, after the call to these functions the set of tags is an intersection of sets of tags of two operands before the call). These functions enable calls to Python built-ins sum(), reduce() and others. For example, call to sum() can be used to to calculate sum of values of monitoring variables instances in a list.

__add__(k)
__sub__(k)
__mul__(k)
__div__(k)

The same as the above, but operates with constant k as a second argument.

__radd__(k)
__rsub__(k)
__rmul__(k)
__rdiv__(k)

These versions of the arichmetics functions operate with reversed arguments and enable Python expressions such as:

1
2
k + mvar
k * mvar

where k is a constant and mvar is an instance of MonitoringVariable. These magic functions make it possible to write in Python:

aggregate_var = aggregate_var + input_traffic_rate * 60

where both aggregate_var and input_traffic_rate are both instances of MonitoringVariable. Expression used in this example can be used to calculate total amount of input or outputtraffic (in bytes) through interface. This formula can be used in combination with call to reduce().

14.2.2. Statistics

class net.happygears.nw2.py.Statistics

Object of this class provides functions that can be used to perform basic statistical calculations over the time series of the parent monitoring variable. Example:

1
2
3
4
5
def is_outlier(mvar, value, n_sigmas):
    assert isinstance(mvar, MonitoringVariable)
    mean = mvar.statistics.mean()
    sigma = mvar.statistics.sigma()
    return value != mean and abs(value - mean) >= (n_sigmas * sigma)

14.2.2.1. Methods

double mean()

returns a number equal to the mean value of observations in the whole time series stored in memory. Observations with value NaN are skipped. Note that this operates only on the data in memory. The length of the time series in memmory is determined by the value of configuration parameter monitor.storage.retentionHrs

double mean(begin, length)

returns a number equal to the mean value of length non-NaN observations in the time series beginning with observation with index begin. Observations with value NaN are skipped and do not count towards length. If begin + length extends beyond the end of the time series buffer, this function stops at the last element. Note that this operates only on the data in memory.

double median()

returns a number equal to the median value of observations in the whole time series stored in memory. Observations with value NaN are skipped. Note that this operates only on the data in memory. The length of the time series in memmory is determined by the value of configuration parameter monitor.storage.retentionHrs

double median(begin, length)

returns a number equal to the median value of length non-NaN observations in the time series beginning with observation with index begin. Observations with value NaN are skipped and do not count towards length. If begin + length extends beyond the end of the time series buffer, this function stops at the last element. Note that this operates only on the data in memory.

double sigma()

returns a number equal to the standard deviation of values of observations in the whole time series stored in memory. Observations with value NaN are skipped. Note that this operates only on the data in memory. The length of the time series in memmory is determined by the value of configuration parameter monitor.storage.retentionHrs

double sigma(begin, length)

returns a number equal to the standard deviation of length non-NaN observations in the time series beginning with observation with index begin. Observations with value NaN are skipped and do not count towards length. If begin + length extends beyond the end of the time series buffer, this function stops at the last element. Note that this operates only on the data in memory.

14.2.3. TimeSeries

class net.happygears.nw2.time_series_buffer.TimeSeriesBuffer

Object of this class represents single time series, that is, a set of timestamp-value pairs that represents monitoring data collected for single net.happygears.nw2.py.MonitoringVariable instance. This behaves like a list where items are objects of the class net.happygears.nw2.py.Observation, so you can iterate over it and access items by index. Unlike in case of the standard Python lists, functions that access observations return a copy of the data stored in the time series. You do not need to create objects of this class manually, instead, you always access them as attribute timeseries of net.happygears.nw2.py.MonitoringVariable:

1
2
3
assert isinstance(mvar, MonitoringVariable)
for observation in mvar.timeseries:
    print observation

14.2.3.1. Methods

long getLastTimeStamp()

returns time stamp of the last observation in the time series

double getLastValue()

returns value of the last observation in the time series. This can be a NaN.

getLastNonNaNValue()

Return value of the latest observation that is not a NaN regardless of its timestamp and how far back in time that was

boolean isLastNaN()

checks if the last observation in the time series is a NaN.

void put(long timestamp, double value)

Puts new observation into the time series buffer

void clear()

clears time series buffer.

Observation first()

returns first observation as Observation object

Observation last()

returns last observation as Observation object

long getTimeStamp(int idx)

returns time stamp of the observation identified by its index idx

double getValue(int idx)

returns value of the observation identified by its index idx

double getLastValue()

returns the value of the last observation in the time series. If the time series holds numeric values, this function returns the last one. If the time series holds strings, this function returns NaN.

String getLastValueAsString()

returns the value of the last observation in the time series. This function returns string representation of the last value regardless of its type, that is, if the time series holds numeric values, this function returns formatted value as a string.

Observation get(int idx)

returns observation identified by its index idx as Observation object

void updateLastValue(final double value)

update value of the last observation in the buffer

double getMinValue()

calculates and returns minimum value by comparing values of all observations in the time series buffer. Returns result as a number

double getMaxValue()

calculates and returns maximum value by comparing values of all observations in the time series buffer. Returns result as a number

14.2.3.2. Python “magic” methods

__len__()

returns the size of the time series

__nonzero__()

returns true if the time series is not empty. This function enables the following Python expression:

1
2
if mvar.timeseries:
    # do something when time series is not empty
Observation __getitem__(int key)

returns Observation object identified by its index key. With this function we can access observations in the time series as if it was a list:

mvar.timeseries[1]

negative index is also supported:

mvar.timeseries[-1]

slices are supported too:

mvar.timeseries[1:10]

14.2.4. Observation

class net.happygears.nw2.py.Observation

14.2.4.1. Attributes

timestamp

a time stamp in milliseconds (long)

value
value of the observation. This is stored as an instance of Java class Number and can be used in Python directly. This can be NaN.

14.2.4.2. Methods

Observation(timestamp)
Parameters:timestamp – observation time stamp (time in milliseconds)

Create an Observation object with given timestamp and value of NaN

Observation(timestamp, value)
Parameters:
  • timestamp – observation time stamp (time in milliseconds)
  • value – observation value (a number)

Create an Observation object with given timestamp and value

isNaN()

Returns True of the value of this Observation is NaN.

14.2.4.3. Python “magic” methods

__cmp__(other)
__eq__(value)
__ne__(value)
__lt__(value)
__le__(value)
__gt__(value)
__ge__(value)

“rich” comparison methods are supported and compare Observation value, ignoring its timestamp.

__str__(other)

Return string representation of the Observation, useful for logging and reports. Timestamp is printed in seconds.

14.2.5. DataSource

class net.happygears.nw2.py.DataSource

Instance of this class are creaeted internally when the system prepares monitoring variables used for device polling. MonitoringVariable instances hold reference to the instance of DataSource class. You should not need to create objects of this class in the Python script.

14.2.5.1. Attributes

name
The name of the data source. This matches the name of the interface or hardware component this data source describes.
index
index is equal to ifIndex if Data Source corresponds to an interface or some kind of unique index of hw component that we have learned while discovering device components.
container

Container describes hw component that contains the component named by attribute “name”. Not all components have containers, this depends on the device vendor.

description
Component description. In case of an interface, this is interface description.
unit

Units in which collected data is measured. For example, for the variables that collect data from temperature sensors, this could be ‘C’.

14.2.6. DataScaler

class net.happygears.nw2.py.DataScaler
DataScaler(DataSource ds)
Parameters:ds (DataSource) – input DataSource object

this scaler takes into account pre-set data range it takes from the data source. Since it does not have access to the timeseries, it can not take into account actual values.

14.2.6.1. Methods

DataScaler(MonitoringVariable mvar)
Parameters:mvar (MonitoringVariable) – monitoring variable to take values from

this constructor has access to both DataSource object (a member of MonitoringVariable) and timeseries. Scaler will compute the range using actual values of observations in the time series

DataScaler.scaleValue(Observation o)
Parameters:o (Observation) – input Observation object

Takes an Observation object and returns a number equal to the scaled value of this observation

DataScaler.getPrefix()

returns calculated prefix.

DataScaler.getUnit()

returns the same basic unit it copies form the DataSource object

Example:

1
2
3
4
assert isinstance(mvar, MonitoringVariable)
scaler = DataScaler(mvar)
value = mvar.last()
print scaler.scaleValue(value) + ' ' + scaler.getPrefix() + scaler.getUnit()

14.3. Wrappers

The following classes are Python wrappers for the Java classes used to hold information about devices, network interfaces, hardware components etc. These classes are used in variable and view builder scripts.

14.3.1. PyDevice

class net.happygears.nw2.py.py_wrappers.PyDevice

14.3.1.1. Attributes

name

Device name. This can be one of the following:

  • if config file nw2.conf mentions this device by name, then the value of this attribute is taken from the config.
  • if the device is configured by its ip address, then the program tries to use the value returned by sysName OID when we discover the device. This is usually the “hostname” configured on the device.
  • if we could not get the value of sysName, then the program runs reverse DNS lookup for the address of the device and assigns the result to this attribute.
  • if reverse DNS lookup query fails, the value of this attribute is equal to the ip address of the device.
sys_name

Device name returned by the System MIB sysName OID. This is usually host name configured on the device

reverse_dns

DNS PTR record configured for this device’s IP address

hostname

Device name with all domain parts stripped. If device is configured with short host name, the value of this attribute is equal to it. If the host name configured on the device is really FQDN, then this attribute is equal to its leftmost component.

location

Device location configured in the System MIB sysLocation OID

contact

Contact name configured in the System MIB sysContact OID

sys_descr

Device description returned by the System MIB sysDescr OID.

box_descr

Device’s hardware description

sw_rev

Software revision running on the device

address

IP address used to communicate with the device

tags
Tags of this device as a set of strings. You can manipulate tags by adding or removing items of this set. Setting new value to this attribute is not supported.

14.3.1.2. Instance Methods

getTagsInFacet(facet)

returns list of tags that belong to the specified tag facet. This is different from the attribute tags: where the attribute returns full set of tags of the variable, call to getTagsInFacet() returns only subset of tags that belong to the specified tag facet.

getNode()

returns reference to the underlying NetworkNode object.

forwardingClasses()

returns set of formwaridng class numbers configured on the device

getQueueNum(int fcNumber)
Parameters:fcNumber – forwarding class number

returns Cos queue number for the given forwarding class number

getFcName(int fcNumber)
Parameters:fcNumber – forwarding class number

returns forwarding class name for the given forwarding class number

getFcNumber(int queueNumber)
Parameters:queueNumber – queue number

returns forwarding class number for the given queue number

getVmHostName()

returns VM host name if this device is virtual machine, otherwise returns empty string

getPyInterfaces()

returns list of net.happygears.nw2.py.py_wrappers.PyNetworkInterface objects that represent network interfaces of this device

getInterface(int ifIndex)

return net.happygears.nw2.py.py_wrappers.PyNetworkInterface object that represents network interface with given ifIndex. If such interface does not exist, this method returns None.

14.3.2. PyNetworkInterface

class net.happygears.nw2.py.py_wrappers.PyNetworkInterface

14.3.2.1. Attributes

name
Interface name
description
Interface description
abbreviated_name

Abbreviated name of the interface. NetSpyGlass uses internal translation table to generate abbreviated names. For example, “GigabitEthernet” translates to “ge” and “TenGigabitEthernet” translates to “te”.

address

First address and netmask of the interface as a string in “address/prefixlen” notation

addresses

List of all addresses of the interface as strings in in “address/prefixlen” notation

tags
Tags of this interface as a set of strings. You can manipulate tags by adding or removing items of this set. Setting new value to this attribute is not supported.
if_index

Interface ifIndex

if_speed

Value returned by ifSpeed OID

if_high_speed

Value returned by ifHighSpeed OID if it is supported

isis_circuit

Id of ISIS circuit terminating on this interface

cos_queues

all QoS queues configured on the interface as a set of numbers

14.3.3. PyHardwareComponent

class net.happygears.nw2.py.py_wrappers.PyHardwareComponent

14.3.3.1. Attributes

name
Component name
index
Component index. This index is guaranteed to be unique within parent device. Hardware components and interfaces use separate indexes so h/w component index may conisidentally be the same as ifIndex of some interface. In most cases h/w component index is derived from the OID of the component but some times can be computed (this depends on the vendor and SNMP MIB used to discover the component)
description
Component description if available
model

Component model if available

oid

SNMP OID we use to query to get component status or current value if it is a sensor

sensor_scale

Values returned by queries to the oid are multiplied by this coefficient to normalize them. For example, if SNMP MIB says that some sensor reports value in units of 0.01A, then sensor_scale may be set to 100 to normalize values and record them in units of 1A. This makes it possible to maintain common database of values for devices from different vendoes that might report values in different units.

sensor_data_type

(a string) this attribute describes the unit this sensor uses and has one of the following values:

  • other
  • unknown
  • voltsAC
  • voltsDC
  • amperes
  • watts
  • hertz
  • celsius
  • percentRH
  • rpm
  • cmm
  • truthvalue
  • specialEnum
  • dBm

this list will grow over time as we add support for new sensors. If hardware component is not a sensor, the value of this attribute is “other”

component_class

(a string) this attribute describes high level class the component belongs to and can be one of the following:

  • other
  • unknown
  • chassis
  • backplane
  • container
  • powerSupply
  • fan
  • sensor
  • module
  • port
  • stack
  • cpu
  • opticalTransceiver
  • chassisAlarm
  • pdu
  • disk
  • memory

this list will grow over time as we add support for new component classes.

tags
Tags as a set of strings

14.3.4. PyChassisAlarm

class net.happygears.nw2.py.py_wrappers.PyChassisAlarm

net.happygears.nw2.py.py_wrappers.PyChassisAlarm is a special case of net.happygears.nw2.py.py_wrappers.PyHardwareComponent that has attribute component_class with value chassisAlarm. This object represents a counter of minor or major chassis alarms raised by the device. This class has all attributes of net.happygears.nw2.py.py_wrappers.PyHardwareComponent and one additional attribute:

14.3.4.1. Attributes

type

(a string) alarm type, can have values ‘major’ or ‘minor’

14.3.5. PyProtocolDescriptor

class net.happygears.nw2.py.py_wrappers.PyProtocolDescriptor

This class is an abstraction that describes parameter or a counter of a protocol. For example, this can be BGP peer state or number of BGP updates received from a peer and so on.

14.3.5.1. Attributes

name
Component name
index
Object index. This index is guaranteed to be unique within parent device. In most cases index is derived from the OID of the component but some times can be computed (this depends on the vendor and SNMP MIB used to discover the component)
description
Component description if available
oid

SNMP OID we use to query to get current value of the counter

sensor_scale

Values returned by queries to the oid are multiplied by this coefficient to normalize them.

protocol

(a string) the name of the network protocol, such as ‘OSPF’ or ‘BGP4’

14.3.6. PyNetworkGraph

class net.happygears.nw2.py.py_wrappers.PyNetworkGraph

Objects of this class wraps internal class that represents network topology graph.

14.3.6.1. Instance Methods

get_connected_device(device, intf)
Parameters:
Returns:

a tuple (opp_dev, opp_intf) where opp_dev is net.happygears.nw2.py.py_wrappers.PyDevice object that represents device on the opposite end of the network link terminated on dev:intf and opp_intf is an net.happygears.nw2.py.py_wrappers.PyNetworkInterface object that represents corresponding interface of opp_dev. If interface intf is not connected anywhere, this function returns None.

You can find example of this method usage in section User Defined Interface Tags: Parsing Interface Descriptions.

14.4. Examples

The following examples are taken from the interface variables builder script, you can find a copy of this script in python/variable_builders/interface.py in your NetSpyGlass installation.

Here is an example of a function that accesses network interface tags to check some conditions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def is_interesting_interface(self, intf):
    """
    This function implements some basic checks to decide if we want to monitor this interface

    :type intf: PyNetworkInterface
    :param intf: PyNetworkInterface wrapper object
    :return:  True if we want to monitor this interface
    """
    return ('ifAdminStatus.Up' in intf.tags and
            not 'ifRole.LoopbackInterface' in intf.tags and
            not 'ifRole.OutOfBandManagement' in intf.tags and
            not 'ifRole.SimulatedInterface' in intf.tags and
            not 'ifRole.Internal' in intf.tags)

Next example demonstrates access to attributes if_index and if_speed of network interface object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def make_basic_vars(self, intf):
    """
    Generate configuration for the basic set of monitoring variables
    for the interface: interface utilization, errors, discards

    :type intf: PyNetworkInterface
    :param intf: PyNetworkInterface wrapper object
    :return: a dictionary where the key is variable name and value is another dictionary
    """
    if_index = intf.if_index
    in_octets_oid = 'IF-MIB:ifInOctets.{0}'.format(if_index)
    out_octets_oid = 'IF-MIB:ifOutOctets.{0}'.format(if_index)
    if_speed_oid = 'IF-MIB:ifSpeed.{0}'.format(if_index)
    if_speed_scale = 1.0

    if intf.if_high_speed > 0:
        in_octets_oid = 'IF-MIB:ifHCInOctets.{0}'.format(if_index)
        out_octets_oid = 'IF-MIB:ifHCOutOctets.{0}'.format(if_index)
        if_speed_oid = 'IF-MIB:ifHighSpeed.{0}'.format(if_index)
        if_speed_scale = 1E6  # ifHighSpeed is in 1,000,000 bits/sec

    return {
        # ---------------------------------------------------------------
        'ifSpeed': {
            'component': intf,
            'snmp_oid': if_speed_oid,
            'scale': if_speed_scale
        },

        'ifHCInOctets': {
            'component': intf,
            'snmp_oid': in_octets_oid
        },

        'ifHCOutOctets': {
            'component': intf,
            'snmp_oid': out_octets_oid
        }
    }