From b7d700c4cd28e0d046d7b58547681a0a9b3a4f4f Mon Sep 17 00:00:00 2001 From: checktheroads Date: Fri, 4 Oct 2019 16:54:32 -0700 Subject: [PATCH] inherit preconfigured class --- grafana.json | 963 ------------------ hyperglass/configuration/models/_utils.py | 14 + hyperglass/configuration/models/branding.py | 45 +- hyperglass/configuration/models/commands.py | 55 +- .../configuration/models/credentials.py | 12 +- hyperglass/configuration/models/features.py | 28 +- hyperglass/configuration/models/general.py | 12 +- hyperglass/configuration/models/messages.py | 6 +- hyperglass/configuration/models/networks.py | 14 +- hyperglass/configuration/models/params.py | 10 +- hyperglass/configuration/models/proxies.py | 17 +- hyperglass/configuration/models/routers.py | 66 +- hyperglass/configuration/models/vrfs.py | 36 +- 13 files changed, 137 insertions(+), 1141 deletions(-) delete mode 100644 grafana.json diff --git a/grafana.json b/grafana.json deleted file mode 100644 index c10456f..0000000 --- a/grafana.json +++ /dev/null @@ -1,963 +0,0 @@ -{ - "annotations": { - "list": [{ - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - }] - }, - "editable": true, - "gnetId": null, - "graphTooltip": 0, - "id": 7, - "iteration": 1560633009018, - "links": [], - "panels": [{ - "cacheTimeout": null, - "colorBackground": true, - "colorPostfix": false, - "colorPrefix": false, - "colorValue": false, - "colors": [ - "#40798c", - "#330036", - "#330036" - ], - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 0, - "y": 0 - }, - "id": 4, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [{ - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [{ - "from": "null", - "text": "N/A", - "to": "null" - }], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "", - "targets": [{ - "expr": "sum(count_data_total)", - "format": "time_series", - "instant": true, - "intervalFactor": 1, - "refId": "A" - }], - "thresholds": "", - "timeFrom": null, - "timeShift": null, - "title": "Queries Processed", - "type": "singlestat", - "valueFontSize": "200%", - "valueMaps": [{ - "op": "=", - "text": "N/A", - "value": "null" - }], - "valueName": "total" - }, - { - "aliasColors": { - "dtn01": "#79b791", - "hnl01": "#330036", - "las01": "#40798c", - "phx01": "#ff5e5b" - }, - "breakPoint": "50%", - "cacheTimeout": null, - "combine": { - "label": "Others", - "threshold": 0 - }, - "fontSize": "80%", - "format": "short", - "gridPos": { - "h": 12, - "w": 7, - "x": 4, - "y": 0 - }, - "id": 7, - "interval": null, - "legend": { - "percentage": false, - "show": true, - "values": true - }, - "legendType": "Under graph", - "links": [], - "maxDataPoints": 3, - "nullPointMode": "connected", - "pieType": "donut", - "strokeWidth": 1, - "targets": [{ - "expr": "sum(count_data_total) by (loc_id)", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "{{loc_id}}", - "refId": "D" - }], - "timeFrom": null, - "timeShift": null, - "title": "Queries by Location", - "type": "grafana-piechart-panel", - "valueName": "total" - }, - { - "aliasColors": { - "BGP AS Path": "#330036", - "BGP Community": "#ff5e5b", - "BGP Route": "#79b791", - "Ping": "#40798c", - "Traceroute": "#ffba49" - }, - "breakPoint": "50%", - "cacheTimeout": null, - "combine": { - "label": "Others", - "threshold": 0 - }, - "fontSize": "80%", - "format": "short", - "gridPos": { - "h": 12, - "w": 7, - "x": 11, - "y": 0 - }, - "id": 2, - "interval": null, - "legend": { - "percentage": false, - "show": true, - "values": true - }, - "legendType": "Under graph", - "links": [], - "maxDataPoints": 3, - "nullPointMode": "connected", - "pieType": "donut", - "strokeWidth": 1, - "targets": [{ - "expr": "sum(count_data_total{type=\"bgp_route\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "BGP Route", - "refId": "A" - }, - { - "expr": "sum(count_data_total{type=\"bgp_aspath\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "BGP AS Path", - "refId": "B" - }, - { - "expr": "sum(count_data_total{type=\"bgp_community\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "BGP Community", - "refId": "C" - }, - { - "expr": "sum(count_data_total{type=\"ping\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "Ping", - "refId": "D" - }, - { - "expr": "sum(count_data_total{type=\"traceroute\"})", - "format": "time_series", - "instant": true, - "interval": "", - "intervalFactor": 1, - "legendFormat": "Traceroute", - "refId": "E" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Queries by Type", - "type": "grafana-piechart-panel", - "valueName": "total" - }, - { - "columns": [], - "fontSize": "100%", - "gridPos": { - "h": 12, - "w": 6, - "x": 18, - "y": 0 - }, - "id": 9, - "interval": "", - "links": [], - "pageSize": null, - "scroll": true, - "showHeader": true, - "sort": { - "col": 8, - "desc": true - }, - "styles": [{ - "alias": "Time", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "pattern": "Time", - "type": "hidden" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "decimals": 2, - "pattern": "__name__", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "Target", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "target", - "thresholds": [], - "type": "string", - "unit": "short" - }, - { - "alias": "Count", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 0, - "mappingType": 1, - "pattern": "Value", - "thresholds": [], - "type": "number", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "instance", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "job", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "source", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "type", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "Location", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "loc_id", - "thresholds": [], - "type": "string", - "unit": "short" - } - ], - "targets": [{ - "expr": "topk(10, sum(count_data_total{target=~\"$target\"}) by (target))", - "format": "table", - "instant": true, - "intervalFactor": 1, - "refId": "A" - }], - "timeFrom": null, - "timeShift": null, - "title": "Top 10 Query Targets", - "transform": "table", - "type": "table" - }, - { - "cacheTimeout": null, - "colorBackground": true, - "colorPostfix": false, - "colorPrefix": false, - "colorValue": false, - "colors": [ - "#40798c", - "#ff5e5b", - "#330036" - ], - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 0, - "y": 3 - }, - "id": 10, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [{ - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [{ - "from": "null", - "text": "N/A", - "to": "null" - }], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "", - "targets": [{ - "expr": "sum(count_notfound_total)", - "format": "time_series", - "instant": true, - "intervalFactor": 1, - "refId": "A" - }], - "thresholds": "", - "timeFrom": null, - "timeShift": null, - "title": "404 Errors", - "type": "singlestat", - "valueFontSize": "200%", - "valueMaps": [{ - "op": "=", - "text": "N/A", - "value": "null" - }], - "valueName": "total" - }, - { - "cacheTimeout": null, - "colorBackground": true, - "colorPostfix": false, - "colorPrefix": false, - "colorValue": false, - "colors": [ - "#40798c", - "#40798c", - "#330036" - ], - "description": "", - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 0, - "y": 6 - }, - "id": 11, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [{ - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [{ - "from": "null", - "text": "N/A", - "to": "null" - }], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "", - "targets": [{ - "expr": "sum(count_ratelimit_total{message=\"429 Too Many Requests: Query\"})", - "format": "time_series", - "instant": true, - "intervalFactor": 1, - "refId": "A" - }], - "thresholds": "", - "timeFrom": null, - "timeShift": null, - "title": "Rate Limit Exceeded: Query", - "type": "singlestat", - "valueFontSize": "200%", - "valueMaps": [{ - "op": "=", - "text": "N/A", - "value": "null" - }], - "valueName": "total" - }, - { - "cacheTimeout": null, - "colorBackground": true, - "colorPostfix": false, - "colorPrefix": false, - "colorValue": false, - "colors": [ - "#40798c", - "#79b791", - "#330036" - ], - "description": "", - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true - }, - "gridPos": { - "h": 3, - "w": 4, - "x": 0, - "y": 9 - }, - "id": 12, - "interval": null, - "links": [], - "mappingType": 1, - "mappingTypes": [{ - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], - "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [{ - "from": "null", - "text": "N/A", - "to": "null" - }], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false - }, - "tableColumn": "", - "targets": [{ - "expr": "sum(count_ratelimit_total{message=\"429 Too Many Requests: Site\"})", - "format": "time_series", - "instant": true, - "intervalFactor": 1, - "refId": "A" - }], - "thresholds": "", - "timeFrom": null, - "timeShift": null, - "title": "Rate Limit Exceeded: Site", - "type": "singlestat", - "valueFontSize": "200%", - "valueMaps": [{ - "op": "=", - "text": "N/A", - "value": "null" - }], - "valueName": "total" - }, - { - "columns": [], - "fontSize": "100%", - "gridPos": { - "h": 6, - "w": 24, - "x": 0, - "y": 12 - }, - "id": 6, - "links": [], - "pageSize": null, - "scroll": true, - "showHeader": true, - "sort": { - "col": 0, - "desc": true - }, - "styles": [{ - "alias": "Time", - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "pattern": "Time", - "type": "date" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "__name__", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "job", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "Value", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "instance", - "thresholds": [], - "type": "hidden", - "unit": "short" - }, - { - "alias": "Location", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "loc_id", - "thresholds": [], - "type": "string", - "unit": "short" - }, - { - "alias": "Source", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "source", - "thresholds": [], - "type": "string", - "unit": "short" - }, - { - "alias": "Target", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "target", - "thresholds": [], - "type": "string", - "unit": "short" - }, - { - "alias": "Query Type", - "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], - "dateFormat": "YYYY-MM-DD HH:mm:ss", - "decimals": 2, - "mappingType": 1, - "pattern": "type", - "preserveFormat": false, - "sanitize": false, - "thresholds": [], - "type": "string", - "unit": "short", - "valueMaps": [{ - "text": "BGP Route", - "value": "bgp_route" - }, - { - "text": "BGP Community", - "value": "bgp_community" - }, - { - "text": "BGP AS Path", - "value": "bgp_aspath" - }, - { - "text": "Ping", - "value": "ping" - }, - { - "text": "Traceroute", - "value": "traceroute" - } - ] - } - ], - "targets": [{ - "expr": "count_data_total", - "format": "table", - "instant": true, - "intervalFactor": 1, - "refId": "A" - }], - "timeFrom": null, - "timeShift": null, - "title": "Query Log", - "transform": "table", - "type": "table" - } - ], - "schemaVersion": 18, - "style": "dark", - "tags": [], - "templating": { - "list": [{ - "allValue": null, - "current": { - "selected": false, - "text": "All", - "value": "$__all" - }, - "datasource": "Prometheus", - "definition": "label_values(type)", - "hide": 0, - "includeAll": true, - "label": "Query Type", - "multi": false, - "name": "query_type", - "options": [], - "query": "label_values(type)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": null, - "current": { - "selected": true, - "text": "All", - "value": "$__all" - }, - "datasource": "Prometheus", - "definition": "label_values(loc_id)", - "hide": 0, - "includeAll": true, - "label": "Location", - "multi": false, - "name": "location", - "options": [], - "query": "label_values(loc_id)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": null, - "current": { - "selected": true, - "text": "All", - "value": "$__all" - }, - "datasource": "Prometheus", - "definition": "label_values(source)", - "hide": 0, - "includeAll": true, - "label": "Source IP", - "multi": false, - "name": "source", - "options": [], - "query": "label_values(source)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": null, - "current": { - "selected": true, - "text": "All", - "value": "$__all" - }, - "datasource": "Prometheus", - "definition": "label_values(target)", - "hide": 0, - "includeAll": true, - "label": "Target", - "multi": false, - "name": "target", - "options": [], - "query": "label_values(target)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "hyperglass", - "uid": "1kYrhFnWk", - "version": 42 -} diff --git a/hyperglass/configuration/models/_utils.py b/hyperglass/configuration/models/_utils.py index 6bca69c..58a80a0 100644 --- a/hyperglass/configuration/models/_utils.py +++ b/hyperglass/configuration/models/_utils.py @@ -3,6 +3,7 @@ Utility Functions for Pydantic Models """ import re +from pydantic import BaseSettings def clean_name(_name): @@ -14,3 +15,16 @@ def clean_name(_name): _replaced = re.sub(r"[\-|\.|\@|\~|\:\/|\s]", "_", _name) _scrubbed = "".join(re.findall(r"([a-zA-Z]\w+|\_+)", _replaced)) return _scrubbed.lower() + + +class HyperglassModel(BaseSettings): + """Base model for all hyperglass configuration models""" + + pass + + class Config: + """Default pydantic configuration""" + + validate_all = True + extra = "forbid" + validate_assignment = True diff --git a/hyperglass/configuration/models/branding.py b/hyperglass/configuration/models/branding.py index b15421b..6a2777a 100644 --- a/hyperglass/configuration/models/branding.py +++ b/hyperglass/configuration/models/branding.py @@ -7,17 +7,20 @@ Validates input for overridden parameters. """ # Third Party Imports -from pydantic import BaseSettings +from pydantic import constr from pydantic import validator from pydantic.color import Color +# Project Imports +from hyperglass.configuration.models._utils import HyperglassModel -class Branding(BaseSettings): + +class Branding(HyperglassModel): """Class model for params.branding""" site_name: str = "hyperglass" - class Colors(BaseSettings): + class Colors(HyperglassModel): """Class model for params.colors""" primary: Color = "#40798c" @@ -28,43 +31,49 @@ class Branding(BaseSettings): dark: Color = "#383541" background: Color = "#fbfffe" - class Credit(BaseSettings): + def dict(self, *args, **kwargs): + _dict = {} + for k, v in self.__dict__.items(): + _dict.update({k: v.as_hex()}) + return _dict + + class Credit(HyperglassModel): """Class model for params.branding.credit""" enable: bool = True - class Font(BaseSettings): + class Font(HyperglassModel): """Class model for params.branding.font""" primary: str = "Nunito" mono: str = "Fira Code" - class HelpMenu(BaseSettings): + class HelpMenu(HyperglassModel): """Class model for params.branding.help_menu""" enable: bool = True - class Logo(BaseSettings): + class Logo(HyperglassModel): """Class model for params.branding.logo""" path: str = "ui/images/hyperglass-dark.png" width: int = 384 favicons: str = "ui/images/favicons/" - class PeeringDb(BaseSettings): + class PeeringDb(HyperglassModel): """Class model for params.branding.peering_db""" enable: bool = True - class Terms(BaseSettings): + class Terms(HyperglassModel): """Class model for params.branding.terms""" enable: bool = True - class Text(BaseSettings): + class Text(HyperglassModel): """Class model for params.branding.text""" - title_mode: str = "logo_only" + title_mode: constr(regex=("logo_only|text_only|logo_title|all")) = "logo_only" title: str = "hyperglass" subtitle: str = "AS{primary_asn}" query_location: str = "Location" @@ -80,21 +89,21 @@ class Branding(BaseSettings): traceroute: str = "Traceroute" vrf: str = "VRF" - class Error404(BaseSettings): + class Error404(HyperglassModel): """Class model for 404 Error Page""" title: str = "Error" subtitle: str = "{uri} isn't a thing" button: str = "Home" - class Error500(BaseSettings): + class Error500(HyperglassModel): """Class model for 500 Error Page""" title: str = "Error" subtitle: str = "Something Went Wrong" button: str = "Home" - class Error504(BaseSettings): + class Error504(HyperglassModel): """Class model for 504 Error Element""" message: str = "Unable to reach {target}" @@ -103,14 +112,6 @@ class Branding(BaseSettings): error500: Error500 = Error500() error504: Error504 = Error504() - @validator("title_mode") - def check_title_mode(cls, v): - """Verifies title_mode matches supported values""" - supported_modes = ["logo_only", "text_only", "logo_title", "all"] - if v not in supported_modes: - raise ValueError("title_mode must be one of {}".format(supported_modes)) - return v - colors: Colors = Colors() credit: Credit = Credit() font: Font = Font() diff --git a/hyperglass/configuration/models/commands.py b/hyperglass/configuration/models/commands.py index 36e700c..86143b0 100644 --- a/hyperglass/configuration/models/commands.py +++ b/hyperglass/configuration/models/commands.py @@ -6,14 +6,14 @@ Imports config variables and overrides default class attributes. Validates input for overridden parameters. """ -# Third Party Imports -from pydantic import BaseSettings +# Project Imports +from hyperglass.configuration.models._utils import HyperglassModel -class Command(BaseSettings): +class Command(HyperglassModel): """Class model for non-default commands""" - class IPv4(BaseSettings): + class IPv4(HyperglassModel): """Class model for non-default dual afi commands""" bgp_route: str = "" @@ -22,7 +22,7 @@ class Command(BaseSettings): ping: str = "" traceroute: str = "" - class IPv6(BaseSettings): + class IPv6(HyperglassModel): """Class model for non-default ipv4 commands""" bgp_route: str = "" @@ -31,7 +31,7 @@ class Command(BaseSettings): ping: str = "" traceroute: str = "" - class VPNIPv4(BaseSettings): + class VPNIPv4(HyperglassModel): """Class model for non-default ipv6 commands""" bgp_route: str = "" @@ -40,7 +40,7 @@ class Command(BaseSettings): ping: str = "" traceroute: str = "" - class VPNIPv6(BaseSettings): + class VPNIPv6(HyperglassModel): """Class model for non-default ipv6 commands""" bgp_route: str = "" @@ -55,7 +55,7 @@ class Command(BaseSettings): vpn_ipv6: VPNIPv6 = VPNIPv6() -class Commands(BaseSettings): +class Commands(HyperglassModel): """Base class for commands class""" @classmethod @@ -69,10 +69,10 @@ class Commands(BaseSettings): setattr(Commands, nos, Command(**cmds)) return obj - class CiscoIOS(BaseSettings): + class CiscoIOS(HyperglassModel): """Class model for default cisco_ios commands""" - class IPv4Vrf(BaseSettings): + class IPv4Vrf(HyperglassModel): """Default commands for dual afi commands""" bgp_community: str = "show bgp vpnv4 unicast vrf {vrf} community {target}" @@ -83,7 +83,7 @@ class Commands(BaseSettings): "traceroute vrf {vrf} {target} timeout 1 probe 2 source {source}" ) - class IPv6Vrf(BaseSettings): + class IPv6Vrf(HyperglassModel): """Default commands for dual afi commands""" bgp_community: str = "show bgp vpnv6 unicast vrf {vrf} community {target}" @@ -94,7 +94,7 @@ class Commands(BaseSettings): "traceroute vrf {vrf} {target} timeout 1 probe 2 source {source}" ) - class IPv4Default(BaseSettings): + class IPv4Default(HyperglassModel): """Default commands for ipv4 commands""" bgp_community: str = "show bgp ipv4 unicast community {target}" @@ -103,7 +103,7 @@ class Commands(BaseSettings): ping: str = "ping {target} repeat 5 source {source}" traceroute: str = "traceroute {target} timeout 1 probe 2 source {source}" - class IPv6Default(BaseSettings): + class IPv6Default(HyperglassModel): """Default commands for ipv6 commands""" bgp_community: str = "show bgp ipv6 unicast community {target}" @@ -119,10 +119,10 @@ class Commands(BaseSettings): ipv4_vrf: IPv4Vrf = IPv4Vrf() ipv6_vrf: IPv6Vrf = IPv6Vrf() - class CiscoXR(BaseSettings): + class CiscoXR(HyperglassModel): """Class model for default cisco_xr commands""" - class Dual(BaseSettings): + class Dual(HyperglassModel): """Default commands for dual afi commands""" bgp_community: str = ( @@ -134,7 +134,7 @@ class Commands(BaseSettings): '"\\(BGP |Table |Non-stop\\)"' ) - class IPv4(BaseSettings): + class IPv4(HyperglassModel): """Default commands for ipv4 commands""" bgp_route: str = ( @@ -146,7 +146,7 @@ class Commands(BaseSettings): "traceroute ipv4 {target} timeout 1 probe 2 source {source}" ) - class IPv6(BaseSettings): + class IPv6(HyperglassModel): """Default commands for ipv6 commands""" bgp_route: str = ( @@ -162,23 +162,23 @@ class Commands(BaseSettings): ipv4: IPv4 = IPv4() ipv6: IPv6 = IPv6() - class Juniper(BaseSettings): + class Juniper(HyperglassModel): """Class model for default juniper commands""" - class Dual(BaseSettings): + class Dual(HyperglassModel): """Default commands for dual afi commands""" bgp_community = "show route protocol bgp community {target}" bgp_aspath = "show route protocol bgp aspath-regex {target}" - class IPv4(BaseSettings): + class IPv4(HyperglassModel): """Default commands for ipv4 commands""" bgp_route = "show route protocol bgp table inet.0 {target} detail" ping = "ping inet {target} count 5 source {src_addr_ipv4}" traceroute = "traceroute inet {target} wait 1 source {source}" - class IPv6(BaseSettings): + class IPv6(HyperglassModel): """Default commands for ipv6 commands""" bgp_route = "show route protocol bgp table inet6.0 {target} detail" @@ -189,10 +189,10 @@ class Commands(BaseSettings): ipv4: IPv4 = IPv4() ipv6: IPv6 = IPv6() - class Huawei(BaseSettings): + class Huawei(HyperglassModel): """Class model for default huawei commands""" - class IPv4Vrf(BaseSettings): + class IPv4Vrf(HyperglassModel): """Default commands for dual afi commands""" bgp_community: str = ( @@ -211,7 +211,7 @@ class Commands(BaseSettings): "tracert -q 2 -f 1 -vpn-instance {vrf} -a {source} {target}" ) - class IPv6Vrf(BaseSettings): + class IPv6Vrf(HyperglassModel): """Default commands for dual afi commands""" bgp_community: str = ( @@ -230,7 +230,7 @@ class Commands(BaseSettings): "tracert -q 2 -f 1 vpn-instance {vrf} -a {source} {target}" ) - class IPv4Default(BaseSettings): + class IPv4Default(HyperglassModel): """Default commands for ipv4 commands""" bgp_community: str = "display bgp routing-table regular-expression {target}" @@ -239,7 +239,7 @@ class Commands(BaseSettings): ping: str = "ping -c 5 -a {source} {target}" traceroute: str = "tracert -q 2 -f 1 -a {source} {target}" - class IPv6Default(BaseSettings): + class IPv6Default(HyperglassModel): """Default commands for ipv6 commands""" bgp_community: str = "display bgp ipv6 routing-table community {target}" @@ -261,7 +261,6 @@ class Commands(BaseSettings): huawei: Command = Huawei() class Config: - """Pydantic Config""" + """Pydantic Config Overrides""" validate_all = False - validate_assignment = True diff --git a/hyperglass/configuration/models/credentials.py b/hyperglass/configuration/models/credentials.py index ba2ed15..068d28b 100644 --- a/hyperglass/configuration/models/credentials.py +++ b/hyperglass/configuration/models/credentials.py @@ -7,21 +7,21 @@ Validates input for overridden parameters. """ # Third Party Imports -from pydantic import BaseSettings from pydantic import SecretStr # Project Imports from hyperglass.configuration.models._utils import clean_name +from hyperglass.configuration.models._utils import HyperglassModel -class Credential(BaseSettings): +class Credential(HyperglassModel): """Model for per-credential config in devices.yaml""" username: str password: SecretStr -class Credentials(BaseSettings): +class Credentials(HyperglassModel): """Base model for credentials class""" @classmethod @@ -36,9 +36,3 @@ class Credentials(BaseSettings): cred = clean_name(credname) setattr(Credentials, cred, Credential(**params)) return obj - - class Config: - """Pydantic Config""" - - validate_all = True - validate_assignment = True diff --git a/hyperglass/configuration/models/features.py b/hyperglass/configuration/models/features.py index 39ab40a..d622ecf 100644 --- a/hyperglass/configuration/models/features.py +++ b/hyperglass/configuration/models/features.py @@ -9,24 +9,24 @@ Validates input for overridden parameters. from math import ceil # Third Party Imports -from pydantic import BaseSettings from pydantic import constr +from hyperglass.configuration.models._utils import HyperglassModel -class Features(BaseSettings): +class Features(HyperglassModel): """Class model for params.features""" - class BgpRoute(BaseSettings): + class BgpRoute(HyperglassModel): """Class model for params.features.bgp_route""" enable: bool = True - class BgpCommunity(BaseSettings): + class BgpCommunity(HyperglassModel): """Class model for params.features.bgp_community""" enable: bool = True - class Regex(BaseSettings): + class Regex(HyperglassModel): """Class model for params.features.bgp_community.regex""" decimal: str = r"^[0-9]{1,10}$" @@ -35,12 +35,12 @@ class Features(BaseSettings): regex: Regex = Regex() - class BgpAsPath(BaseSettings): + class BgpAsPath(HyperglassModel): """Class model for params.features.bgp_aspath""" enable: bool = True - class Regex(BaseSettings): + class Regex(HyperglassModel): """Class model for params.bgp_aspath.regex""" mode: constr(regex="asplain|asdot") = "asplain" @@ -51,17 +51,17 @@ class Features(BaseSettings): regex: Regex = Regex() - class Ping(BaseSettings): + class Ping(HyperglassModel): """Class model for params.features.ping""" enable: bool = True - class Traceroute(BaseSettings): + class Traceroute(HyperglassModel): """Class model for params.features.traceroute""" enable: bool = True - class Cache(BaseSettings): + class Cache(HyperglassModel): """Class model for params.features.cache""" redis_id: int = 0 @@ -71,7 +71,7 @@ class Features(BaseSettings): timeout=ceil(timeout / 60) ) - class MaxPrefix(BaseSettings): + class MaxPrefix(HyperglassModel): """Class model for params.features.max_prefix""" enable: bool = False @@ -81,12 +81,12 @@ class Features(BaseSettings): "Prefix length must be smaller than /{m}. {i} is too specific." ) - class RateLimit(BaseSettings): + class RateLimit(HyperglassModel): """Class model for params.features.rate_limit""" redis_id: int = 1 - class Query(BaseSettings): + class Query(HyperglassModel): """Class model for params.features.rate_limit.query""" rate: int = 5 @@ -98,7 +98,7 @@ class Features(BaseSettings): ).format(rate=rate, period=period) button: str = "Try Again" - class Site(BaseSettings): + class Site(HyperglassModel): """Class model for params.features.rate_limit.site""" rate: int = 60 diff --git a/hyperglass/configuration/models/general.py b/hyperglass/configuration/models/general.py index a688b5c..7d0a0d3 100644 --- a/hyperglass/configuration/models/general.py +++ b/hyperglass/configuration/models/general.py @@ -7,21 +7,19 @@ Validates input for overridden parameters. """ # Standard Library Imports from typing import List -from typing import Union -# Third Party Imports -from pydantic import BaseSettings -from pydantic import IPvAnyNetwork +# Project Imports +from hyperglass.configuration.models._utils import HyperglassModel -class General(BaseSettings): +class General(HyperglassModel): """Class model for params.general""" debug: bool = False primary_asn: str = "65001" org_name: str = "The Company" - google_analytics: Union[str, None] = None - redis_host: Union[str, IPvAnyNetwork] = "localhost" + google_analytics: str = "" + redis_host: str = "localhost" redis_port: int = 6379 requires_ipv6_cidr: List[str] = ["cisco_ios", "cisco_nxos"] request_timeout: int = 30 diff --git a/hyperglass/configuration/models/messages.py b/hyperglass/configuration/models/messages.py index ec6d1dc..db470e4 100644 --- a/hyperglass/configuration/models/messages.py +++ b/hyperglass/configuration/models/messages.py @@ -6,11 +6,11 @@ Imports config variables and overrides default class attributes. Validates input for overridden parameters. """ -# Third Party Imports -from pydantic import BaseSettings +# Project Imports +from hyperglass.configuration.models._utils import HyperglassModel -class Messages(BaseSettings): +class Messages(HyperglassModel): """Class model for params.messages""" no_query_type: str = "A query type must be specified." diff --git a/hyperglass/configuration/models/networks.py b/hyperglass/configuration/models/networks.py index 8aaebec..8602e4a 100644 --- a/hyperglass/configuration/models/networks.py +++ b/hyperglass/configuration/models/networks.py @@ -6,20 +6,18 @@ Imports config variables and overrides default class attributes. Validates input for overridden parameters. """ -# Third Party Imports -from pydantic import BaseSettings - # Project Imports from hyperglass.configuration.models._utils import clean_name +from hyperglass.configuration.models._utils import HyperglassModel -class Network(BaseSettings): +class Network(HyperglassModel): """Model for per-network/asn config in devices.yaml""" display_name: str -class Networks(BaseSettings): +class Networks(HyperglassModel): """Base model for networks class""" @classmethod @@ -37,9 +35,3 @@ class Networks(BaseSettings): networks.update({netname: Network(**params).dict()}) Networks.networks = networks return obj - - class Config: - """Pydantic Config""" - - validate_all = True - validate_assignment = True diff --git a/hyperglass/configuration/models/params.py b/hyperglass/configuration/models/params.py index 20b1cef..e0fccd4 100644 --- a/hyperglass/configuration/models/params.py +++ b/hyperglass/configuration/models/params.py @@ -7,23 +7,17 @@ Validates input for overridden parameters. """ # Third Party Imports -from pydantic import BaseSettings from hyperglass.configuration.models.branding import Branding from hyperglass.configuration.models.features import Features from hyperglass.configuration.models.general import General from hyperglass.configuration.models.messages import Messages +from hyperglass.configuration.models._utils import HyperglassModel -class Params(BaseSettings): +class Params(HyperglassModel): """Base model for params""" general: General = General() features: Features = Features() branding: Branding = Branding() messages: Messages = Messages() - - class Config: - """Pydantic Config""" - - validate_all = True - validate_assignment = True diff --git a/hyperglass/configuration/models/proxies.py b/hyperglass/configuration/models/proxies.py index 3dbb710..e54e45b 100644 --- a/hyperglass/configuration/models/proxies.py +++ b/hyperglass/configuration/models/proxies.py @@ -5,24 +5,21 @@ Imports config variables and overrides default class attributes. Validates input for overridden parameters. """ -# Standard Library Imports -from typing import Union # Third Party Imports -from pydantic import BaseSettings -from pydantic import IPvAnyAddress from pydantic import SecretStr from pydantic import validator # Project Imports from hyperglass.configuration.models._utils import clean_name +from hyperglass.configuration.models._utils import HyperglassModel from hyperglass.exceptions import UnsupportedDevice -class Proxy(BaseSettings): +class Proxy(HyperglassModel): """Model for per-proxy config in devices.yaml""" - address: Union[IPvAnyAddress, str] + address: str port: int = 22 username: str password: SecretStr @@ -39,7 +36,7 @@ class Proxy(BaseSettings): return v -class Proxies(BaseSettings): +class Proxies(HyperglassModel): """Base model for proxies class""" @classmethod @@ -54,9 +51,3 @@ class Proxies(BaseSettings): dev = clean_name(devname) setattr(Proxies, dev, Proxy(**params)) return obj - - class Config: - """Pydantic Config""" - - validate_all = True - validate_assignment = True diff --git a/hyperglass/configuration/models/routers.py b/hyperglass/configuration/models/routers.py index b902237..fc56e8f 100644 --- a/hyperglass/configuration/models/routers.py +++ b/hyperglass/configuration/models/routers.py @@ -8,77 +8,68 @@ Validates input for overridden parameters. # Standard Library Imports from typing import List from typing import Union + from ipaddress import IPv4Address, IPv6Address # Third Party Imports -from pydantic import BaseSettings -from pydantic import IPvAnyAddress from pydantic import validator -from logzero import logger as log # Project Imports from hyperglass.configuration.models._utils import clean_name +from hyperglass.configuration.models._utils import HyperglassModel from hyperglass.constants import Supported from hyperglass.exceptions import UnsupportedDevice from hyperglass.exceptions import ConfigError -class DeviceVrf4(BaseSettings): +class DeviceVrf4(HyperglassModel): """Model for AFI definitions""" afi_name: str = "" vrf_name: str = "" source_address: IPv4Address - class Config: - """Pydantic Config""" - - validate_assignment = True - validate_all = True + @validator("source_address") + def stringify_ip(cls, v): + if isinstance(v, IPv4Address): + v = str(v) + return v -class DeviceVrf6(BaseSettings): +class DeviceVrf6(HyperglassModel): """Model for AFI definitions""" afi_name: str = "" vrf_name: str = "" source_address: IPv6Address - class Config: - """Pydantic Config""" - - validate_assignment = True - validate_all = True + @validator("source_address") + def stringify_ip(cls, v): + if isinstance(v, IPv6Address): + v = str(v) + return v -class VrfAfis(BaseSettings): +class VrfAfis(HyperglassModel): """Model for per-AFI dicts of VRF params""" ipv4: Union[DeviceVrf4, None] = None ipv6: Union[DeviceVrf6, None] = None - class Config: - """Pydantic Config""" - validate_assignment = True - validate_all = True - - -class Vrf(BaseSettings): +class Vrf(HyperglassModel): default: VrfAfis class Config: - """Pydantic Config""" + """Pydantic Config Overrides""" extra = "allow" - validate_assignment = True - validate_all = True -class Router(BaseSettings): +class Router(HyperglassModel): """Model for per-router config in devices.yaml.""" - address: Union[IPvAnyAddress, str] + address: str network: str credential: str proxy: Union[str, None] = None @@ -120,7 +111,6 @@ class Router(BaseSettings): If an AFI map is not defined, try to get one based on the NOS name. If that doesn't exist, use a default. """ - log.debug(f"Start: {v}") _vrfs = [] for vrf_label, vrf_afis in v.items(): if vrf_label is None: @@ -145,19 +135,16 @@ class Router(BaseSettings): if not params.get("vrf_name"): params.update({"vrf_name": vrf_label}) setattr(Vrf, vrf_label, VrfAfis(**vrf_afis)) - log.debug(_vrfs) values["_vrfs"] = _vrfs return v class Config: - """Pydantic Config""" + """Pydantic Config Overrides""" - validate_assignment = True - validate_all = True extra = "allow" -class Routers(BaseSettings): +class Routers(HyperglassModel): """Base model for devices class.""" @classmethod @@ -173,18 +160,17 @@ class Routers(BaseSettings): for (devname, params) in input_params.items(): dev = clean_name(devname) router_params = Router(**params) + setattr(Routers, dev, router_params) + routers.update({dev: router_params.dict()}) hostnames.append(dev) + for vrf in router_params.dict()["vrfs"]: vrfs.add(vrf) + Routers.routers = routers Routers.hostnames = hostnames Routers.vrfs = list(vrfs) + return Routers() - - class Config: - """Pydantic Config""" - - validate_all = True - validate_assignment = True diff --git a/hyperglass/configuration/models/vrfs.py b/hyperglass/configuration/models/vrfs.py index 2b8a7e9..cacd4df 100644 --- a/hyperglass/configuration/models/vrfs.py +++ b/hyperglass/configuration/models/vrfs.py @@ -8,47 +8,43 @@ Validates input for overridden parameters. # Standard Library Imports from typing import List from typing import Dict +from ipaddress import IPv4Network +from ipaddress import IPv6Network # Third Party Imports -from pydantic import BaseSettings +from pydantic import constr from pydantic import IPvAnyNetwork from pydantic import validator # Project Imports from hyperglass.configuration.models._utils import clean_name -from hyperglass.exceptions import ConfigInvalid +from hyperglass.configuration.models._utils import HyperglassModel + +from logzero import logger as log -class Vrf(BaseSettings): +class Vrf(HyperglassModel): """Model for per VRF/afi config in devices.yaml""" display_name: str ipv4: bool = True ipv6: bool = True - access_list: List[Dict[str, IPvAnyNetwork]] = [ + access_list: List[Dict[constr(regex=("allow|deny")), IPvAnyNetwork]] = [ {"allow": "0.0.0.0/0"}, {"allow": "::/0"}, ] - @validator("access_list", whole=True, always=True) + @validator("access_list", pre=True, whole=True, always=True) def validate_action(cls, value): - allowed_actions = ("allow", "deny") for li in value: for action, network in li.items(): - if action not in allowed_actions: - raise ConfigInvalid( - field=action, - error_msg=( - "Access List Entries must be formatted as " - '"- action: network" (list of dictionaries with the action ' - "as the key, and the network as the value), e.g. " - '"- deny: 192.0.2.0/24 or "- allow: 2001:db8::/32".' - ), - ) + if isinstance(network, (IPv4Network, IPv6Network)): + li[action] = str(network) + log.info(value) return value -class Vrfs(BaseSettings): +class Vrfs(HyperglassModel): """Base model for vrfs class""" @classmethod @@ -79,9 +75,3 @@ class Vrfs(BaseSettings): Vrfs.display_names = display_names Vrfs._all = _all return Vrfs() - - class Config: - """Pydantic Config""" - - validate_all = True - validate_assignment = True