
[[asset-topology]]
= Asset Topology Provider
:description: Learn how to set up and configure asset-based topologies via Karaf or events in {page-component-title}: GraphML, asset layers, and node filtering.

{page-component-title} lets users define arbitrarily complex layered topologies using http://graphml.graphdrawing.org/[GraphML] (see xref:development:graph/graph.adoc[]).
The Asset Topology Provider avoids the need for users to work directly with GraphML by directly generating a layered GraphML topology based on node parameters and the contents of the node asset table.
This simplifies the task for many use cases by allowing users to define fields in the node asset table, which lets you position nodes physically and logically in a complex topology.

The structure of the generated topology is determined by the `assetLayers` configuration constant.
To illustrate how this works, consider the following configuration:

[source, properties]
assetLayers=asset-region,asset-building

The {page-component-title} asset table is parsed to generate nested layers in the order of the comma-separated keys in the `assetLayers` property.
Each layer is a graph named after the key.
Graph nodes in each layer reference related graph nodes in the underlying layer.
The lowest layer contains graph nodes that are directly linked to monitored {page-component-title} nodes that have entries in the asset table.

The following diagram shows the structure of a topology generated by the above `assetLayers` property:

image::asset-topology/graphMLtopologyLayers.jpg["Diagram illustrating how node asset entries are interpreted as layers", 800]

In this example, the `region` asset fields for nodes 1, 2, 3, 4 are set to `north`.
All of these nodes are in the same north region.
The `building` asset fields for node 1 and node 2 are set to `21` (both nodes are in building 21), while the `building` asset fields for node 3 and node 4 are set to `22`.
The Asset Topology Provider generates four linked graphs for this configuration.
The layer 0 graph is called `asset-region`, the layer 1 graph is called `asset-building`, and the layer 2 graph is called `nodes`.

Conceptually, the topology is rendered as concentric sets.
The Asset Topology Provider first searches all of the nodes with regions defined and creates a new level 0 graph node representing each region found.
It then searches within each region to find the building entries and creates a corresponding level 1 graph node for each building name found.
Finally, it creates layer 2 nodes corresponding to each monitored node and places each in the correct building.

{page-component-title}-monitored nodes that have empty region or building asset fields cannot be placed correctly in this topology.
The previous diagram shows these nodes as unallocated nodes.
Finally, only building and region nodes are generated which can be linked to {page-component-title} nodes in the topology.
The Asset Topology Provider does not generate spurious graph nodes in upper layers that are not directly and completely referenced by {page-component-title} nodes in the lowest layer.

The following are example screenshots of a topology containing regions, buildings, racks, and nodes:

.Regions layer
image::asset-topology/AssetScreen1.png["{page-component-title} UI displaying the Regions layer of a topology graph", 900]

.Buildings layer
image::asset-topology/AssetScreen2.png["{page-component-title} UI displaying the Buildings layer of a topology graph", 900]

.Nodes layer
image::asset-topology/AssetScreen3.png["{page-component-title} UI displaying the Nodes layer of a topology graph", 900]

== Asset layers

The entries for `assetLayers` can be any node or asset entry from the following list (defined in the `NodeParamLabels` class).
Note that keys beginning with `node-` come from the node table; keys beginning with `parent-` come from the node table entry of the designated parent node (if defined); and keys beginning with `asset-`  come from the corresponding asset table entry for the given node (if defined).

[caption=]
.`assetLayers` keys
[options="autowidth"]
|===
5+| *Node Fields*

| node-nodelabel
| node-nodeid
| node-foreignsource
| node-foreignid
| node-nodesysname

| node-nodesyslocation
| node-operatingsystem
| node-categories
|
|

5+| *Parent Node Fields*

| parent-nodelabel
| parent-nodeid
| parent-foreignsource
| parent-foreignid
|

5+| *Node Asset Fields*

| asset-address1
| asset-address2
| asset-city
| asset-zip
| asset-state

| asset-latitude
| asset-longitude
| asset-region
| asset-division
| asset-department

| asset-building
| asset-floor
| asset-room
| asset-rack
| asset-slot

| asset-port
| asset-circuitid
| asset-category
| asset-displaycategory
| asset-notifycategory

| asset-pollercategory
| asset-thresholdcategory
| asset-managedobjecttype
| asset-managedobjectinstance
| asset-manufacturer

| asset-vendor
| asset-modelnumber
| asset-description
| asset-operatingsystem
| asset-country
|===

This lets you generate arbitrary topologies, including physical fields (room, rack) and logical fields (asset node tags).
Note that you should not put any spaces in the comma-separated `assetLayers` list.
If `assetLayers` is defined as empty, then a single graph layer is generated containing all {page-component-title} nodes.

== Node filtering

In many cases, you may want to control which nodes are included or excluded from a topology.
For instance, it's useful to be able to generate customized topologies for specific customers that include only regions or buildings, relevant to their filtered node set.
To this end, it is possible to define a node filter that chooses which nodes are included in a generated topology.

You can define filters using the same asset table keys that are available for `assetLayers`.

[caption=]
.Node filtering operations
[options="autowidth"]
|===
| Operation  | Definition   | Example

| OR
| key1=value1,value2 +
alternatively, key1=value1;key1=value2
| asset-region=north,south

| AND
| key1=val1;key2=val2
| asset-region=north;asset-building=23

| NOT
| key1=!val1
| asset-building=!23
|===

The following configuration includes only nodes with region north or south, but excludes all nodes with building 23:

[source, properties]
filter=asset-region=north,south;asset-building=!23

The filters treat comma-separated key values as an `OR` search.
Thus, you can select based on multiple separate node tags.

The following configuration includes routers and servers in all buildings except building 23:

[source, properties]
filter=node-categories=routers,servers;asset-building=!23

The filters treat all asset table entries as comma-separated variables.
This also means that, for instance, `asset-displaycategory` could also contain several values separated by commas (for example, `customer1,customer2,customer3`).

NOTE: Make sure that asset addresses and other free-format asset text fields do not contain commas if you want an exact match on the whole field.

Regular expressions, indicated by a prepended tilde (`~`), are also allowed.
You can also negate a regular expression by preceding it with `!~`.

The following example matches against regions "Stuttgart" and "Isengard" and any building name that ends in 4:

[source, properties]
filter=asset-region=~.*gar(t|d);asset-building=~.*4

== Configuration

The Asset Topology Provider persists both the asset topology graph definitions and the generated GraphML graphs.
This means that it is possible to regenerate graphs without re-entering the configuration if the asset table changes.

The Asset Topology Provider persists GraphML graphs alongside any other GraphML graphs in `$\{OPENNMS_HOME}/etc/graphml`.
Note that if you use REST or any other means to generate other GraphML graphs, you should ensure that the `providerIds` and labels are distinct from those that the Asset Topology Provider uses.

The asset graph definitions for the Asset Topology Provider are persisted to `$\{OPENNMS_HOME}/etc/org.opennms.features.topology.plugins.topo.asset.xml`.
Normally, you should use the Karaf shell or events to define new graphs, rather than editing this file directly.

The configuration file contains each of the graph definitions as properties in the following format:

[source, xml]
----
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configs>
    <config>
        <label>Asset Topology Provider</label>
        <breadcrumb-strategy>SHORTEST_PATH_TO_ROOT</breadcrumb-strategy>
        <provider-id>asset</provider-id>
        <preferred-layout>Grid Layout</preferred-layout>
        <filters>
            <filter>asset-region=South</filter>
        </filters>
        <layers>
            <layer>asset-region</layer>
            <layer>asset-building</layer>
            <layer>asset-rack</layer>
        </layers>
    </config>
</configs>
----

The following table describes individual definition parameters:

[options="autowidth"]
|===
| Parameter | Description

| providerId
| The unique name of the provider.
Used as a handle to install and remove the topology.

| label
| The name that shows up on the topology menu.
Must be unique.

| assetLayers
| List of asset layers, in order.

| filters
| List of filters to apply.

| preferredLayout
| Preferred node layout in generated graphs.

| breadcrumbStrategy
| Breadcrumb strategy used to display breadcrumbs above each graph.
|===

=== Create asset-based topologies via Karaf shell

You can use the {page-component-title} Karaf shell to control topology generation.

.SSH to {page-component-title} Karaf shell
[source, console]
ssh admin@localhost -p 8101

The following commands are available:

[cols="2,2,3"]
|===
| Command   | Description   | Options

| opennms:asset-topo-create
| Creates asset topology.
Uses the default settings if a tag is not included in the command.^1^
| *-l, --label:* Asset topology label (displayed in topology menu).
Default: `asset`. +
*-i, --providerId:* Unique `providerId` of asset topology.
Default: Asset Topology Provider. +
*-f, --filter:* Optional node filter.
Default: _Empty_. +
*-a, --assetLayers:* Comma-separated list of asset layers.
Default: `asset-region,asset-building,asset-rack`. +
*-p, --preferredLayout:* Preferred layout.
Default: Grid Layout. +
*-b, --breadcrumbStrategy:* Breadcrumb strategy.
Default: `SHORTEST_PATH_TO_ROOT`.

| opennms:asset-topo-remove
| Removes asset topology.
| *-i, --providerId:* Unique `providerId` of the asset topology.
Default: `asset`.

| opennms:asset-topo-list
| Lists all installed asset topologies.
| *all:* Display detailed view, including `--uriParams` string.

| opennms:asset-topo-regenerate
| Regenerates the graphs for the given asset topology definition.
| *-i, --providerId:* Unique `providerId` of the asset topology to regenerate.
Default: `asset`.

| opennms:asset-topo-regenerateall
| Best-effort regeneration of all asset topologies.
If one graph fails, the command tries to complete the rest of the definitions.
|
|===

. If you type `asset-topology:create`, a default topology is created using `providerId`.

== Create asset-based topologies via events

The Asset Topology Provider listens for events that trigger the generation and installation or removal of topologies.
These events are defined in `$\{OPENNMS_HOME}/etc/events/GraphMLAssetPluginEvents.xml`, and use the default parameters if none are supplied.

Use the following commands to create a new topology from your current {page-component-title} inventory:

.Create topology using default parameters
[source, console]
sudo ./send-event.pl  uei.opennms.plugins/assettopology/create localhost

.Create topology with defined parameters
[source, console]
sudo ./send-event.pl  uei.opennms.plugins/assettopology/create localhost  -p 'providerId test' -p 'label test' -p 'assetLayers asset-country,asset-city,asset-building'-->

You can also use the following parameters:

[source, console]
----
-p 'filters asset-displaycategory=!testDisplayCategory'
-p 'preferredLayout Grid Layout'
-p 'breadcrumbStrategy SHORTEST_PATH_TO_ROOT'
----

=== Uninstall topologies

Use the following commands to uninstall an asset topology:

.Uninstall using default `providerId`
[source, console]
sudo ./send-event.pl  uei.opennms.plugins/assettopology/remove localhost

.Uninstall using defined `providerId`
[source, console]
sudo ./send-event.pl  uei.opennms.plugins/assettopology/remove localhost -p 'providerId test'

=== Regenerate topologies

Use the following commands to regenerate an existing asset topology:

.Regenerate using default `providerId`
[source, console]
sudo ./send-event.pl  uei.opennms.plugins/assettopology/regenerate localhost

.Regenerate using defined `providerId`
sudo ./send-event.pl  uei.opennms.plugins/assettopology/regenerate localhost-p 'providerId test'

To regenerate all existing asset topologies, use the following command:

[source, console]
sudo ./send-event.pl  uei.opennms.plugins/assettopology/regenerateall localhost

== View the topology

After you install a topology and refresh your screen, you should see a new topology display option in the {page-component-title} Topology page.
The `label` field provides the topology's display name.
It does not have to be the same as the `providerId` that the REST API uses to install or remove a topology; however, the `label` field must be unique across all installed topologies.

It's possible to have several topologies installed that have been generated using different configuration settings.
You must ensure that the `providerId` and `label` fields used for each installation command are unique.

== Additional notes

Note that you must first uninstall an {page-component-title} GraphML topology before installing a new one.
You will also have to log out and log back in to the web UI to see the new topology file.

If you uninstall a topology while viewing it, the UI generates an error.
You will also have to log out and back in to see the remaining topologies.
