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
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -247,19 +247,22 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
        "url"      : "monitoringservice:8812",
        "database" : "monitoring",
        "user"     : "admin",
        "password" : "quest",
        "basicAuth": false,
        "isDefault": true,
        "jsonData" : {
            "sslmode"               : "disable",
            "postgresVersion"       : 1100,
            "maxOpenConns"          : 0,
            "maxIdleConns"          : 2,
            "connMaxLifetime"       : 14400,
            "tlsAuth"               : false,
            "tlsAuthWithCACert"     : false,
            "timescaledb"           : false,
            "tlsConfigurationMethod": "file-path",
            "tlsSkipVerify"         : true
        },
        "secureJsonFields" : {
            "password" : true
        "secureJsonData": {
            "password": "quest"
        }
    }' ${GRAFANA_URL_UPDATED}/api/datasources
    echo
@@ -267,7 +270,7 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]] && [[ "$TFS_COMPONENTS" == *"monitoring"
    # Create Monitoring Dashboard
    # Ref: https://grafana.com/docs/grafana/latest/http_api/dashboard/
    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
    echo

+313 −0
Original line number Diff line number Diff line
{"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": ""
  }
}
+44 −19
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
# limitations under the License.

import copy, json, logging
from typing import Optional
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.tools.grpc.Tools import grpc_message_to_json_string
@@ -46,6 +47,7 @@ ACTION_TO_TEXT = {
    # action =>  infinitive,  past
    'add'     : ('Add',       'Added'),
    'update'  : ('Update',    'Updated'),
    'config'  : ('Configure', 'Configured'),
}

def process_descriptor(entity_name, action_name, grpc_method, grpc_class, entities):
@@ -111,6 +113,28 @@ def process_descriptors(descriptors):
    # in normal mode, connections should not be set
    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 = []
    for service in services:
        service_copy = copy.deepcopy(service)
@@ -134,7 +158,8 @@ def process_descriptors(descriptors):

    process_descriptor('context',  'add',    context_client.SetContext,      Context,  contexts      )
    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('device',   'config', device_client .ConfigureDevice, Device,   devices_config)
    process_descriptor('link',     'add',    context_client.SetLink,         Link,     links         )
    process_descriptor('service',  'add',    service_client.CreateService,   Service,  services_add  )
    process_descriptor('service',  'update', service_client.UpdateService,   Service,  services      )
+2 −2
Original line number Diff line number Diff line
@@ -83,9 +83,9 @@
                  <a class="nav-link" href="{{ url_for('slice.home') }}">Slice</a>
                  {% endif %}
                </li>
                <!--<li class="nav-item">
                <li class="nav-item">
                  <a class="nav-link" href="/grafana" id="grafana_link" target="grafana">Grafana</a>
                </li>-->
                </li>
  
                <li class="nav-item">
                  <a class="nav-link" href="{{ url_for('main.debug') }}">Debug</a>
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
            <div class="col-sm-4">
                <b>UUID: </b>{{ device.device_id.device_uuid.uuid }}<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>
                <ul>
                    {% for driver in device.device_drivers %}