NetSpyGlass Server JSON API *************************** .. highlight:: json :linenothreshold: 2 .. role:: python(code) :language: python .. toctree:: :maxdepth: 1 API v2.0 ======== Status call ----------- GET /v2/ui/net/:id/status[?s=order] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ retrieve status. This includes defined network, latest discovery status, information about ongoing network discovery (if any), and views. The UI uses this API call to build the "home" page where each map view appears as a tile. List of views (tiles) can be sorted according to the optional parameter `s`. Sort order is defined by the value, which can be 'name' or 'id'. Sorting by the id makes views appear in the order in which they were created. If parameter `s` is not provided, views are sorted by the id. Network topology and inventory (discovery data) ----------------------------------------------- GET /v2/discovery/net/:id/topo?[timestamp=:time|generation=:gen] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns network topology data in json format. Each device is represented by a brief summary that includes its name, address, id and tags. Each link is represented by a set of the following parameters: source device id, destination device id, source interface ifIndex, destination interface ifIndex, and vlan number. Optional query parameters: - `timestamp` if this parameter has value >0, then this call returns topology data from the latest discovery that has completed before the timestamp - `generation` if this parameter has value >0, then this call returns data from the discovery with this generation number. If both `timestamp` and `generation` are missing, or ``timestamp==0`` and ``generation==-1``, then this method returns topology data from the latest successful discovery. If both ``timestamp > 0`` and ``generation > 0``, this method uses the timestamp GET /v2/discovery/net/:id/devices[?timestamp=:time|generation=:gen] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns information about monitored devices (discovery data). Optional parameters `timestamp` and `generation` can be used to retrieve device data that corresponds to particular discovery generation GET /v2/discovery/net/:id/devices/:devid[?timestamp=:time|generation=:gen] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns information about device identified by its id (discovery data). Optional parameters `timestamp` and `generation` can be used to retrieve device data that corresponds to particular discovery generation Calls used by the UI to access information about devices -------------------------------------------------------- GET /v2/ui/net/:id/dashboards/device/:id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call serves the first ("Summary") page of the device panel GET /v2/ui/net/:id/data/device/:devid?[format=(brief|full)][category=:name] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns information about device identified by its id (discovery data) with ability to choose format. GET /v2/ui/net/:id/popup/device/:devid ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call returns information used to build popup graph that opens when user clicks device label in maps. This popup displays graph built with monitoring data. GET /v2/ui/net/:id/popup/device/:devid/hwcomp/:idx ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call returns information used to build popup graph that opens when user clicks device label in maps. This call returns list of monitoring variables that have non-empty time series for the device identified by :devid and its hardware component with index :idx. If :idx < 0, then this call returns list of all variables with non-empty time series for all hardware components of the device. GET /v2/ui/net/:id/popup/device/:devid/intf/:ifIndex ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call returns information used to build popup graph that opens when user clicks link label in maps. This popup displays graph built with monitoring data. Map Views --------- GET /v2/ui/net/:id/views[?type=:view_type] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call returns list of views owned by the current user (or all views if the server runs w/o user authentication). Views can be optionally limited to those of particular type. The `view_type` parameter is a string that can have one of the following values: - `SYSTEM` - `SCRIPTED` - `INTERACTIVE` the type should not be quoted. Returned data has the following format:: [ { "id" : 3, "name" : "backbone", "devRule" : "", "linkRule" : "", "type" : "SCRIPTED", "editable" : false, "updatedAt" : 1490122101000, "layoutUpdatedAt" : 1490585179000, "formData": "" }, { "id" : 4, "name" : "Datacenter A", "devRule" : "", "linkRule" : "", "type" : "SCRIPTED", "editable" : false, "updatedAt" : 1490122101000, "layoutUpdatedAt" : 1490585177000, "formData": "" } ] GET /v2/ui/net/:id/views/:view_id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call returns information about view identified by its id in the same format as previous call. Returned data is a list of one item:: [ { "id" : 17, "name" : "new view 17", "devRule" : "", "linkRule" : "", "type" : "INTERACTIVE", "editable" : true, "updatedAt" : 1490662954000, "layoutUpdatedAt" : 1490662954000, "formData": "" } ] POST /v2/ui/net/:id/views ^^^^^^^^^^^^^^^^^^^^^^^^^ Create new blank map view. The view is created with all default parameters so no information is expected in the request body or parameters. This call returns HTTP status OK if it was successful and new view id in the response body:: { "status": "ok", "id": 1234 } POST /v2/ui/net/:id/views/:view_id/update ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Update the view. Information about it is passed via request body in the following format:: { "name": "view name", "devRule": "NsgQL matching expression for devices", "linkRule" : "NsgQL matching expression for interfaces", "adjacent": "true|false", "connecting": "true|false", "formData": "some form data" } Since view Id is passed via URL path, it is not needed in the request body. However it is not an error if it is present there. Attribute `formData` is an opaque text string passed from the UI. This can be json-encoded contents of the view editor form. Calls `GET /v2/ui/net/:id/views/:view_id` and `GET /v2/ui/net/:id/views/` return this information as-is. This call returns status 200 when operation was successful, or "Bad Request" error with body in case of error:: { "status" : "error", "error": "error text" } DELETE /v2/ui/net/:id/views/:view_id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Delete the view identified by its id. No information in the request body is expected. POST /v2/ui/net/:id/views/:view_id/share ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ share view identified by its id with other users. The view is identified by its id in the URL and no information in the request body is expected. Only the user who created this view can share it. Views created by Python scripts are shared by default and can not be shared via this API call. Returns status 200 when operation was successful, or "Bad Request" error with body in case of error:: { "status" : "error", "error": "error text" } .. note:: When a view is created and saved by the user, it still remains "private". This means when a user connects to the server and loads the UI, this view appears in the list of tiles in the home page only ifthe operation is performed by the same user who created it. However, if user shares the view, then it becomes visible to all users registered in the system. POST /v2/ui/net/:id/views/:view_id/unshare ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unshare view identified by its id. Only views created in the UI and owned by the currnely logged in user can be unshared. POST /v2/ui/net/:id/views/:view_id/validate ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Validate the view. Information about it is passed via request body in the same format as the call `POST /v2/ui/net/:id/views/:view_id/update`. This call returns status 200 when operation was successful, or "Bad Request" error with body in case of error:: { "status" : "error", "error": "error text" } GET /v2/ui/net/:id/views/:view_id/map[?timestamp=:time] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns information used to build network map in the UI for the view identified by its id and optional time in the past. GET /v2/ui/net/:id/views/:view_id/map?layout=auto ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ runs automatic map layout algorithm and returns newly built map GET /v2/ui/net/:id/views/:view_id/map?layout=reset ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reset coordinates of all devices in this map, this makes devices "float" GET /v2/ui/net/:id/views/:view_id/map?layout=fit ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ try to fit the map into browser window by scaling coordinates of all devices linearly GET /v2/ui/net/:id/views/:view_id/preview[?devRule=NSGQL][&linkRule=NSGQL][&hide=true][&connecting=false|true][&adjacent=false|true] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call attempts to rebuild network map for the view `view_id` using provided NsgQL expressions and flags `connecting` and `adjacent`. Parameters `devRule` and `linkRule` are NsgQL expressions (only the matching part, usually provided after the `WHERE` of an NsgQL query is required). Expression provided as a value of query parameter `devRule` matches devices and expression provided with parameter `linkRule` matches interfaces of the devices. Devices and links in the data this call returns have attribute `matching` that has value `true` if corresponding device or link matches the filter. If parameter `hide` is provided and has value `true` then devices and links that do not match rules are hidden. See :ref:`nsgql` GET /v2/ui/net/:id/views/:view_id/linkGraphVars ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns list of variables defined in the configuration file with parameter `deviceDetailsComponents.Interface` GET /v2/ui/net/:id/views/:view_id/linkVar/:lv/nodeVar/:nv[?timestamp=:time] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns monitoring data for the map defined by view id for the link variable `lv` and device variable `nv` PUT /v2/ui/net/:id/views/:view_id/coordinates ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ updates coordinates of one or several devices in the map defined by the view id. Input data is expected in the request body in JSON format:: [ { "id": nodeId1, "x": x1, "y": y1 }, ... ] Server Health Checking ---------------------- .. _api_ping: GET /v2/ping/net/:netid/[se] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call can be used for server health checking (e.g. when deployed in HA configuration and behind a load balancer). This call is very lightweight and does not require user auth. Normally, the servlet returns 200 and a single text string "ok" that indicates whether it is ready to serve. If the server runs without HA configuration, response "ok" indicates that it has completed startup process and is ready to serve. The server will respond with HTTP 200 but an empty body if it is in the process of starting up or is being shut down. If the server is a part of HA group, the group leader responds with "ok", while other servers in the group respond with word "standby". When called with additional path component "/se", i.e. "/v2/ping/net/:netid/se", the server returns 503 when it is not ready to serve. This includes standalone server that is in the middle of startup or shut down sequence or a member of an HA group that is not a leader. This is intended for proxies that can put a server out of rotation only when it responds with "Service Unavailable (503)" .. note:: The path must end with a "/" when option "se" is not used, for example ``/v2/ping/net/1/`` .. _api_data_query: Data Query (NsgQL) ------------------ POST /v2/query/net/:id/data/ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Returns information selected by the parameters of the query sent via request body in json format. Data must be sent to this API call in NsgQL format ( :ref:`nsgql` ):: { "targets": [ { "nsgql": "NsgQL SELECT query 1", "format": "output format" }, { "nsgql": "NsgQL SELECT query 2", "format": "output format" } ], "from": "now-30m", "until": "now", "groupByTime": "1m", } Graphs ------ NetSpyGlass UI and Grafana data plugin v2 use :ref:`api_data_query` with `format=time_series` to build graphs. View Filters ------------ POST /v2/ui/net/:id/filters/[?user=:user_name] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Create new view filter using information passed via request body in JSON format:: { "name": "filter name", "nsgql": "NsgQL mtching expression", "formData": "" } The value of the attribute "formData" is an opaque serialized data block used to fill filter form in the UI. The backend does not interpret this information in any way and just returns it back to the UI in response to the call "GET /v2/ui/net/:id/filters" Internally, filters are associated with user accounts. The server establishes this association using information about logged in user when it is available. Different users can have filters with the same name. This call returns HTTP status OK and empty body when it is successful or server error (500) and the following json in case of errors:: { "error": "error text" } .. note:: Information about logged in user is taken from the authentication data of the API call. When the call is made using access token, then the name of the user is not available and should be passed via optional query parameter `user`. If parameter `user` is not supplied when the call is made with access token, then the filter is created in association with a pseudo-user with the name that matches the token. GET /v2/ui/net/:id/filters/[?user=:user_name] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns list of view filters associated with currently logged in user or user name passed via query parameter. Format:: [ { "id" : 66970, "user" : userName, "deleted" : false, "createdAt" : 1489539475000, "updatedAt" : 1489539475000, "name" : "filter name", "formData" : "serialized form data", "nsgql" : "NsgQL expression", "shared" : false, }, ... ] DELETE /v2/ui/net/:id/filters/:filter_id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deletes view filter with given Id. Returns status 200 when operation was successful, or "Bad Request" error with body in case of error:: { "error": "error text" } POST /v2/ui/net/:id/filters/:filter_id/share ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Shares private view filter with given Id with other users. Returns status 200 when operation was successful, or "Bad Request" error with body in case of error:: { "error": "error text" } .. note:: When a filter is created and saved by the user, it still remains "private". This means when a user opens map filters panel and clicks "Filter name" selector, the filter appears there only if the operation is performed by the same user who created it. However, if user shares the filter, then it becomes visible to all users registered in the system. POST /v2/ui/net/:id/filters/:filter_id/unshare ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Removes "sharesd" status from a view filter with given Id. The filter becomes private again. Returns status 200 when operation was successful, or "Bad Request" error with body in case of error:: { "error": "error text" } Settings -------- GET /v2/ui/net/:id/settings this call returns JSON dictionary that contains various server-side parameters defined in the configuration file and elsewhere. Integrations ------------ POST /v2/external/net/:id/kentik/:kentik_api_call where `kentik_api_call` can be "url", "topXdata", "topXchart". the server takes external integration parameters from the configuration section `integrations.kentik`, makes an API call and returns the data back to the caller. Essentially, the server acts as a proxy, making a call to an external service. Alerts and Alert silences JSON API ---------------------------------- .. note:: All dedicated JSON API calls that deal with alerts and silences have been deprecated and removed, except for the call used to create or update silences (see below). Use NsgQL tables `alerts` and `silences` instead either via `nsgql` command line tool or with :ref:`api_data_query`. POST /v2/alerts/net/:netid/silences ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Add new silence to the system. Takes data from the body of the POST call and creates new alert silence. The data should follow this format: .. code-block:: json { "startsAt": 1584725536534, "expirationTimeMs": 3600000, "match" : { "key": "alertkey", "varNme": "varName", "deviceId": deviceId, "deviceName": "deviceName", "index": index, "tags": "Role.Router, !Explicit.test" } } Silence start time is Unix timestamp in milliseconds (time since 1970-01-01 00:00:00 UTC). If start time is not specified, then it is assumed to be the current time and the silence takes effect immediately. Expiration time interval is in milliseconds. All items in the `match` directory are optional, you are only required to provide attributes you actually want to use to match alerts. .. note:: Even though an empty `match` is permitted, the silence created with empty match rule never matches any alerts and is useless. This call returns the silence it has created as JSON dictionary wrapped in an array: .. code-block:: json [ { "id" : 3728, "createdAt" : 1584725812844, "updatedAt" : 1584725812849, "startsAt" : 1584676800000, "expirationTimeMs" : 7200000, "user" : "vadim", "reason" : "testing silence start time #6", "match" : { "varName" : "", "key" : "", "deviceId" : 1234, "deviceName" : "", "index" : 0, "tags" : [ ] } } ] POST /v2/alerts/net/:netid/silences/:id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Updates existing silence with id `id`. Takes data from the body of the POST call and creates new alert silcnce. The data should follow this format (the same as with the call that creates the silence): .. code-block:: json { "expirationTimeMs": 3600000, "user": "vadim", "reason": "doing maitenance for the next hour", "match" : { "key": "alertKey", "varName": "varName", "deviceId": deviceId, "deviceName": deviceName, "index": index, "tags": "Role.Router, !Explicit.test" } } This call returns the silence it has updated as JSON dictionary wrapped in an array .. note:: Maximum length of the field `reason` is 255 characters .. _device_management: Device Management ----------------- The following API calls are used to add and update devices. Use NsgQL with :ref:`api_data_query` to get list of devices defined in the system. There are two versions of these calls: blocking and non-blocking. Non-blocking calls create background task and immediately return. Response body includes task ID, see :ref:`tasks` for API calls that can be used to get status of running background tasks. Blocking device management API calls returns when the operation has finished and return its status. Blocking calls have "/blocking" in the path. POST /v2/ui/net/:netid/devices/ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Information about the devices is sent in the body of this call and can be either in JSON or CSV (comma separated values) format. If the data is sent in JSON format, the call must include header `Content-Type: application/json`. If the data is sent in CSV format, we expect header `Content-Type: text/csv`. Only these two values of `Content-Type` are supported at this time. If the data is sent as JSON, the body of the call must have the following format: .. code-block:: json [ { 'address': '1.2.3.5', 'name': 'deviceName1', 'channels': 'pollingConf1, pollingConf2, pollingConf3' }, { 'address': '10.1.2.3', 'name': 'deviceName2', 'channels': 'anotherPollingConfg, pollingConf2' }, { 'address': '10.10.10.1', 'channels': 'anotherPollingConfg, pollingConf1' }, ] you can include one or more device definitions in the same API call. Keys `address` and `channels` are required, while `name` is optional. The value for the key `channels` is a comma separated list of channel names that should be used to communicate with this device. In the example above, we provide both the address and name for the first two devices, however we let NetSpyGlass determine the name of the last device automatically. .. important:: Channel names provided with device configuration must match those defined in the channel configuration UI dialogs. If the data is sent in CSV format, the server expect all parameters that describe one device to come on the same line as a comma separated list of words. The same three devices shown above in JSON format would like as follows in CSV format: .. code-block:: none 1.2.3.5,deviceName1,pollingConf1,pollingConf2,pollingConf3 10.1.2.3,deviceName2,anotherPollingConfg,pollingConf2 10.10.10.1,,anotherPollingConfg,pollingConf1 since channels are a list of words and can have different length, total number of fields in each row of in CSV format can be different. In our example the first device has 3 channels, while the other two have only 2. When the name is omitted, the data in CSV format must have an extra comma as shown in the last line in the example above. The API call described here can be used to add one or many devices to the system. The same call can be used to update existing devices. The server uses ip address found in the API call body to find device in the database. If it can not find one, then the new device is added. If it could find device with the same address, then its name and channels are updated and the device is saved back to the database. If the device with this address has been deleted in the past, it is restored again. This API call never deletes devices. This API call starts the operation to add/update devices in the background and returns immediately. Response body contains the following information: .. code-block:: json { "taskID": "111886578825888", "userName": "testing", "startTime": "2019-08-09T00:55:34.074Z", "server": "aggr-1" } the keys are: - taskID : this is a unique identifier for the operation that has started in the background - user : user name who started it - startTime : time stamp (ms) when the operation started Background task reports its progress to the UI using SocketIO. You can also use :ref:`tasks` API to get the status of the task using its task id Here is an example of a device upload from the file that uses API call described here to upload file with device information in JSON format and then runs a simple loop, calling task tracking API described below to monitor the progress. The script uses `jq` to parse server responses to get task Id. .. code-block:: bash #!/bin/sh BASE_URL='https://nsgserver/v2/ui/net/1' AUTH_HEADER='X-NSG-Auth-API-Token: AUTH_TOKEN' task=$(curl -sk -H "$AUTH_HEADER" -X POST -H 'Content-Type: application/json' --data @lab1-devices.conf ${BASE_URL}/devices/ | jq '.["taskID"] | tonumber') echo "Task Id=$task" while : do curl -sk -H "$AUTH_HEADER" ${BASE_URL}/tasks/$task echo sleep 1 done POST /v2/ui/net/:netid/devices/blocking/ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Blocking version of the API call used to create device. Response body is the same as of the `GET` call used to get status of a background task (see below): .. code-block:: json [ { "taskID": "108613131444406", "userName": "testing", "startTime": "2019-08-09T00:01:00.631Z", "totalCount": 7, "progressCount": 7, "server": "aggr-1", "completed": true, "log": [] } ] PUT /v2/ui/net/:netid/devices/:dev_id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call can be used to update device identified by deviceID. Request body and response are the same as with the POST call. Only one device can be updated at a time. PUT /v2/ui/net/:netid/devices/blocking/:dev_id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Blocking version of the call used to update device. DELETE /v2/ui/net/:netid/devices/:id1,:id2,... and /v2/ui/net/:netid/devices/blocking/:id1,:id2,... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ devices that should be deleted are identified by their ids. The comma separated list of device ids is required. The call starts operation to delete devices in the background and returns immediately. The call returns 500 and error message if the device ids list is missing or could not be parsed. The call returns 200 and the following response if the operation has started successfully: .. code-block:: json { "taskID": "112105653350740", "userName": "testing", "startTime": "2019-08-09T00:59:13.147Z", "server": "aggr-1" } the keys are: - taskID : this is a unique identifier for the operation that has started in the background - user : user name who started it - startTime : time stamp (ms) when the operation started Use NsgQL query against table `devices` to find the id: .. code-block:: none SELECT id FROM devices WHERE .. _tasks: Background Tasks ---------------- Several JSON API calls are dedicated to the tracking of background tasks running in the server. One example of a background task is operations of adding, updating or deleting groups of devices (:ref:`device_management`). API call used to add or update devices and the call used to delete devices start the operation in the background and return unique identifier (`taskId`) that can be used with API calls described in this section to get the status and progress of the task. GET /v2/ui/net/:netid/tasks/ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you can use optional query parameters: - active : this parameter filters tasks and makes the call return tasks are still running - completed : this parameter filters tasks and makes the call return only tasks that have finished Examples: GET /v2/ui/net/:netid/tasks/?active GET /v2/ui/net/:netid/tasks/?completed GET /v2/ui/net/:netid/tasks/?active&completed Note that this API call does not return task log. To get the log, use the call that matches task by its `taskId` (below). The response is formatted as JSON Array with the following elements that describe individual tasks. Here is an example: .. code-block:: json [ { "taskID": "108613131444406", "userName": "testing", "startTime": "2019-08-09T00:01:00.631Z", "totalCount": 7, "progressCount": 7, "server": "aggr-1", "completed": true, "log": [] } ] The keys in the dictionary that describes one task are as follows: - type : this is a string that describes task type - taskID : unique task id returned by the API call that started the task - userName : the name of the user who started the task - startTime : the time when the task started, ms - totalCount and progressCount: these keys can be used to track task progress - completed : the task has finished if the value is "true", otherwise the task is still running - log : task log (see example below) GET /v2/ui/net/:id/tasks/:taskid ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ These calls can be used to get information about one task identified by its taskId. The response follows the same format as described above but also adds task log records: .. code-block:: json GET /v2/ui/net/:id/tasks/112105653350740 [{ "taskID": "112105653350740", "userName": "testing", "startTime": "2019-08-09T00:59:13.147Z", "totalCount": 7, "progressCount": 7, "server": "aggr-1", "completed": true, "log": [{ "timestamp": "2019-08-09T00:59:19.446915Z", "priority": 40000, "message": "device add/update error: Error processing device configuration \"{\"name\":\"ex2200\"}\": No configuration setting found for key \"address\"" }] }] Use optional parameter `maxLogLevel` to filter log records by level: GET /v2/ui/net/:id/tasks/:taskid?maxLogLevel=ERROR Supported log levels are: `INFO`, `WARNING`, `ERROR`, `FATAL`. External device and component tags ---------------------------------- GET /v2/tags/net:netid/external[?id=:devID|name=:name|address=:address] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This call will return external tags for all devices or a device identified by the query parameters. Only one device match parameter can be provided at a time, but if the query parameter is missing, the call returns external tags for all devices and components. The response format is as follows: .. code-block:: json [ { "category": "device", "device": { "id" : 12345, "name" : "device_name", "address" : "10.1.2.3" }, "tags": [ "Location.SJC", "AcmeRole.BB" ] }, { "category": "interface", "device": { "id" : 12345, "name" : "device_name", "address" : "10.1.2.3" }, "component": { "index": 1010, "name": "ge-0/0/0" }, "tags": [ "NsgControl.noLink" ] }, ] See the next section for the description of the "category". Information about the device includes its id, name and address. This information is provided to make it easier to match the device against external sources, such as Netbox, where NetSpyGlass device ID is unlikely to be present, however the name and address can be used. The address returned by this call is the one NetSpyGlass uses to communicate with the device. We also provide both the index and name for the interface and component. If the value of "category" is "device", the tag is meant to be attached to the device rather than interface or a component and section "component" may be skipped. Note that the call does not support filtering by the component and always returns external tags attached to all components (if any) of the matching device. POST /v2/tags/net:netid/external ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The body should have the following format:: [ { "category": , "device": { }, "component" : { } "tags": [ "Facet.Word" ] } ] The category can be one of the following: * "device" - the tag will be assigned to the device; key "index" is ignored * "interface" - the tag will be assigned to the interface with ifIndex given by key "index" * "component" - the tag will be assigned to the hardware component with index given by the key "index" Device match clause can be one of: * "id" - the value should be numeric device ID * "name" - the value should be device name * "address" - the value should be device IP address only one device match clause is supported at a time. Component match can be one of: * "index" - interface or h/w component is matched by its index * "name" - interface or h/w component is matched by the name Each dictionary inside of the envelope array assigns one tag, but the call can pass any number of these in any combination. If the call tries to update multiple tags for many devices and some of the device or component match clauses do not match, the response will mention them under "errors" but the server will continue to process the rest and return HTTP response 200. The response of this call has the following format: .. code-block:: json { "errors": [ "Device not found: name=invalid-name", "Device not found: address=10.99.32.1" ], "status": "tags updated for 10 devices" } Example ^^^^^^^ The following example demonstrates different combinations of device and component match clause formats. .. code-block:: json [ { "category": "device", "device": { "id" : 12345, }, "tags": [ "Location.SJC" ] }, { "category": "device", "device": { "id" : 98765, }, "tags": [ "Location.IAD" ] }, { "category": "interface", "device": { "id" : 1001, }, "component" : { "index": 1010 } "tags": [ "NsgControl.noLink" ] }, { "category": "interface", "device": { "id" : 1001, }, "component" : { "name": "ge-0/0/0" } "tags": [ "NsgControl.noLink" ] }, { "category": "component", "device": { "name": "jnpr-router" }, "component": { "name" : "Routing Engine 0" }, "tags": [ "NsgControl.SomeTag1", "NsgControl.Another", ] } ] .. note:: The input data format for this API call supports matching of device and interface/component by their numeric id, name or address. Since internal object models in NetSpyGlass rely on the ids, the server uses provided name or address to find the device or interface and records their id when it writes information about external tag to the database. The match of the name or address happens once when the API call is executed. If the name or address changes later, the tag will remain attached to the same device or interface until you make this API call again. Removing External Tags ^^^^^^^^^^^^^^^^^^^^^^ The POST API call described above always replaces all external tags for the matching device and component. If you need to remove all external tags for a device or a component, execute the same API call with body data that does not have "tags" key. The scope of this call is determined by the category, device and component match clause. If the call has category "device", then all external tags attached to the matching device will be removed but any external tags attached to its components will remain intact. The following would remove all external tags for the device with id=56: .. code-block:: json [ { "category": "device", "device": { "id" : 56 } } ] The following would remove all external tags for the component and device identified by name: .. code-block:: json [ { "category": "device", "device": { "name" : "router1" }, "component": { "name" : "Routing Engine 0" } } ] Reports ------- GET /v2/ui/net/:netid/reports/:category/list[?offset=N1&limit=N2&q=filter&status=discoveryStatus&from=timeFrom&until=timeUntil&s=sortField&desc&fields=][&most_recent=true|false] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns list of available reports in specified category. Category is defined by part of the path `:category` and can be "discovery" or "monitoring" * Parameters `offset` and `limit` are used for pagination. * Parameter `q` can be used to filter reports. The value can be device ID (a number), device address, or a substring that matching device name should start with. If this parameter is missing, the call returns information about all available reports in given category. * Parameter `status` is used to filter reports by discovery status. Possible values: "COMPLETE", "ABORTED" * Parameter `s` can be used to sort report. Supported values are `createdAt` and `reportName` * parameter `desc` (no value) sets sort order to be descending * parameter `fields` specifies set of fields to be returned. Default is `path,name,createdAt,type,contentType,length` * parameter `most_recent` (values can be `true` or `false`). If the value is `true` (the default), then this API call returns only most recent report that matches filter `q`, or if the filter is missing, the call returns information about most recent report for each report name in given category. If the value is false, then this call returns information about all available reports matching `q`. * parameters `from` and `until` can be used to limit reports by creation time GET /v2/ui/net/:netid/reports/:category/count[?offset=N1&limit=N2&q=filter&status=discoveryStatus] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call returns total count of matching reports and takes the same query parameters as the call `/list` described above GET /v2/ui/net/:netid/reports/:category/:report_name_or_id ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this call returns contents of the report identified by `:category` and `:report_name_or_id`. The value of the parameter `report_name_or_id` can be report name or ElasticSearch document id Incremental Discovery --------------------- GET /v2/nsg/discovery/net/:netid/start ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ *deprecated* UI used to call this when user clicks button "Start discovery" POST /v2/nsg/discovery/net/:netid/submit/:dev ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (no body is required) Add device to the front of incremental discovery queue. Devices added to the front of the queue are picked up for discovery as soon as a discovery server becomes available. Device (`:dev`) can be identified by device ID, name or ip address GET /v2/nsg/discovery/net/:netid/queue?limit=NN ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ return top NN items from discovery queue. Response consists of the following sections: Top level keys: * `paused` : if true, discovery is paused (see below) * `currentlyProcessing` : discovery server processes collected data for this device right now * `queue` : an array with entries that describe devices in the input queue. These devices wait for the next discovery server to become available to begin discovery process. This array represents an ordered queue; devices added to the queue most recently have lowest value of the key "duration" and appear at the beginning of the array. Discovery servers take items from the from the front of the queue which corresponds to the end of this array. * `communicating` : an array of dictionaries that describe devices being discovered. These are the devices discovery servers are communicating with at the moment by sending various SNMP GET and WALK queries. Entries move to this section from "queue". Entries in this list do not have any particular meaningful order. * `pendingProcessing` : this array of dictionaries describes devices that finished discovery process and wait for the discovery manager server to pick them up to process the result. This array represents an ordered queue; devices added to the queue most recently have lowest value of the key "duration" and appear at the beginning of the array. Discovery manager takes items from the from the front of the queue which corresponds to the end of this array. Format of entries in `queue` and `communicating` is the same. Each dictionary has the following keys: * `deviceID` : device ID * `name` : device name * `address` : device address * `duration` : how long the device has been in this state (in the input queue or in progress) ( seconds) Entries in `pendingProcessing` have slightly different format: * `id`: device ID * `name`: device name * `address`: device address * `state`: discovery completion state. Can be "COMPLETE" or "ABORTED" * `duration`: how long the device has been sitting in this queue (seconds) Example: .. code-block:: json { "enabled": true, "paused": false, "communicating": [ { "deviceID": 11524, "name": "sdcasX20a", "address": "10.36.35.59", "duration": 0.600164 }, { "deviceID": 12389, "name": "ofcaph2-12m", "address": "10.20.54.178", "duration": 0.131424 }, { "deviceID": 2198, "name": "s01376mgrsw01", "address": "10.156.212.55", "duration": 1.085298 } }, "queue": [ { "deviceID": 24133, "name": "s04358ap01", "address": "10.189.172.11", "duration": 0.166758682 }, { "deviceID": 11266, "name": "s09680sw01", "address": "10.178.148.5", "duration": 0.165866584 }, { "deviceID": 2484, "name": "s01644sw01", "address": "10.137.16.5", "duration": 0.164876884 }, { "deviceID": 30269, "name": "s08863ap02", "address": "10.75.148.12", "duration": 0.163884884 } ], "pendingProcessing": [ { "sessionId": 1643334280105, "id": 5128, "name": "s04272sw01", "address": "10.189.116.5", "timestamp": 1643334281.821854, "state": "COMPLETE", "server": "labdcbig3-nsg-ndd-1", "duration": 3.636162179, "empty": false }, { "sessionId": 1643334280106, "id": 11524, "name": "sdcasX20a", "address": "10.36.35.59", "timestamp": 1643334281.76247, "state": "COMPLETE", "server": "labdcbig3-nsg-ndd-2", "duration": 3.69559098, "empty": false } ], "currentlyProcessing": "s05702pbx01", "currentGeneration": { "generation": 56, "createdAt": "2022-01-26T19:00:04.344Z", "createdAtMs": 1643223604344, "devicesToDiscover": 25350 } } POST /v2/nsg/discovery/net/:netid/new_generation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (no body is required) start new generation POST /v2/nsg/discovery/net/:netid/pause ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (no body is required) Pause discovery. Discovery servers are going to continue taking device IDs form the input queue until the queue is empty but new devices are not going to be scheduled. POST /v2/nsg/discovery/net/:netid/resume ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (no body is required) Resume scheduling of devices for discovery