Skip to content
Snippets Groups Projects
Commit ffbf7393 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

WebUI:

- Activated "Grafana" link in top menu
- Implemented onboarding of devices + configuration from JSON descriptor files
- added device status in device details page
- created new grafana dashboard for new PostgreSQL-based monitoring database
- updated deploy.sh script with correct configuration of Grafana monitoring datasource and new dashboard
parent f691ef72
No related branches found
No related tags found
2 merge requests!54Release 2.0.0,!4Compute component:
...@@ -247,19 +247,22 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring" ...@@ -247,19 +247,22 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
"url" : "monitoringservice:8812", "url" : "monitoringservice:8812",
"database" : "monitoring", "database" : "monitoring",
"user" : "admin", "user" : "admin",
"password" : "quest", "basicAuth": false,
"basicAuth" : false,
"isDefault": true, "isDefault": true,
"jsonData" : { "jsonData" : {
"sslmode" : "disable", "sslmode" : "disable",
"postgresVersion" : 1100, "postgresVersion" : 1100,
"tlsAuth" : false, "maxOpenConns" : 0,
"tlsAuthWithCACert": false, "maxIdleConns" : 2,
"connMaxLifetime" : 14400,
"tlsAuth" : false,
"tlsAuthWithCACert" : false,
"timescaledb" : false,
"tlsConfigurationMethod": "file-path", "tlsConfigurationMethod": "file-path",
"tlsSkipVerify": true "tlsSkipVerify" : true
}, },
"secureJsonFields" : { "secureJsonData": {
"password" : true "password": "quest"
} }
}' ${GRAFANA_URL_UPDATED}/api/datasources }' ${GRAFANA_URL_UPDATED}/api/datasources
echo echo
...@@ -267,7 +270,7 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring" ...@@ -267,7 +270,7 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
# Create Monitoring Dashboard # Create Monitoring Dashboard
# Ref: https://grafana.com/docs/grafana/latest/http_api/dashboard/ # Ref: https://grafana.com/docs/grafana/latest/http_api/dashboard/
curl -X POST -H "Content-Type: application/json" \ curl -X POST -H "Content-Type: application/json" \
-d '@src/webui/grafana_dashboard.json' \ -d '@src/webui/grafana_dashboard_psql.json' \
${GRAFANA_URL_UPDATED}/api/dashboards/db ${GRAFANA_URL_UPDATED}/api/dashboards/db
echo echo
......
{"overwrite": true, "folderId": 0, "dashboard":
{
"id": null,
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "datasource",
"uid": "grafana"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"iteration": 1664814762635,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": {
"type": "postgres",
"uid": "monitoringdb"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "smooth",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "always",
"spanNulls": true,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": [
{
"matcher": {
"id": "byRegexp",
"options": ".*PACKETS_.*"
},
"properties": [
{
"id": "custom.axisPlacement",
"value": "left"
},
{
"id": "unit",
"value": "pps"
},
{
"id": "custom.axisLabel",
"value": "Packets / sec"
},
{
"id": "custom.axisSoftMin",
"value": 0
}
]
},
{
"matcher": {
"id": "byRegexp",
"options": ".*BYTES_.*"
},
"properties": [
{
"id": "custom.axisPlacement",
"value": "right"
},
{
"id": "unit",
"value": "Bps"
},
{
"id": "custom.axisLabel",
"value": "Bytes / sec"
},
{
"id": "custom.axisSoftMin",
"value": 0
}
]
}
]
},
"gridPos": {
"h": 19,
"w": 24,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"legend": {
"calcs": [
"first",
"min",
"mean",
"max",
"lastNotNull"
],
"displayMode": "table",
"placement": "right"
},
"tooltip": {
"mode": "multi",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "postgres",
"uid": "monitoringdb"
},
"format": "time_series",
"group": [],
"hide": false,
"metricColumn": "kpi_value",
"rawQuery": true,
"rawSql": "SELECT\r\n $__time(timestamp), kpi_value AS metric, device_id, endpoint_id, kpi_sample_type\r\nFROM\r\n monitoring\r\nWHERE\r\n $__timeFilter(timestamp) AND device_id IN ($device_id) AND endpoint_id IN ($endpoint_id) AND kpi_sample_type IN ($kpi_sample_type)\r\nGROUP BY\r\n device_id, endpoint_id, kpi_sample_type\r\nORDER BY\r\n timestamp\r\n",
"refId": "A",
"select": [
[
{
"params": [
"kpi_value"
],
"type": "column"
}
]
],
"table": "monitoring",
"timeColumn": "timestamp",
"where": [
{
"name": "",
"params": [
"device_id",
"IN",
"$device_id"
],
"type": "expression"
}
]
}
],
"title": "L3 Monitoring Packets/Bytes Received/Sent",
"transformations": [
{
"id": "renameByRegex",
"options": {
"regex": "metric {device_id=\\\"([^\\\"]+)\\\", endpoint_id=\\\"([^\\\"]+)\\\", kpi_sample_type=\\\"([^\\\"]+)\\\"}",
"renamePattern": "$3 ($1 $2)"
}
}
],
"type": "timeseries"
}
],
"refresh": "5s",
"schemaVersion": 36,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
},
"datasource": {
"type": "postgres",
"uid": "monitoringdb"
},
"definition": "SELECT DISTINCT device_id FROM monitoring;",
"hide": 0,
"includeAll": true,
"label": "Device",
"multi": true,
"name": "device_id",
"options": [],
"query": "SELECT DISTINCT device_id FROM monitoring;",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"current": {
"selected": false,
"text": "All",
"value": "$__all"
},
"datasource": {
"type": "postgres",
"uid": "monitoringdb"
},
"definition": "SELECT DISTINCT endpoint_id FROM monitoring WHERE device_id IN (${device_id})",
"hide": 0,
"includeAll": true,
"label": "EndPoint",
"multi": true,
"name": "endpoint_id",
"options": [],
"query": "SELECT DISTINCT endpoint_id FROM monitoring WHERE device_id IN (${device_id})",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
},
{
"current": {
"selected": true,
"text": [
"PACKETS_RECEIVED",
"PACKETS_TRANSMITTED"
],
"value": [
"PACKETS_RECEIVED",
"PACKETS_TRANSMITTED"
]
},
"datasource": {
"type": "postgres",
"uid": "monitoringdb"
},
"definition": "SELECT DISTINCT kpi_sample_type FROM monitoring;",
"hide": 0,
"includeAll": true,
"label": "Kpi Sample Type",
"multi": true,
"name": "kpi_sample_type",
"options": [],
"query": "SELECT DISTINCT kpi_sample_type FROM monitoring;",
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 0,
"type": "query"
}
]
},
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "L3 Monitoring",
"uid": "tf-l3-monit",
"version": 1,
"weekStart": ""
}
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
# limitations under the License. # limitations under the License.
import copy, json, logging import copy, json, logging
from typing import Optional
from flask import jsonify, redirect, render_template, Blueprint, flash, session, url_for, request from flask import jsonify, redirect, render_template, Blueprint, flash, session, url_for, request
from common.proto.context_pb2 import Connection, Context, Device, Empty, Link, Service, Slice, Topology, ContextIdList from common.proto.context_pb2 import Connection, Context, Device, Empty, Link, Service, Slice, Topology, ContextIdList
from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.grpc.Tools import grpc_message_to_json_string
...@@ -43,9 +44,10 @@ ENTITY_TO_TEXT = { ...@@ -43,9 +44,10 @@ ENTITY_TO_TEXT = {
} }
ACTION_TO_TEXT = { ACTION_TO_TEXT = {
# action => infinitive, past # action => infinitive, past
'add' : ('Add', 'Added'), 'add' : ('Add', 'Added'),
'update' : ('Update', 'Updated'), 'update' : ('Update', 'Updated'),
'config' : ('Configure', 'Configured'),
} }
def process_descriptor(entity_name, action_name, grpc_method, grpc_class, entities): def process_descriptor(entity_name, action_name, grpc_method, grpc_class, entities):
...@@ -94,14 +96,14 @@ def process_descriptors(descriptors): ...@@ -94,14 +96,14 @@ def process_descriptors(descriptors):
topology['device_ids'] = [] topology['device_ids'] = []
topology['link_ids'] = [] topology['link_ids'] = []
process_descriptor('context', 'add', context_client.SetContext, Context, contexts_add ) process_descriptor('context', 'add', context_client.SetContext, Context, contexts_add )
process_descriptor('topology', 'add', context_client.SetTopology, Topology, topologies_add) process_descriptor('topology', 'add', context_client.SetTopology, Topology, topologies_add)
process_descriptor('device', 'add', context_client.SetDevice, Device, devices ) process_descriptor('device', 'add', context_client.SetDevice, Device, devices )
process_descriptor('link', 'add', context_client.SetLink, Link, links ) process_descriptor('link', 'add', context_client.SetLink, Link, links )
process_descriptor('service', 'add', context_client.SetService, Service, services ) process_descriptor('service', 'add', context_client.SetService, Service, services )
process_descriptor('context', 'update', context_client.SetContext, Context, contexts ) process_descriptor('context', 'update', context_client.SetContext, Context, contexts )
process_descriptor('topology', 'update', context_client.SetTopology, Topology, topologies ) process_descriptor('topology', 'update', context_client.SetTopology, Topology, topologies )
process_descriptor('slice', 'add', context_client.SetSlice, Slice, slices ) process_descriptor('slice', 'add', context_client.SetSlice, Slice, slices )
process_descriptor('connection', 'add', context_client.SetConnection, Connection, connections ) process_descriptor('connection', 'add', context_client.SetConnection, Connection, connections )
context_client.close() context_client.close()
return return
...@@ -111,6 +113,28 @@ def process_descriptors(descriptors): ...@@ -111,6 +113,28 @@ def process_descriptors(descriptors):
# in normal mode, connections should not be set # in normal mode, connections should not be set
assert len(connections) == 0 assert len(connections) == 0
devices_add = []
devices_config = []
for device in devices:
connect_rules = []
config_rules = []
for config_rule in device.get('device_config', {}).get('config_rules', []):
custom_resource_key : Optional[str] = config_rule.get('custom', {}).get('resource_key')
if custom_resource_key is not None and custom_resource_key.startswith('_connect/'):
connect_rules.append(config_rule)
else:
config_rules.append(config_rule)
if len(connect_rules) > 0:
device_add = copy.deepcopy(device)
device_add['device_endpoints'] = []
device_add['device_config'] = {'config_rules': connect_rules}
devices_add.append(device_add)
if len(config_rules) > 0:
device['device_config'] = {'config_rules': config_rules}
devices_config.append(device)
services_add = [] services_add = []
for service in services: for service in services:
service_copy = copy.deepcopy(service) service_copy = copy.deepcopy(service)
...@@ -132,14 +156,15 @@ def process_descriptors(descriptors): ...@@ -132,14 +156,15 @@ def process_descriptors(descriptors):
service_client.connect() service_client.connect()
slice_client.connect() slice_client.connect()
process_descriptor('context', 'add', context_client.SetContext, Context, contexts ) process_descriptor('context', 'add', context_client.SetContext, Context, contexts )
process_descriptor('topology', 'add', context_client.SetTopology, Topology, topologies ) process_descriptor('topology', 'add', context_client.SetTopology, Topology, topologies )
process_descriptor('device', 'add', device_client .AddDevice, Device, devices ) process_descriptor('device', 'add', device_client .AddDevice, Device, devices_add )
process_descriptor('link', 'add', context_client.SetLink, Link, links ) process_descriptor('device', 'config', device_client .ConfigureDevice, Device, devices_config)
process_descriptor('service', 'add', service_client.CreateService, Service, services_add) process_descriptor('link', 'add', context_client.SetLink, Link, links )
process_descriptor('service', 'update', service_client.UpdateService, Service, services ) process_descriptor('service', 'add', service_client.CreateService, Service, services_add )
process_descriptor('slice', 'add', slice_client.CreateSlice, Slice, slices_add ) process_descriptor('service', 'update', service_client.UpdateService, Service, services )
process_descriptor('slice', 'update', slice_client.UpdateSlice, Slice, slices ) process_descriptor('slice', 'add', slice_client .CreateSlice, Slice, slices_add )
process_descriptor('slice', 'update', slice_client .UpdateSlice, Slice, slices )
slice_client.close() slice_client.close()
service_client.close() service_client.close()
......
...@@ -83,9 +83,9 @@ ...@@ -83,9 +83,9 @@
<a class="nav-link" href="{{ url_for('slice.home') }}">Slice</a> <a class="nav-link" href="{{ url_for('slice.home') }}">Slice</a>
{% endif %} {% endif %}
</li> </li>
<!--<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/grafana" id="grafana_link" target="grafana">Grafana</a> <a class="nav-link" href="/grafana" id="grafana_link" target="grafana">Grafana</a>
</li>--> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ url_for('main.debug') }}">Debug</a> <a class="nav-link" href="{{ url_for('main.debug') }}">Debug</a>
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
<div class="col-sm-4"> <div class="col-sm-4">
<b>UUID: </b>{{ device.device_id.device_uuid.uuid }}<br><br> <b>UUID: </b>{{ device.device_id.device_uuid.uuid }}<br><br>
<b>Type: </b>{{ device.device_type }}<br><br> <b>Type: </b>{{ device.device_type }}<br><br>
<b>Status: </b> {{ dose.Name(device.device_operational_status).replace('DEVICEOPERATIONALSTATUS_', '') }}<br>
<b>Drivers: </b> <b>Drivers: </b>
<ul> <ul>
{% for driver in device.device_drivers %} {% for driver in device.device_drivers %}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment