The Junos Space platform monitors its network devices and updates a common data model whenever there is a change in state of a device, such as with the device's configuration or inventory. Junos Space applications can subscribe to device change notifications so that whenever a device state changes, the subscribed application receives a notification. The application can use this information about the change to update their own data models.
The state of a device includes its:
Two mechanisms are available for subscribing to device change notifications:
Subscribe to device change notifications using REST APIs. Once the subscription is registered, notifications are generated for the subscribed XPaths whenever the device changes. This XPath refers to node changes in the states for any of the managed devices. The xpath-filter element takes XML as a string specifying the XPath filters. This input XML should comply with the schema. See the following example:
HTTP POST /api/space/device-management/subscribe-change-notifications
Content-Type: application/vnd.net.juniper.space.device-management.
subscribe-change-notifications+xml;version=1;charset=UTF-8
<subscribe-change-notifications>
<appName>REST</appName>
<xpath-filter><![CDATA[
<app-interest-spec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xml-app-interest-spec.xsd">
<app-name>REST</app-name>
<schemas>
<schema type="system-information">
<dmi-node xpath="/system-information" type="STRING" />
<dmi-node xpath="/system-information/host-name" type="STRING" />
</schema>
</schemas>
</app-interest-spec>
]]>
</xpath-filter>
</subscribe-change-notifications>
200 OK
The following table describes the appropriate nodes and attributes for app-interest XSD. (Note: Nodes are shown in bold text, and required attributes are listed under related nodes.) For more information, see XSD schema.
NODES | DESCRIPTION |
---|---|
app-interest-spec | This node is the root element of the registration file. |
app-name | This attribute specifies the name of the application registering the xpaths. For registration using REST, it is just a string to identify your registration. |
schemas | This node is the container for the schema nodes described below. |
schema | This represents the schema node. |
device-family | This attribute represents the device's family. |
name | This attribute is a simple string representing the name for the collection of xpaths. |
override | This attribute overrides the name common to more than one device family to list it separately. |
type | This attribute represents the value of the configuration. It can have any of these values: configuration, interface-inventory, logical-interface-inventory, hardware-inventory, software-inventory, license-inventory, system-information. |
dmi-node | This node registers the xpath of elements. |
blob | This attribute registers the child nodes of a particular node to receive the change notification. |
exclude | This attribute excludes the xpath from the blob node. |
key | This attribute represents the key node registered for the collection type. |
type | This attribute represents the type of the node for a configuration schema xpath. It can be either string or collection. |
override | This attribute overrides the name common to more than one in the registered xpath schema. |
preserve | This attribute preserves a single or all child nodes in different results even if they have changed or not. For a single child node, you provide the value as "SELF", and for all the child nodes, you can provide RECURSIVE. |
xpath | This attribute registers the device knobs for change notifications. |
You can a create a HornetQ queue over REST using the /api/hornet-q service. For more information about creating a queue, see "Enabling Notifications" in the Junos Space SDK Application Developer Guide.
HTTP POST /api/hornet-q/queues
Content-Type: application/hornetq.jms.queue+xml
<queue name="testq">
<durable>false</durable>
</queue>
201 Created
After creating a HornetQ queue, the REST client needs to subscribe to a device-change topic and use a selector for the JMS Property interested_app_names. The selector should be the same as the app-name provided when registering for the device change notification. See the following example:
HTTP POST /api/hornet-q/topics/jms.topic.device-change/push-subscriptions
Content-Type : application/xml
<push-topic-registration>
<durable>false</durable>
<selector><![CDATA[
interested_app_names like '%REST%'
]]>
</selector>
<link type="application/xml" rel="destination" href="http://127.0.0.1:8080/api/hornet-q/queues/jms.queue.testq" />
</push-topic-registration>
201 Created
After subscribing to a device-change topic, REST clients should poll the HornetQ queue. They will receive DeviceChangeDiffResult as XML or JSON on the queue when any change occurs on the registered XPath nodes. To learn about polling a HornetQ queue, see "Enabling Notifications" in the Junos Space SDK Application Developers Guide.
Alternatively you can register for device change notifications using a static XML file.
<app-interest-spec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xml-app-interest-spec.xsd">
<app-name>Sample_App</app-name>
<schemas>
<!-- Your xpath node filter should go here for example
<schema type="configuration" device-family="junos">
<dmi-node xpath="/configuration/groups/name"/>
<dmi-node xpath="/configuration/groups/rcsid"/>
<dmi-node xpath="/configuration/groups/system"/>
</schema>
-->
</schemas>
</app-interest-spec>
The Junos Space platform sends device change notifications to Junos Space applications through the JMS. The platform uses a single topic-named device change to broadcast device changes to all subscribed applications. To receive device change notifications for your application, an MDB is created to listen to the device-change topic.
The platform provides a base MDB to listen to the device-changeBaseMDB topic. Applications interested in receiving the device change notification need to create their own MDB to listen to this device-change topic. This MDB should extend from the base MDB (device-changeBaseMDB) and implement the following abstract methods:
METHOD | DESCRIPTION |
---|---|
boolean handleDeviceChange(DeviceChangeDiffResult diffResult) | Allows applications to process device change results. It would have a filtered diff based on the XPath provided during registration. |
void setDeviceStatus(Integer deviceId, ApplicationDeviceStatus status) | Allows Junos Space applications to set the status of their (application specific) device as 'out of sync' or 'in sync'. On receiving the message, the base MDB first calls the setDeviceStatus method to mark the device as ‘out-of-sync’ by setting the status parameter to ApplicationDeviceStatus.DEVICE_STATE_OUT_OF_SYNC. |
String getApplicationName() | Allows you to request the application name. Ensure that it exactly matches the one specified in the app-interest registration file under the <app-name> node. |
When a device change message is received, the MBD calls the setDeviceStatus method and sets the status parameter to ApplicationDeviceStatus.DEVICE_STATE_OUT_OF_SYNC. The setDeviceStatus method allows the application to set its own device status in the database as either "out of sync" or "in sync". The application should have its own device entity.
Next handleNotification() is called, passing the DeviceChangeDiffResult result. The DeviceChangeDiffResult method retrieves the different XML strings and XML differences. The applications can process the device change diff result inside the handleDeviceChange method.
Finally, on a successful response, the setDeviceStatus method is called again to mark the state of the device as "in-sync". Therefore, the status parameter is returned as ApplicationDeviceStatus.DEVICE_STATE_IN_SYNC.
@MessageDriven(name = "SampleAppMDB",
activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "topic/device-change"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "NonDurable"),
@ActivationConfigProperty(propertyName = "messageSelector", propertyValue=
"interested_app_names LIKE '%Sample_App%'")
})
public class SampleAppMDB extends net.juniper.jmp.cmp.deviceChange.DeviceChangeBaseMDB
{
public boolean handleDeviceChange( DeviceChangeDiffResult result )
{
/* result parameter will have filtered difference based on xpath
provided during device-change registration,
*/
return true;
}
public void setDeviceStatus(Integer deviceId, ApplicationDeviceStatus status)
{
/* set the status of (application specific) device as 'out of sync' or 'in sync'*/
}
public String getApplicationName()
{
/* Application name should match the name specified in
app interest registration file under <app-name> node.
*/
return "Sample_App";
}
}
Here is the outline of the DeviceChangeDiffResult class:
DeviceChangeDiffResult{
private Integer deviceId;
private String diffResults;
public Integer getDeviceId() {
return deviceId;
}
/* first element in map represents the schemaName and the second xml diff*/
public Map<String, String> getDiffResults() {
return diffResults;
}
/* Returns list of xpaths that has changed in this diff result */
public Set<string> getChangedXPaths(){
//implementation
}
}
MBD override methods list nodes that are common to more than one device family. For example, if an application wants to register the following xpaths for both the junos and ext-junos device families.
You can list these xpaths under a common schema node and then
include this common node for both device families with the override
attribute as shown in the following example.
<app-interest-spec xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xml-app-interest-spec.xsd">
<app-name>CEMS</app-name>
<schema type="configuration" name="common-nodes" >
<dmi-node xpath="/configuration/routing-instances/instance/name"/>
<dmi-node xpath="/configuration/routing-instances/instance/instance-type"/>
</schema>
<schema type="configuration" device-family="junos" override="common-nodes">
/*other dmi xpaths for junos */
...
...
</schema>
<schema type="configuration" device-family="ext-junos" override="common-nodes">
<dmi-node xpath="/configuration/vlans/vlan/name"/>
/*other dmi xpaths for ext-junos*/
...
...
</schema>
</app-interest-spec>
Note: The common schema node must have a name. The same name should be specified as a value of the override attribute.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="app-interest-spec" type="appInterestRegistration"/>
<xs:complexType name="appInterestRegistration">
<xs:sequence>
<xs:element name="app-name" type="xs:string" minOccurs="0"/>
<xs:element name="schemas" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="schema" type="schemaNode" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:complexType name="schemaNode">
<xs:sequence>
<xs:element name="dmi-node" type="dmiNode" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="device-family" type="xs:string"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="override" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="dmiNode">
<xs:sequence>
<xs:element name="exclude" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="blob" type="xs:boolean"/>
<xs:attribute name="exclude">
<xs:simpleType>
<xs:list itemType="xs:string"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="key">
<xs:simpleType>
<xs:list itemType="xs:string"/>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="override" type="overrideDmiNodeEnum"/>
<xs:attribute name="preserve" type="preserveDmiNodeEnum"/>
<xs:attribute name="xpath" type="xs:string" use="required"/>
</xs:complexType>
<xs:simpleType name="overrideDmiNodeEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="REMOVE"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="preserveDmiNodeEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="SELF"/>
<xs:enumeration value="RECURSIVE"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>