From 26794895ad96a30f3e206b759ee8e79fc6299df6 Mon Sep 17 00:00:00 2001 From: The Anh Nguyen Date: Thu, 29 Feb 2024 00:37:15 +0700 Subject: [PATCH] Migrate dynamic scripted Grafana Dashboards to Scenes (#7927) * add grafana scenes into atc * update build Grafana scenes * update Dockerfile * fix tps panel * update datasource * add Apache license header * fix weasel check * update logo weasel * update Grafana docs * [WIP] update eslint * update eslint rules + fix code style * update import paths, fix build * remove logo assets * [WIP] update * update specs traffic stats * add built files of Grana Scenes into Grafana CiaB * fix code styles * add docstring * fix tab indent * docs: update docs Traffic Stats * fix: fix build traffic stats * fix: spec action * chore: add CHANGELOG --- CHANGELOG.md | 1 + docs/source/admin/traffic_stats.rst | 12 +- .../cdn-in-a-box/optional/grafana/Dockerfile | 8 +- .../optional/grafana/app.yaml.template | 30 + .../optional/grafana/datasources.yml.template | 11 + .../optional/grafana/run-grafana.sh | 2 + .../docker/build/Dockerfile-traffic_stats | 3 + .../docker/build/docker-compose.yml | 1 + traffic_stats/build/build_rpm.sh | 15 +- traffic_stats/build/traffic_stats.spec | 18 +- .../grafana/traffic_ops_cachegroup.js | 254 --- .../grafana/traffic_ops_deliveryservice.js | 301 ---- traffic_stats/grafana/traffic_ops_scripted.js | 524 ------- traffic_stats/grafana/traffic_ops_server.js | 1372 ----------------- .../trafficcontrol-scenes/.editorconfig | 34 + .../trafficcontrol-scenes/.eslintrc.json | 466 ++++++ .../trafficcontrol-scenes/.gitignore | 56 + .../trafficcontrol-scenes/cypress.json | 3 + .../cypress/integration/01-smoke.spec.ts | 24 + .../trafficcontrol-scenes/jest-setup.js | 16 + .../trafficcontrol-scenes/jest.config.js | 22 + .../trafficcontrol-scenes/package.json | 78 + .../src/components/App/App.tsx | 41 + .../src/components/App/index.tsx | 20 + .../src/components/Routes/Routes.tsx | 35 + .../src/components/Routes/index.tsx | 20 + .../trafficcontrol-scenes/src/const.ts | 52 + .../trafficcontrol-scenes/src/module.ts | 23 + .../src/pages/CacheGroup/CacheGroup.tsx | 43 + .../src/pages/CacheGroup/index.tsx | 20 + .../src/pages/CacheGroup/panels/bandwidth.tsx | 46 + .../pages/CacheGroup/panels/connections.tsx | 45 + .../src/pages/CacheGroup/scene.tsx | 82 + .../pages/DeliveryService/DeliveryService.tsx | 42 + .../src/pages/DeliveryService/index.tsx | 20 + .../DeliveryService/panels/bandwidth-cg.tsx | 46 + .../DeliveryService/panels/bandwidth.tsx | 46 + .../src/pages/DeliveryService/panels/tps.tsx | 68 + .../src/pages/DeliveryService/scene.tsx | 87 ++ .../src/pages/Server/Server.tsx | 42 + .../src/pages/Server/index.tsx | 20 + .../src/pages/Server/panels/bandwidth.tsx | 44 + .../src/pages/Server/panels/connections.tsx | 46 + .../src/pages/Server/panels/cpu.tsx | 47 + .../src/pages/Server/panels/index.tsx | 27 + .../src/pages/Server/panels/load-average.tsx | 44 + .../src/pages/Server/panels/memory.tsx | 45 + .../src/pages/Server/panels/netstat.tsx | 48 + .../pages/Server/panels/read-write-time.tsx | 55 + .../src/pages/Server/panels/wrap-count.tsx | 44 + .../src/pages/Server/scene.tsx | 133 ++ .../trafficcontrol-scenes/src/plugin.json | 53 + .../src/utils/utils.plugin.ts | 24 + .../src/utils/utils.routing.ts | 29 + .../trafficcontrol-scenes/tsconfig.json | 40 + .../webpack/constants.ts | 16 + .../trafficcontrol-scenes/webpack/utils.ts | 93 ++ .../webpack/webpack.config.ts | 231 +++ 58 files changed, 2599 insertions(+), 2469 deletions(-) create mode 100644 infrastructure/cdn-in-a-box/optional/grafana/app.yaml.template delete mode 100644 traffic_stats/grafana/traffic_ops_cachegroup.js delete mode 100644 traffic_stats/grafana/traffic_ops_deliveryservice.js delete mode 100644 traffic_stats/grafana/traffic_ops_scripted.js delete mode 100644 traffic_stats/grafana/traffic_ops_server.js create mode 100644 traffic_stats/trafficcontrol-scenes/.editorconfig create mode 100644 traffic_stats/trafficcontrol-scenes/.eslintrc.json create mode 100644 traffic_stats/trafficcontrol-scenes/.gitignore create mode 100644 traffic_stats/trafficcontrol-scenes/cypress.json create mode 100644 traffic_stats/trafficcontrol-scenes/cypress/integration/01-smoke.spec.ts create mode 100644 traffic_stats/trafficcontrol-scenes/jest-setup.js create mode 100644 traffic_stats/trafficcontrol-scenes/jest.config.js create mode 100644 traffic_stats/trafficcontrol-scenes/package.json create mode 100644 traffic_stats/trafficcontrol-scenes/src/components/App/App.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/components/App/index.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/components/Routes/Routes.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/components/Routes/index.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/const.ts create mode 100644 traffic_stats/trafficcontrol-scenes/src/module.ts create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/CacheGroup.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/index.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/bandwidth.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/connections.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/scene.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/DeliveryService.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/index.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth-cg.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/tps.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/scene.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/Server.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/index.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/bandwidth.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/connections.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/cpu.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/index.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/load-average.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/memory.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/netstat.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/read-write-time.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/wrap-count.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/pages/Server/scene.tsx create mode 100644 traffic_stats/trafficcontrol-scenes/src/plugin.json create mode 100644 traffic_stats/trafficcontrol-scenes/src/utils/utils.plugin.ts create mode 100644 traffic_stats/trafficcontrol-scenes/src/utils/utils.routing.ts create mode 100644 traffic_stats/trafficcontrol-scenes/tsconfig.json create mode 100644 traffic_stats/trafficcontrol-scenes/webpack/constants.ts create mode 100644 traffic_stats/trafficcontrol-scenes/webpack/utils.ts create mode 100644 traffic_stats/trafficcontrol-scenes/webpack/webpack.config.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 800b5639a2..06da5e9e70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - [#7812](https://github.com/apache/trafficcontrol/pull/7812) *Traffic Portal*: Expose the `configUpdateFailed` and `revalUpdateFailed` fields on the server table. - [#7870](https://github.com/apache/trafficcontrol/pull/7870) *Traffic Portal*: Adds a hyperlink to the DSR page to the DS itself for ease of navigation. - [#7896](https://github.com/apache/trafficcontrol/pull/7896) *ATC Build system*: Count commits since the last release, not commits +- [#7927](https://github.com/apache/trafficcontrol/pull/7927) *Traffic Stats*: Migrate dynamic scripted Grafana Dashboards to Scenes ### Changed - [#7614](https://github.com/apache/trafficcontrol/pull/7614) *Traffic Ops* The database upgrade process no longer overwrites changes users may have made to the initially seeded data. diff --git a/docs/source/admin/traffic_stats.rst b/docs/source/admin/traffic_stats.rst index 1593f94959..29370c4560 100644 --- a/docs/source/admin/traffic_stats.rst +++ b/docs/source/admin/traffic_stats.rst @@ -91,10 +91,8 @@ To easily create databases, retention policies, and continuous queries, run :pro Configuring Grafana ------------------- -In Traffic Portal the :menuselection:`Other --> Grafana` menu item can be configured to display Grafana graphs using InfluxDB data (when not configured, this menu item will not appear). In order for this to work correctly, you will need two things: - -#. A :term:`Parameter` with the graph URL (more information below) -#. The graphs created in Grafana. See below for how to create some simple graphs in Grafana. These instructions assume that InfluxDB has been configured and that data has been written to it. If this is not true, you will not see any graphs. +Grafana can be configured to display graphs using InfluxDB data. +See below for how to create some simple graphs in Grafana. These instructions assume that InfluxDB has been configured and that data has been written to it. If this is not true, you will not see any graphs. To create a graph in Grafana, you can follow these basic steps: @@ -115,11 +113,11 @@ To create a graph in Grafana, you can follow these basic steps: #. Once you have the graph the way you want it, click the :guilabel:`Save Dashboard` button at the top #. You should now have a new saved graph -In order for Traffic Portal users to see Grafana graphs, Grafana will need to allow anonymous access. Information on how to configure anonymous access can be found on the configuration page of the `Grafana Website `_. +Grafana uses Grafana Scenes to display information about individual :term:`Delivery Services` or :term:`Cache Groups`. In order for the custom graphs to display correctly, the built files of :atc-file:`traffic_stats/trafficcontrol-scenes/` need to be placed in the :file:`/var/lib/grafana/plugins/trafficcontrol-scenes-app` directory on the Grafana server. If your Grafana server is the same as your Traffic Stats server the RPM install process will take care of putting the files in place. If your Grafana server is different from your Traffic Stats server, you will need to manually copy the files to the correct directory. -Traffic Portal uses custom dashboards to display information about individual :term:`Delivery Services` or :term:`Cache Groups`. In order for the custom graphs to display correctly, the Javascript files in :atc-file:`traffic_stats/grafana/` need to be in the :file:`/usr/share/grafana/public/dashboards/` directory on the Grafana server. If your Grafana server is the same as your Traffic Stats server the RPM install process will take care of putting the files in place. If your Grafana server is different from your Traffic Stats server, you will need to manually copy the files to the correct directory. +To view dynamic dashboards from Grafana Scenes, visit: ``https://grafanaHost/a/trafficcontrol-scenes-app`` -.. seealso:: More information on custom scripted graphs can be found in the `scripted dashboards `_ section of the Grafana documentation. +.. seealso:: More information on Grafana Scenes can be found in the `blog post `_ of Grafana. Configuring Traffic Portal for Traffic Stats -------------------------------------------- diff --git a/infrastructure/cdn-in-a-box/optional/grafana/Dockerfile b/infrastructure/cdn-in-a-box/optional/grafana/Dockerfile index d3f09acc0e..09a984d1f4 100644 --- a/infrastructure/cdn-in-a-box/optional/grafana/Dockerfile +++ b/infrastructure/cdn-in-a-box/optional/grafana/Dockerfile @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. -FROM grafana/grafana:10.1.5-ubuntu +FROM grafana/grafana:10.2.3-ubuntu USER root ARG TRAFFIC_TS_RPM=traffic_stats/traffic_stats.rpm @@ -28,13 +28,15 @@ ADD enroller/server_template.json \ traffic_ops/to-access.sh \ optional/grafana/run-grafana.sh \ optional/grafana/datasources.yml.template \ + optional/grafana/app.yaml.template \ $TRAFFIC_TS_RPM \ / RUN cd ~ \ && 7z x /traffic_stats.rpm \ - && 7z e traffic_stats-*.cpio *.js -r \ - && mv *.js /usr/share/grafana/public/dashboards \ + && 7z e traffic_stats-*.cpio module.js plugin.json module.js.map -r \ + && mkdir -p /var/lib/grafana/plugins/trafficcontrol-scenes-app/ \ + && mv plugin.json module.js.map module.js /var/lib/grafana/plugins/trafficcontrol-scenes-app/ \ && rm /traffic_stats.rpm \ && rm ~/traffic_stats-*.cpio diff --git a/infrastructure/cdn-in-a-box/optional/grafana/app.yaml.template b/infrastructure/cdn-in-a-box/optional/grafana/app.yaml.template new file mode 100644 index 0000000000..ef238523b1 --- /dev/null +++ b/infrastructure/cdn-in-a-box/optional/grafana/app.yaml.template @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +# Refer to "http://docs.grafana.org/administration/provisioning/#example-datasource-config-file" +# for the variables usages + +apiVersion: 1 + +apps: + - type: 'trafficcontrol-scenes-app' + org_id: 1 + org_name: 'apache' + disabled: false + jsonData: + apiUrl: https://trafficcontrol.apache.org/ + isApiKeySet: true diff --git a/infrastructure/cdn-in-a-box/optional/grafana/datasources.yml.template b/infrastructure/cdn-in-a-box/optional/grafana/datasources.yml.template index 21536c34f3..d75448fe8a 100644 --- a/infrastructure/cdn-in-a-box/optional/grafana/datasources.yml.template +++ b/infrastructure/cdn-in-a-box/optional/grafana/datasources.yml.template @@ -51,3 +51,14 @@ datasources: database: deliveryservice_stats basicAuth: false isDefault: false + +- name: telegraf + type: influxdb + access: proxy + orgId: 1 + url: http://$INFLUXDB_HOST:$INFLUXDB_PORT + password: $INFLUXDB_ADMIN_PASSWORD + user: $INFLUXDB_ADMIN_USER + database: telegraf + basicAuth: false + isDefault: false diff --git a/infrastructure/cdn-in-a-box/optional/grafana/run-grafana.sh b/infrastructure/cdn-in-a-box/optional/grafana/run-grafana.sh index ff782d1e35..930b7a1a12 100755 --- a/infrastructure/cdn-in-a-box/optional/grafana/run-grafana.sh +++ b/infrastructure/cdn-in-a-box/optional/grafana/run-grafana.sh @@ -58,6 +58,8 @@ export GF_SERVER_PROTOCOL="https" export GF_SERVER_HTTP_PORT=$GRAFANA_PORT export GF_SERVER_CERT_FILE=$X509_INFRA_CERT_FILE export GF_SERVER_CERT_KEY=$X509_INFRA_KEY_FILE +export GF_DEFAULT_APP_MODE="development" envsubst < "/datasources.yml.template" > "$GF_PATHS_PROVISIONING/datasources/datasources.yml" +envsubst < "/app.yaml.template" > "$GF_PATHS_PROVISIONING/plugins/app.yaml" /run.sh diff --git a/infrastructure/docker/build/Dockerfile-traffic_stats b/infrastructure/docker/build/Dockerfile-traffic_stats index 8b946d33c5..3c52eee3e6 100644 --- a/infrastructure/docker/build/Dockerfile-traffic_stats +++ b/infrastructure/docker/build/Dockerfile-traffic_stats @@ -42,6 +42,9 @@ RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-* && \ ### traffic_stats specific requirements FROM common-dependencies AS traffic-stats +RUN curl -sL https://rpm.nodesource.com/setup_20.x | bash - && \ + yum -y install nodejs + COPY GO_VERSION / RUN set -o nounset -o errexit; \ rpm_arch="$(rpm --eval %_arch)" && \ diff --git a/infrastructure/docker/build/docker-compose.yml b/infrastructure/docker/build/docker-compose.yml index 271442a571..458d9a1f7a 100644 --- a/infrastructure/docker/build/docker-compose.yml +++ b/infrastructure/docker/build/docker-compose.yml @@ -149,6 +149,7 @@ services: - linux/arm64 volumes: - ../../..:/trafficcontrol:z + - ../../../.npm:/root/.npm:z grove_build: image: apache/traffic_grove_builder:master diff --git a/traffic_stats/build/build_rpm.sh b/traffic_stats/build/build_rpm.sh index 54f5d5c62f..2437e1ece4 100755 --- a/traffic_stats/build/build_rpm.sh +++ b/traffic_stats/build/build_rpm.sh @@ -78,6 +78,19 @@ initBuildArea() { go build -v -gcflags "$gcflags" -ldflags "$ldflags" create/create_ts_databases.go || \ { echo "Could not build create_ts_databases binary"; return 1; }) + # compile trafficcontrol-scenes + echo "Installing grafana scenes npm dependencies" + (cd trafficcontrol-scenes + npm i || \ + { echo "Could not install packages from $TS_DIR/trafficcontrol-scenes: $?"; return 1; } + ) + + echo "Build grafana scenes" + (cd trafficcontrol-scenes + npm run build || \ + { echo "Could not build $TS_DIR/trafficcontrol-scenes: $?"; return 1; } + ) + rsync -aLv ./ "$ts_dest"/ || \ { echo "Could not copy to $ts_dest: $?"; return 1; } cp "$TS_DIR"/build/*.spec "$RPMBUILD"/SPECS/. || \ @@ -103,6 +116,6 @@ preBuildChecks() { importFunctions preBuildChecks -checkEnvironment -i go,rsync +checkEnvironment -i npm,go,rsync initBuildArea buildRpm traffic_stats diff --git a/traffic_stats/build/traffic_stats.spec b/traffic_stats/build/traffic_stats.spec index 2c7ab0197c..e9ace68aeb 100644 --- a/traffic_stats/build/traffic_stats.spec +++ b/traffic_stats/build/traffic_stats.spec @@ -50,6 +50,13 @@ godir=src/github.com/apache/trafficcontrol/traffic_stats/influxdb_tools cp -R "$TC_DIR"/traffic_stats/influxdb_tools/* . ) || { echo "Could not copy go program at $(pwd): $!"; exit 1; } +# copy trafficcontrol-scenes +scenesdir=src/github.com/apache/trafficcontrol/traffic_stats/trafficcontrol-scenes +( mkdir -p "$scenesdir" && \ + cd "$scenesdir" && \ + cp -R "$TC_DIR"/traffic_stats/trafficcontrol-scenes/* . +) || { echo "Could not copy trafficcontrol-scenes at $(pwd): $!"; exit 1; } + %install mkdir -p "${RPM_BUILD_ROOT}"/opt/traffic_stats mkdir -p "${RPM_BUILD_ROOT}"/opt/traffic_stats/bin @@ -60,7 +67,7 @@ mkdir -p "${RPM_BUILD_ROOT}"/opt/traffic_stats/var/run mkdir -p "${RPM_BUILD_ROOT}"/opt/traffic_stats/var/log/traffic_stats mkdir -p "${RPM_BUILD_ROOT}"/etc/init.d mkdir -p "${RPM_BUILD_ROOT}"/etc/logrotate.d -mkdir -p "${RPM_BUILD_ROOT}"/usr/share/grafana/public/dashboards/ +mkdir -p "${RPM_BUILD_ROOT}"/var/lib/grafana/plugins/trafficcontrol-scenes-app src=src/github.com/apache/trafficcontrol/traffic_stats cp -p "$src"/traffic_stats "${RPM_BUILD_ROOT}"/opt/traffic_stats/bin/traffic_stats @@ -68,7 +75,7 @@ cp "$src"/traffic_stats.cfg "${RPM_BUILD_ROOT}"/opt/traffic_stats/conf/tr cp "$src"/traffic_stats_seelog.xml "${RPM_BUILD_ROOT}"/opt/traffic_stats/conf/traffic_stats_seelog.xml cp "$src"/traffic_stats.init "${RPM_BUILD_ROOT}"/etc/init.d/traffic_stats cp "$src"/traffic_stats.logrotate "${RPM_BUILD_ROOT}"/etc/logrotate.d/traffic_stats -cp "$src"/grafana/*.js "${RPM_BUILD_ROOT}"/usr/share/grafana/public/dashboards/ +cp -r "$src"/trafficcontrol-scenes/dist/* "${RPM_BUILD_ROOT}"/var/lib/grafana/plugins/trafficcontrol-scenes-app/ cp "$src"/influxdb_tools/sync_ts_databases "${RPM_BUILD_ROOT}"/opt/traffic_stats/influxdb_tools/ cp "$src"/influxdb_tools/create_ts_databases "${RPM_BUILD_ROOT}"/opt/traffic_stats/influxdb_tools/ @@ -125,15 +132,12 @@ fi %dir /opt/traffic_stats/var/log %dir /opt/traffic_stats/var/run %dir /opt/traffic_stats/var/log/traffic_stats -%dir /usr/share/grafana/public/dashboards +%dir /var/lib/grafana/plugins/trafficcontrol-scenes-app %dir /opt/traffic_stats/influxdb_tools %attr(755, traffic_stats, traffic_stats) /opt/traffic_stats/bin/traffic_stats %attr(755, traffic_stats, traffic_stats) /etc/init.d/traffic_stats -%attr(644, traffic_stats, traffic_stats) /usr/share/grafana/public/dashboards/traffic_ops_cachegroup.js -%attr(644, traffic_stats, traffic_stats) /usr/share/grafana/public/dashboards/traffic_ops_deliveryservice.js -%attr(644, traffic_stats, traffic_stats) /usr/share/grafana/public/dashboards/traffic_ops_scripted.js -%attr(644, traffic_stats, traffic_stats) /usr/share/grafana/public/dashboards/traffic_ops_server.js +%attr(755, traffic_stats, traffic_stats) /var/lib/grafana/plugins/trafficcontrol-scenes-app %attr(755, traffic_stats, traffic_stats) /opt/traffic_stats/influxdb_tools/create_ts_databases %attr(755, traffic_stats, traffic_stats) /opt/traffic_stats/influxdb_tools/sync_ts_databases diff --git a/traffic_stats/grafana/traffic_ops_cachegroup.js b/traffic_stats/grafana/traffic_ops_cachegroup.js deleted file mode 100644 index a714a585ce..0000000000 --- a/traffic_stats/grafana/traffic_ops_cachegroup.js +++ /dev/null @@ -1,254 +0,0 @@ -/* - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/* global _ */ - -/* - * Scripted dashboard for traffic ops. - * - * Based on the grafana scripted.js script (which is ASF 2.0 licensed). - */ - - - -// accessible variables in this scope -var window, document, ARGS, $, jQuery, moment, kbn; - -// Setup some variables -var dashboard; - -// All url parameters are available via the ARGS object -var ARGS; - -// Intialize a skeleton with nothing but a rows array and service object -dashboard = { - rows : [], -}; - - -// Set default time -// time can be overriden in the url using from/to parameters, but this is -// handled automatically in grafana core during dashboard initialization -dashboard.time = { - from: "now-6h", - to: "now-60s" -}; - -var which = 'argName'; - -if(!_.isUndefined(ARGS.which)) { - which = ARGS.which; -} - - -// Set a title -dashboard.title = which; -//set refresh interval -dashboard.refresh = "30s"; - -{ - dashboard.rows.push( { - "height": "250px", - "panels": [ - { - "title": "total bandwidth (stacked)", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 1, - "datasource": "cache_stats", - "renderer": "flot", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps", - "short" - ], - "grid": { - "leftLogBase": 1, - "leftMax": null, - "rightMax": null, - "leftMin": null, - "rightMin": null, - "rightLogBase": 1, - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": true, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "rawQuery": true, - "query": "SELECT sum(value)*1000 FROM \"monthly\".\"bandwidth.1min\" WHERE cachegroup='" + which + "' and $timeFilter GROUP BY time(60s), hostname", - "alias": "$tag_hostname" - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - }, - { - "title": "Connections (stacked)", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "isNew": true, - "id": 2, - "targets": [ - { - "refId": "A", - "policy": "monthly", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - "key": "cachegroup", - "operator": "=", - "value": which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "tag", - "params": [ - "hostname" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "value" - ] - }, - { - "type": "mean", - "params": [] - } - ] - ], - "measurement": "connections.1min" - } - ], - "datasource": "cache_stats", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": true, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false, - "hideEmpty": true, - "hideZero": true - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true, - "msResolution": true - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ], - "title": "Row", - "collapse": false, - "editable": true - } - ); -} -return dashboard; diff --git a/traffic_stats/grafana/traffic_ops_deliveryservice.js b/traffic_stats/grafana/traffic_ops_deliveryservice.js deleted file mode 100644 index 2508e3c86e..0000000000 --- a/traffic_stats/grafana/traffic_ops_deliveryservice.js +++ /dev/null @@ -1,301 +0,0 @@ -/* - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/* global _ */ - -/* - * Scripted dashboard for traffic ops. - * - * Based on the grafana scripted.js script (which is ASF 2.0 licensed). - */ - - - -// accessible variables in this scope -var window, document, ARGS, $, jQuery, moment, kbn; - -// Setup some variables -var dashboard; - -// All url parameters are available via the ARGS object -var ARGS; - -// Intialize a skeleton with nothing but a rows array and service object -dashboard = { - rows : [], -}; - - -// Set default time -// time can be overriden in the url using from/to parameters, but this is -// handled automatically in grafana core during dashboard initialization -dashboard.time = { - from: "now-6h", - to: "now-60s" -}; - -var which = 'argName'; - -if(!_.isUndefined(ARGS.which)) { - which = ARGS.which; -} - -// Set a title -dashboard.title = which; -//set refresh interval -dashboard.refresh = "30s"; - -{ - dashboard.rows.push( { - "collapse": false, - "editable": true, - "height": "250px", - "panels": [ - { - "aliasColors": { - "bw {deliveryservice: xb-dlassets}": "#7EB26D" - }, - "bars": false, - "datasource": "deliveryservice_stats", - "editable": true, - "error": false, - "fill": 1, - "grid": { - "leftLogBase": 1, - "leftMax": null, - "leftMin": null, - "rightLogBase": 1, - "rightMax": null, - "rightMin": null, - "threshold1": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2": null, - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "id": 1, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "measurement": "bw", - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"kbps.ds.1min\" WHERE deliveryservice='" + which + "' and cachegroup = 'total' and $timeFilter GROUP BY time(60s), deliveryservice ORDER BY asc", - "rawQuery": true, - "tags": { - "deliveryservice": which - }, - "alias": "$tag_deliveryservice" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "bandwidth", - "tooltip": { - "shared": true, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps", - "short" - ] - } - ], - "title": "DsGbps" - }, - { - "title": "TPS!", - "height": "250px", - "editable": true, - "collapse": false, - "panels": [ - { - "title": "tps", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 3, - "datasource": "deliveryservice_stats", - "renderer": "flot", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "grid": { - "leftLogBase": 1, - "leftMax": null, - "rightMax": null, - "leftMin": null, - "rightMin": null, - "rightLogBase": 1, - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "measurement": "tps_2xx", - "tags": { - "deliveryservice": which - }, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_2xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc", - "hide": false, - "rawQuery": true - }, - { - "target": "", - "rawQuery": true, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_3xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc" - }, - { - "target": "", - "rawQuery": true, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_4xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc" - }, - { - "target": "", - "rawQuery": true, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_5xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc" - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ] - }, - { - "collapse": false, - "editable": true, - "height": "250px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "datasource": "deliveryservice_stats", - "editable": true, - "error": false, - "fill": 1, - "grid": { - "leftLogBase": 1, - "leftMax": null, - "leftMin": null, - "rightLogBase": 1, - "rightMax": null, - "rightMin": null, - "threshold1": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2": null, - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "id": 2, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 12, - "stack": true, - "steppedLine": false, - "targets": [ - { - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"kbps.cg.1min\" WHERE deliveryservice='" + which + "' and cachegroup != 'all' and $timeFilter GROUP BY time(60s), cachegroup", - "rawQuery": true, - "alias": "$tag_cachegroup" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "bandwidth by cachegroup", - "tooltip": { - "shared": true, - "value_type": "individual" - }, - "type": "graph", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps" - ] - } - ], - "title": "bwByCg" - } - ); -} -return dashboard; diff --git a/traffic_stats/grafana/traffic_ops_scripted.js b/traffic_stats/grafana/traffic_ops_scripted.js deleted file mode 100644 index 78a5d87f32..0000000000 --- a/traffic_stats/grafana/traffic_ops_scripted.js +++ /dev/null @@ -1,524 +0,0 @@ -/* - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/* global _ */ - -/* - * Scripted dashboard for traffic ops. - * - * Based on the grafana scripted.js script (which is ASF 2.0 licensed). - */ - - - -// accessible variables in this scope -var window, document, ARGS, $, jQuery, moment, kbn; - -// Setup some variables -var dashboard; - -// All url parameters are available via the ARGS object -var ARGS; - -// Intialize a skeleton with nothing but a rows array and service object -dashboard = { - rows : [], -}; - - -// Set default time -// time can be overriden in the url using from/to parameters, but this is -// handled automatically in grafana core during dashboard initialization -dashboard.time = { - from: "now-6h", - to: "now-60s" -}; - -var which = 'argName'; -var type = "argName"; - -if(!_.isUndefined(ARGS.which)) { - which = ARGS.which; -} - -if(!_.isUndefined(ARGS.type)) { - type = ARGS.type; -} -// Set a title -dashboard.title = which; -//set refresh interval -dashboard.refresh = "30s"; - -if (type == "deliveryservice") { - dashboard.rows.push( { - "collapse": false, - "editable": true, - "height": "250px", - "panels": [ - { - "aliasColors": { - "bw {deliveryservice: xb-dlassets}": "#7EB26D" - }, - "bars": false, - "datasource": "deliveryservice_stats", - "editable": true, - "error": false, - "fill": 1, - "grid": { - "leftLogBase": 1, - "leftMax": null, - "leftMin": null, - "rightLogBase": 1, - "rightMax": null, - "rightMin": null, - "threshold1": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2": null, - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "id": 1, - "legend": { - "avg": false, - "current": true, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "measurement": "bw", - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"kbps.ds.1min\" WHERE deliveryservice='" + which + "' and cachegroup = 'total' and $timeFilter GROUP BY time(60s), deliveryservice ORDER BY asc", - "rawQuery": true, - "tags": { - "deliveryservice": which - } - } - ], - "timeFrom": null, - "timeShift": null, - "title": "bandwidth", - "tooltip": { - "shared": true, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps", - "short" - ] - } - ], - "title": "DsGbps" - }, - { - "title": "TPS!", - "height": "250px", - "editable": true, - "collapse": false, - "panels": [ - { - "title": "tps", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 3, - "datasource": "deliveryservice_stats", - "renderer": "flot", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "short", - "short" - ], - "grid": { - "leftLogBase": 1, - "leftMax": null, - "rightMax": null, - "leftMin": null, - "rightMin": null, - "rightLogBase": 1, - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "measurement": "tps_2xx", - "tags": { - "deliveryservice": which - }, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_2xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc", - "hide": false, - "rawQuery": true - }, - { - "target": "", - "rawQuery": true, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_3xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc" - }, - { - "target": "", - "rawQuery": true, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_4xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc" - }, - { - "target": "", - "rawQuery": true, - "query": "SELECT mean(value) FROM \"monthly\".\"tps_5xx.ds.1min\" WHERE $timeFilter AND deliveryservice='" + which + "' GROUP BY time(60s) ORDER BY asc" - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ] - }, - { - "collapse": false, - "editable": true, - "height": "250px", - "panels": [ - { - "aliasColors": {}, - "bars": false, - "datasource": "deliveryservice_stats", - "editable": true, - "error": false, - "fill": 1, - "grid": { - "leftLogBase": 1, - "leftMax": null, - "leftMin": null, - "rightLogBase": 1, - "rightMax": null, - "rightMin": null, - "threshold1": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2": null, - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "id": 2, - "legend": { - "avg": false, - "current": true, - "hideEmpty": false, - "max": true, - "min": false, - "show": true, - "total": false, - "values": true - }, - "lines": true, - "linewidth": 2, - "links": [], - "nullPointMode": "connected", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "span": 12, - "stack": false, - "steppedLine": false, - "targets": [ - { - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"kbps.ds.1min\" WHERE deliveryservice='" + which + "' and cachegroup != 'total' and $timeFilter GROUP BY time(60s), cachegroup", - "rawQuery": true - } - ], - "timeFrom": null, - "timeShift": null, - "title": "bandwidth by cachegroup", - "tooltip": { - "shared": false, - "value_type": "cumulative" - }, - "type": "graph", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps", - "short" - ] - } - ], - "title": "bwByCg" - } - ); -} -else if ( type == "cachegroup" ) { - dashboard.rows.push( { - "height": "250px", - "panels": [ - { - "title": "total bandwidth (stacked)", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 1, - "datasource": "cache_stats", - "renderer": "flot", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps", - "short" - ], - "grid": { - "leftLogBase": 1, - "leftMax": null, - "rightMax": null, - "leftMin": null, - "rightMin": null, - "rightLogBase": 1, - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": true, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "rawQuery": true, - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"bandwidth.1min\" WHERE cachegroup='" + which + "' and $timeFilter GROUP BY time(60s), hostname" - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ], - "title": "Row", - "collapse": false, - "editable": true - } - ); -} -else if ( type == "server" ) { - dashboard.rows.push( - { - "height": "250px", - "panels": [ - { - "title": "bandwidth", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 1, - "datasource": "cache_stats", - "renderer": "flot", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "bps", - "short" - ], - "grid": { - "leftLogBase": 1, - "leftMax": null, - "rightMax": null, - "leftMin": null, - "rightMin": null, - "rightLogBase": 1, - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "measurement": "bandwidth", - "tags": {}, - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"bandwidth.1min\" WHERE hostname='" + which + "' and $timeFilter GROUP BY time(60s)", - "rawQuery": true - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ], - "title": "Row", - "collapse": false, - "editable": true - }, - { - "height": "250px", - "panels": [ - { - "title": "conns", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 2, - "datasource": "cache_stats", - "renderer": "flot", - "x-axis": true, - "y-axis": true, - "y_formats": [ - "short" - ], - "grid": { - "leftLogBase": 1, - "leftMax": null, - "rightMax": null, - "leftMin": null, - "rightMin": null, - "rightLogBase": 1, - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "measurement": "bandwidth", - "tags": {}, - "query": "SELECT mean(value)*1000 FROM \"monthly\".\"connections.1min\" WHERE hostname='" + which + "' and $timeFilter GROUP BY time(60s)", - "rawQuery": true - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ], - "title": "Row", - "collapse": false, - "editable": true - } - ); -} -return dashboard; diff --git a/traffic_stats/grafana/traffic_ops_server.js b/traffic_stats/grafana/traffic_ops_server.js deleted file mode 100644 index 786bb7b7bf..0000000000 --- a/traffic_stats/grafana/traffic_ops_server.js +++ /dev/null @@ -1,1372 +0,0 @@ -/* - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -/* - * Scripted dashboard for traffic ops. - * - * Based on the grafana scripted.js script (which is ASF 2.0 licensed). - */ - -'use strict'; - -// Setup some variables -var dashboard; - -// All URL parameters are available via the ARGS object -var ARGS; - -// Intialize a skeleton with nothing but a rows array and service object, -// and setting default time and refresh interval. -dashboard = { - refresh: "30s", - rows: [], - // time can be overridden in the URL using from/to parameters, but this is - // handled automatically in grafana core during dashboard initialization - time: { - from: "now-24h", - to: "now" - } -}; - -let which = 'argName'; - -if (ARGS.which !== undefined) { - which = ARGS.which; -} - -// Set a title -dashboard.title = which; - -{ - dashboard.rows.push( - { - "height": "250px", - "panels": [ - { - "title": "bandwidth", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 1, - "datasource": "cache_stats", - "renderer": "flot", - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true, - "sort": 0, - "msResolution": false - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "measurement": "bandwidth.1min", - "tags": {}, - "query": `SELECT mean(value) FROM "monthly"."bandwidth.1min" WHERE hostname= '${which}' and $timeFilter GROUP BY time(60s)`, - "rawQuery": true, - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "value" - ] - }, - { - "type": "mean", - "params": [] - } - ] - ], - "alias": "bandwidth" - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [], - "yaxes": [ - { - "show": true, - "min": null, - "max": null, - "logBase": 1, - "format": "Kbits" - }, - { - "show": true, - "min": null, - "max": null, - "logBase": 1, - "format": "short" - } - ], - "xaxis": { - "show": true - } - } - ], - "title": "Row", - "collapse": false, - "editable": true - }, - { - "height": "250px", - "panels": [ - { - "title": "conns", - "error": false, - "span": 12, - "editable": true, - "type": "graph", - "id": 2, - "datasource": "cache_stats", - "renderer": "flot", - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": true, - "min": false, - "max": true, - "current": true, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true, - "sort": 0, - "msResolution": false - }, - "timeFrom": null, - "timeShift": null, - "targets": [ - { - "measurement": "connections.1min", - "tags": {}, - "query": `SELECT mean(value) FROM "monthly"."connections.1min" WHERE hostname= '${which}' and $timeFilter GROUP BY time(60s)`, - "rawQuery": true, - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "value" - ] - }, - { - "type": "mean", - "params": [] - } - ] - ], - "alias": "connections" - } - ], - "aliasColors": {}, - "seriesOverrides": [], - "links": [], - "yaxes": [ - { - "show": true, - "min": null, - "max": null, - "logBase": 1, - "format": "short" - }, - { - "show": true, - "min": null, - "max": null, - "logBase": 1 - } - ], - "xaxis": { - "show": true - } - } - ], - "title": "Row", - "collapse": false, - "editable": true - }, - { - "title": "cpu and mem", - "height": "250px", - "editable": true, - "collapse": false, - "panels": [ - { - "title": "CPU Usage", - "error": false, - "span": 6, - "editable": true, - "type": "graph", - "isNew": true, - "id": 3, - "targets": [ - { - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "host", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "usage_system" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "cpu_system" - ] - } - ], - [ - { - "type": "field", - "params": [ - "usage_iowait" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "cpu_iowait" - ] - } - ], - [ - { - "type": "field", - "params": [ - "usage_user" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "cpu_user" - ] - } - ], - [ - { - "type": "field", - "params": [ - "usage_guest" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "cpu_guest" - ] - } - ], - [ - { - "type": "field", - "params": [ - "usage_steal" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "cpu_steal" - ] - } - ] - ], - "measurement": "cpu", - "alias": "$col" - } - ], - "datasource": "telegraf", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "percent" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": true, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true, - "msResolution": true, - "sort": 2 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - }, - { - "title": "Memory Usage", - "error": false, - "span": 6, - "editable": true, - "type": "graph", - "isNew": true, - "id": 4, - "targets": [ - { - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "host", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "used_percent" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "mem_used" - ] - } - ] - ], - "measurement": "mem", - "alias": "$col" - } - ], - "datasource": "telegraf", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "percent" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": true, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "individual", - "shared": true, - "msResolution": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ] - }, - { - "title": "load avg and diskio", - "height": "250px", - "editable": true, - "collapse": false, - "panels": [ - { - "title": "Load Average", - "error": false, - "span": 6, - "editable": true, - "type": "graph", - "isNew": true, - "id": 5, - "targets": [ - { - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "host", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "load1" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "load1" - ] - } - ], - [ - { - "type": "field", - "params": [ - "load5" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "load5" - ] - } - ], - [ - { - "type": "field", - "params": [ - "load15" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "load15" - ] - } - ] - ], - "measurement": "system", - "alias": "$col" - } - ], - "datasource": "telegraf", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true, - "msResolution": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - }, - { - "title": "Read/Write Time", - "error": false, - "span": 6, - "editable": true, - "type": "graph", - "isNew": true, - "id": 6, - "targets": [ - { - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "host", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "read_time" - ] - }, - { - "type": "sum", - "params": [] - }, - { - "type": "non_negative_derivative", - "params": [ - "10s" - ] - }, - { - "type": "alias", - "params": [ - "read_time" - ] - } - ] - ], - "measurement": "diskio", - "alias": "$col" - }, - { - "refId": "B", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "host", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "write_time" - ] - }, - { - "type": "sum", - "params": [] - }, - { - "type": "non_negative_derivative", - "params": [ - "10s" - ] - }, - { - "type": "alias", - "params": [ - "write_time" - ] - } - ] - ], - "measurement": "diskio", - "alias": "$col" - } - ], - "datasource": "telegraf", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "ns" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true, - "msResolution": true, - "sort": 0 - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ] - }, - { - "title": "Wrap Count and netstat", - "height": "250px", - "editable": true, - "collapse": false, - "panels": [ - { - "title": "wrap count", - "error": false, - "span": 6, - "editable": true, - "type": "graph", - "isNew": true, - "id": 7, - "targets": [ - { - "refId": "A", - "policy": "monthly", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "hostname", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "vol1_wrap_count" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "vol1" - ] - } - ], - [ - { - "type": "field", - "params": [ - "vol2_wrap_count" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "vol2" - ] - } - ] - ], - "measurement": "wrap_count.1min", - "alias": "$col" - } - ], - "datasource": "cache_stats", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true, - "sort": 0, - "msResolution": true - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - }, - { - "title": "netstat", - "error": false, - "span": 6, - "editable": true, - "type": "graph", - "isNew": true, - "id": 8, - "targets": [ - { - "refId": "A", - "policy": "default", - "dsType": "influxdb", - "resultFormat": "time_series", - "tags": [ - { - key: "host", - operator: "=", - value: which - } - ], - "groupBy": [ - { - "type": "time", - "params": [ - "$interval" - ] - }, - { - "type": "fill", - "params": [ - "null" - ] - } - ], - "select": [ - [ - { - "type": "field", - "params": [ - "tcp_close" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_close" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_close_wait" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_close_wait" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_established" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_established" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_time_wait" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_time_wait" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_closing" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_closing" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_fin_wait1" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_fin_wait1" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_fin_wait2" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_fin_wait2" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_last_ack" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_last_ack" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_syn_recv" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_syn_recv" - ] - } - ], - [ - { - "type": "field", - "params": [ - "tcp_syn_sent" - ] - }, - { - "type": "mean", - "params": [] - }, - { - "type": "alias", - "params": [ - "tcp_syn_sent" - ] - } - ] - ], - "measurement": "netstat", - "alias": "$col" - } - ], - "datasource": "telegraf", - "renderer": "flot", - "yaxes": [ - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - }, - { - "label": null, - "show": true, - "logBase": 1, - "min": null, - "max": null, - "format": "short" - } - ], - "xaxis": { - "show": true - }, - "grid": { - "threshold1": null, - "threshold2": null, - "threshold1Color": "rgba(216, 200, 27, 0.27)", - "threshold2Color": "rgba(234, 112, 112, 0.22)" - }, - "lines": true, - "fill": 1, - "linewidth": 2, - "points": false, - "pointradius": 5, - "bars": false, - "stack": false, - "percentage": false, - "legend": { - "show": true, - "values": false, - "min": false, - "max": false, - "current": false, - "total": false, - "avg": false, - "hideEmpty": true, - "hideZero": true - }, - "nullPointMode": "connected", - "steppedLine": false, - "tooltip": { - "value_type": "cumulative", - "shared": true, - "sort": 2, - "msResolution": true - }, - "timeFrom": null, - "timeShift": null, - "aliasColors": {}, - "seriesOverrides": [], - "links": [] - } - ] - } - ); -} -return dashboard; diff --git a/traffic_stats/trafficcontrol-scenes/.editorconfig b/traffic_stats/trafficcontrol-scenes/.editorconfig new file mode 100644 index 0000000000..947e3cf3ce --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/.editorconfig @@ -0,0 +1,34 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = tab +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = double + +[*.html] +indent_size = 2 + +[*.json] +indent_size = 2 + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/traffic_stats/trafficcontrol-scenes/.eslintrc.json b/traffic_stats/trafficcontrol-scenes/.eslintrc.json new file mode 100644 index 0000000000..f988ed8944 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/.eslintrc.json @@ -0,0 +1,466 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +{ + "root": true, + "ignorePatterns": [ + "projects/**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": { + "@typescript-eslint/explicit-function-return-type": "error" + } + }, + { + "files": [ + "*.ts", + "*.tsx", + "*.js" + ], + "parserOptions": { + "project": [ + "tsconfig.json" + ], + "createDefaultProgram": true + }, + "extends": [ + "@grafana/eslint-config" + ], + "plugins": [ + "react", + "@typescript-eslint", + "eslint-plugin-import", + "eslint-plugin-jsdoc", + "eslint-plugin-prefer-arrow" + ], + "rules": { + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/unified-signatures": "error", + "complexity": "off", + "constructor-super": "error", + "no-mixed-spaces-and-tabs": "error", + "eqeqeq": [ + "error", + "smart" + ], + "guard-for-in": "error", + "id-blacklist": [ + "error", + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined", + "undefined" + ], + "id-match": "error", + "import/no-deprecated": "warn", +// "jsdoc/newline-after-description": "error", + "max-classes-per-file": "off", + "no-caller": "error", + "no-cond-assign": "error", + "no-console": [ + "error", + { + "allow": [ + "trace", + "dir", + "timeLog", + "assert", + "clear", + "count", + "countReset", + "group", + "groupEnd", + "table", + "groupCollapsed", + "Console", + "profile", + "profileEnd", + "timeStamp", + "context" + ] + } + ], + "no-debugger": "error", + "no-eval": "error", + "no-new-wrappers": "error", + "no-throw-literal": "error", + "no-undef-init": "error", + "no-underscore-dangle": "error", + "no-unsafe-finally": "error", + "no-unused-labels": "error", + "no-var": "error", + "object-shorthand": "error", + "one-var": [ + "error", + "never" + ], + "prefer-const": "error", + "radix": "error", + "use-isnan": "error", + "valid-typeof": "off", + "arrow-body-style": "error", + "comma-dangle": "off", + "curly": "error", + "eol-last": "error", + "jsdoc/check-alignment": "error", + "max-len": [ + "error", + { + "code": 140 + } + ], + "new-parens": "error", + "no-trailing-spaces": "error", + "quote-props": [ + "error", + "as-needed" + ], + "space-before-function-paren": [ + "error", + { + "anonymous": "never", + "asyncArrow": "always", + "named": "never" + } + ], + "quotes": "off", + "@typescript-eslint/type-annotation-spacing": "error", + "@typescript-eslint/array-type": "off", + "@typescript-eslint/await-thenable": "error", + "@typescript-eslint/ban-types": [ + "error", + { + "extendDefaults": false, + "types": { + "Object": { + "message": "Avoid using the `Object` type. Did you mean `object`?" + }, + "Function": { + "message": "Avoid using the `Function` type. Prefer a specific function type, like `() => void`." + }, + "Boolean": { + "message": "Avoid using the `Boolean` type. Did you mean `boolean`?" + }, + "Number": { + "message": "Avoid using the `Number` type. Did you mean `number`?" + }, + "String": { + "message": "Avoid using the `String` type. Did you mean `string`?" + }, + "Symbol": { + "message": "Avoid using the `Symbol` type. Did you mean `symbol`?" + } + } + } + ], + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-definitions": "error", + "@typescript-eslint/dot-notation": "error", + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "explicit", + "overrides": { + "constructors": "off" + } + } + ], + "@typescript-eslint/explicit-module-boundary-types": "error", + "@typescript-eslint/indent": [ + "error", + "tab" + ], + "@typescript-eslint/member-delimiter-style": [ + "error", + { + "multiline": { + "delimiter": "semi", + "requireLast": true + }, + "singleline": { + "delimiter": "semi", + "requireLast": false + } + } + ], + "@typescript-eslint/member-ordering": "off", + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "enumMember", + "format": [ + "UPPER_CASE" + ] + }, + { + "selector": "property", + "modifiers": [ + "static", + "readonly" + ], + "format": [ + "UPPER_CASE" + ] + }, + { + "selector": "default", + "format": [ + "camelCase" + ], + "leadingUnderscore": "allow", + "trailingUnderscore": "allow" + }, + { + "selector": "variable", + "format": [ + "camelCase", + "UPPER_CASE", + "PascalCase" + ], + "leadingUnderscore": "allow", + "trailingUnderscore": "allow" + }, + { + "selector": "typeLike", + "format": [ + "PascalCase" + ] + } + ], + "@typescript-eslint/no-empty-function": "error", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-extraneous-class": [ + "error", + { + "allowWithDecorator": true + } + ], + "@typescript-eslint/no-duplicate-imports": [ + "error" + ], + "@typescript-eslint/no-dynamic-delete": "error", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/no-inferrable-types": [ + "warn", + { + "ignoreParameters": true + } + ], + "@typescript-eslint/no-invalid-this": [ + "error", + { + "capIsConstructor": false + } + ], + "@typescript-eslint/no-invalid-void-type": "error", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-misused-promises": "error", + "@typescript-eslint/no-non-null-assertion": "error", + "@typescript-eslint/no-redeclare": "error", + "@typescript-eslint/no-require-imports": "error", + "@typescript-eslint/no-shadow": "error", + "@typescript-eslint/no-this-alias": "error", + "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error", + "@typescript-eslint/no-unnecessary-qualifier": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "error", + "@typescript-eslint/no-unnecessary-type-assertion": "error", + "@typescript-eslint/no-unused-expressions": "error", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-use-before-define": "error", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/prefer-for-of": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/prefer-readonly": "error", + "@typescript-eslint/promise-function-async": "error", + "@typescript-eslint/quotes": [ + "error", + "double", + { + "avoidEscape": true + } + ], + "@typescript-eslint/semi": [ + "error" + ], + "@typescript-eslint/typedef": "off", + "jsdoc/no-types": "error", + "jsdoc/require-description": "error", + "jsdoc/require-jsdoc": [ + "error", + { + "contexts": [ + "ClassProperty", + "TSInterfaceDeclaration", + "TSTypeAliasDeclaration", + "TSEnumDeclaration", + "TSEnumMember", + "TSAbstractClassProperty" + ], + "require": { + "ClassDeclaration": true, + "MethodDefinition": true + }, + "checkConstructors": false, + "checkGetters": true, + "checkSetters": false, + "enableFixer": false + } + ], + "@typescript-eslint/unbound-method": "error", + "@typescript-eslint/restrict-plus-operands": "error", + "@typescript-eslint/triple-slash-reference": "error", + "arrow-parens": [ + "off", + "always" + ], + "brace-style": [ + "error", + "1tbs" + ], + "class-methods-use-this": "off", + "import/export": "error", + "import/first": "error", + "import/newline-after-import": "error", + "import/no-cycle": [ + "error", + { + "ignoreExternal": true + } + ], + "import/no-self-import": "error", + "import/no-useless-path-segments": [ + "error", + { + "commonjs": true, + "noUselessIndex": true + } + ], + "import/order": [ + "error", + { + "alphabetize": { + "order": "asc" + }, + "groups": [ + "builtin", + "external", + "internal", + "parent", + "sibling" + ], + "pathGroups": [ + { + "group": "builtin", + "pattern": "zone.js/**/*", + "position": "before" + }, + { + "group": "external", + "pattern": "(@(angular|fortawesome)|chart.js|rxjs)*/**/*", + "position": "before" + }, + { + "group": "internal", + "pattern": "src/**/*" + } + ], + "pathGroupsExcludedImportTypes": [ + "zone.js/**/*", + "@fortawesome*/**/*", + "chart.js", + "rxjs" + ], + "newlines-between": "always", + "warnOnUnassignedImports": true + } + ], + "linebreak-style": [ + "error", + "unix" + ], + "no-bitwise": "off", + "no-duplicate-case": "error", + "no-duplicate-imports": "off", + "no-else-return": "error", + "no-empty": "error", + "no-extra-bind": "error", + "no-fallthrough": "off", + "no-invalid-this": "off", + "no-multiple-empty-lines": [ + "error", + { + "max": 1, + "maxBOF": 0, + "maxEOF": 0 + } + ], + "no-new-func": "error", + "no-redeclare": "off", + "no-restricted-imports": [ + "error", + { + "patterns": [ + { + "message": "Going up more than one directory for an import is overly complex; use an import path that starts with 'src/' instead", + "group": [ + "../../*" + ] + } + ] + } + ], + "no-return-await": "error", + "no-sparse-arrays": "error", + "no-template-curly-in-string": "error", + "no-shadow": "off", + "prefer-arrow/prefer-arrow-functions": "off", + "prefer-object-spread": "error", + "prefer-template": "error", + "sort-keys": [ + "error", + "asc", + { + "natural": true + } + ], + "valid-jsdoc": [ + "error", + { + "matchDescription": ".+", + "requireReturn": false, + "requireReturnType": false, + "requireParamType": false, + "prefer": { + "return": "returns" + } + } + ] + } + } + ] +} diff --git a/traffic_stats/trafficcontrol-scenes/.gitignore b/traffic_stats/trafficcontrol-scenes/.gitignore new file mode 100644 index 0000000000..ce360f4528 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/.gitignore @@ -0,0 +1,56 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# dependencies +/node_modules + +# compiled output +/dist + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +.sass-cache/ +/connect.lock +/coverage +/TESTS-*.xml +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings +yarn.lock + +# System Files +.DS_Store +Thumbs.db diff --git a/traffic_stats/trafficcontrol-scenes/cypress.json b/traffic_stats/trafficcontrol-scenes/cypress.json new file mode 100644 index 0000000000..60ed5aa538 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/cypress.json @@ -0,0 +1,3 @@ +{ + "video": false +} diff --git a/traffic_stats/trafficcontrol-scenes/cypress/integration/01-smoke.spec.ts b/traffic_stats/trafficcontrol-scenes/cypress/integration/01-smoke.spec.ts new file mode 100644 index 0000000000..2c274a4cfc --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/cypress/integration/01-smoke.spec.ts @@ -0,0 +1,24 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import { e2e } from '@grafana/e2e'; + +e2e.scenario({ + describeName: 'Smoke test', + itName: 'Smoke test', + scenario: () => { + e2e.pages.Home.visit(); + e2e().contains('Welcome to Grafana').should('be.visible'); + }, +}); diff --git a/traffic_stats/trafficcontrol-scenes/jest-setup.js b/traffic_stats/trafficcontrol-scenes/jest-setup.js new file mode 100644 index 0000000000..67df3f46f2 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/jest-setup.js @@ -0,0 +1,16 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// Jest setup provided by Grafana scaffolding +import './.config/jest-setup'; diff --git a/traffic_stats/trafficcontrol-scenes/jest.config.js b/traffic_stats/trafficcontrol-scenes/jest.config.js new file mode 100644 index 0000000000..4d90504af5 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/jest.config.js @@ -0,0 +1,22 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// force timezone to UTC to allow tests to work regardless of local timezone +// generally used by snapshots, but can affect specific tests +process.env.TZ = 'UTC'; + +module.exports = { + // Jest configuration provided by Grafana scaffolding + ...require('./.config/jest.config'), +}; diff --git a/traffic_stats/trafficcontrol-scenes/package.json b/traffic_stats/trafficcontrol-scenes/package.json new file mode 100644 index 0000000000..0918bdafe4 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/package.json @@ -0,0 +1,78 @@ +{ + "name": "trafficcontrol-scenes", + "version": "1.0.0", + "description": "Traffic Control Grafana Scenes", + "scripts": { + "build": "webpack -c ./webpack/webpack.config.ts --env production", + "dev": "webpack -w -c ./webpack/webpack.config.ts --env development", + "test": "jest --watch --onlyChanged", + "test:ci": "jest --passWithNoTests --maxWorkers 4", + "typecheck": "tsc --noEmit", + "lint": "eslint --cache --ignore-path ./.gitignore --ext .js,.jsx,.ts,.tsx .", + "lint:fix": "npm run lint -- --fix", + "e2e": "npm exec cypress install && npm exec grafana-e2e run", + "e2e:update": "npm exec cypress install && npm exec grafana-e2e run --update-screenshots", + "server": "docker-compose up --build", + "sign": "npx --yes @grafana/sign-plugin@latest" + }, + "author": "ntheanh201", + "license": "Apache-2.0", + "devDependencies": { + "@babel/core": "^7.21.4", + "@grafana/e2e": "10.0.3", + "@grafana/e2e-selectors": "10.0.3", + "@grafana/eslint-config": "^6.0.0", + "@grafana/tsconfig": "^1.2.0-rc1", + "@swc/core": "^1.3.90", + "@swc/helpers": "^0.5.0", + "@swc/jest": "^0.2.26", + "@testing-library/jest-dom": "6.1.4", + "@testing-library/react": "14.0.0", + "@types/jest": "^29.5.0", + "@types/lodash": "^4.14.194", + "@types/node": "^20.8.7", + "@types/react-router-dom": "^5.3.3", + "@types/testing-library__jest-dom": "5.14.8", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.7.3", + "eslint-plugin-deprecation": "^2.0.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-webpack-plugin": "^4.0.1", + "fork-ts-checker-webpack-plugin": "^8.0.0", + "glob": "^10.2.7", + "identity-obj-proxy": "3.0.0", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "prettier": "^2.8.7", + "replace-in-file-webpack-plugin": "^1.0.6", + "sass": "1.63.2", + "sass-loader": "13.3.1", + "style-loader": "3.3.3", + "swc-loader": "^0.2.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "typescript": "4.8.4", + "webpack": "^5.86.0", + "webpack-cli": "^5.1.4", + "webpack-livereload-plugin": "^3.0.2" + }, + "engines": { + "node": ">=20" + }, + "dependencies": { + "@emotion/css": "11.10.6", + "@grafana/data": "10.0.3", + "@grafana/runtime": "10.0.3", + "@grafana/scenes": "^1.28.0", + "@grafana/schema": "10.0.3", + "@grafana/ui": "10.0.3", + "globby": "^14.0.0", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-router-dom": "5.3.3", + "rxjs": "7.8.0", + "tslib": "2.5.3" + }, + "packageManager": "npm@10.2.3" +} diff --git a/traffic_stats/trafficcontrol-scenes/src/components/App/App.tsx b/traffic_stats/trafficcontrol-scenes/src/components/App/App.tsx new file mode 100644 index 0000000000..cc9869cb53 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/components/App/App.tsx @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AppRootProps } from "@grafana/data"; +import { Routes } from "components/Routes"; +import React, { ReactElement } from "react"; +import { PluginPropsContext } from "utils/utils.plugin"; + +/** + * Renders the component by providing the PluginPropsContext to its children. + */ +export class App extends React.PureComponent { + /** + * Renders the component and returns the JSX element. + * + * @returns The JSX element representing the rendered component. + */ + public render(): ReactElement { + return ( + + + + ); + } +} diff --git a/traffic_stats/trafficcontrol-scenes/src/components/App/index.tsx b/traffic_stats/trafficcontrol-scenes/src/components/App/index.tsx new file mode 100644 index 0000000000..fa90d8097a --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/components/App/index.tsx @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./App"; diff --git a/traffic_stats/trafficcontrol-scenes/src/components/Routes/Routes.tsx b/traffic_stats/trafficcontrol-scenes/src/components/Routes/Routes.tsx new file mode 100644 index 0000000000..2978fa3b96 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/components/Routes/Routes.tsx @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ROUTES } from "const"; +import { CacheGroupPage } from "pages/CacheGroup"; +import { DeliveryServicePage } from "pages/DeliveryService"; +import { ServerPage } from "pages/Server"; +import React, { ReactElement } from "react"; +import { Redirect, Route, Switch } from "react-router-dom"; +import { prefixRoute } from "utils/utils.routing"; + +export const Routes = (): ReactElement => ( + + + + + + +); diff --git a/traffic_stats/trafficcontrol-scenes/src/components/Routes/index.tsx b/traffic_stats/trafficcontrol-scenes/src/components/Routes/index.tsx new file mode 100644 index 0000000000..53af424267 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/components/Routes/index.tsx @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./Routes"; diff --git a/traffic_stats/trafficcontrol-scenes/src/const.ts b/traffic_stats/trafficcontrol-scenes/src/const.ts new file mode 100644 index 0000000000..c4700295fc --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/const.ts @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import pluginJson from "./plugin.json"; + +export const PLUGIN_BASE_URL = `/a/${pluginJson.id}`; + +export const ROUTES = { + cacheGroup: "cache-group", + deliveryService: "delivery-service", + server: "server", +}; + +export const PROMETHEUS_DATASOURCE_REF = { + type: "prometheus", + uid: "prometheus", +}; + +export const INFLUXDB_DATASOURCES_REF = { + cacheStats: { + type: "influxdb", + uid: "cache_stats", + }, + dailyStats: { + type: "influxdb", + uid: "daily_stats", + }, + deliveryServiceStats: { + type: "influxdb", + uid: "deliveryservice_stats", + }, + telegraf: { + type: "influxdb", + uid: "telegraf", + }, +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/module.ts b/traffic_stats/trafficcontrol-scenes/src/module.ts new file mode 100644 index 0000000000..d8906244c9 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/module.ts @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AppPlugin } from "@grafana/data"; +import { App } from "components/App"; + +export const plugin = new AppPlugin<{}>().setRootPage(App); diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/CacheGroup.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/CacheGroup.tsx new file mode 100644 index 0000000000..d332b59da9 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/CacheGroup.tsx @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SceneApp, SceneAppPage } from "@grafana/scenes"; +import { ROUTES } from "const"; +import React, { ReactElement, useMemo } from "react"; +import { prefixRoute } from "utils/utils.routing"; + +import { getCacheGroupScene } from "./scene"; + +const getScene = (): SceneApp => + new SceneApp({ + pages: [ + new SceneAppPage({ + getScene: getCacheGroupScene, + hideFromBreadcrumbs: true, + title: "Cache Groups", + url: prefixRoute(`${ROUTES.cacheGroup}`), + }), + ], + }); + +export const CacheGroupPage = (): ReactElement => { + const scene = useMemo(() => getScene(), []); + + return ; +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/index.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/index.tsx new file mode 100644 index 0000000000..08234240e1 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/index.tsx @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./CacheGroup"; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/bandwidth.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/bandwidth.tsx new file mode 100644 index 0000000000..fc533c3688 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/bandwidth.tsx @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getBandwidthPanel = (): VizPanel => { + const cacheGroupBandwidthQuery = { + alias: "$tag_cachegroup", + query: + "SELECT sum(value) FROM \"monthly\".\"bandwidth.1min\" WHERE \"cachegroup\" = '$cachegroup'" + + "AND $timeFilter GROUP BY time(60s), cachegroup", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + queries: [cacheGroupBandwidthQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Total bandwidth (stacked)") + .setData(qr) + .setCustomFieldConfig("fillOpacity", 20) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setUnit("Kbits") + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/connections.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/connections.tsx new file mode 100644 index 0000000000..77fffdf2de --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/panels/connections.tsx @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getConnectionsPanel = (): VizPanel => { + const connectionQuery = { + query: + "SELECT mean(\"value\") FROM \"monthly\".\"connections.1min\" WHERE (\"cachegroup\" = '$cachegroup')" + + "AND $timeFilter GROUP BY time($interval), \"hostname\" fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + queries: [connectionQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Connections (stacked)") + .setCustomFieldConfig("fillOpacity", 20) + .setData(qr) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setCustomFieldConfig("spanNulls", true) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/scene.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/scene.tsx new file mode 100644 index 0000000000..8e9ad03e1b --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/CacheGroup/scene.tsx @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + EmbeddedScene, + QueryVariable, + SceneControlsSpacer, + SceneFlexItem, + SceneFlexLayout, + SceneRefreshPicker, + SceneTimePicker, + SceneTimeRange, + SceneVariableSet, + VariableValueSelectors, +} from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +import { getBandwidthPanel } from "./panels/bandwidth"; +import { getConnectionsPanel } from "./panels/connections"; + +/** + * Function to get the cache group scene. + * + * @returns The embedded scene representing the cache group. + */ +export function getCacheGroupScene(): EmbeddedScene { + const timeRange = new SceneTimeRange({ + from: "now-6h", + to: "now", + }); + + const cachegroup = new QueryVariable({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + name: "cachegroup", + query: 'SHOW TAG VALUES ON "cache_stats" FROM "monthly"."bandwidth" with key = "cachegroup"', + }); + + return new EmbeddedScene({ + $timeRange: timeRange, + $variables: new SceneVariableSet({ + variables: [cachegroup], + }), + body: new SceneFlexLayout({ + children: [ + new SceneFlexItem({ + body: getBandwidthPanel(), + minHeight: 300, + }), + new SceneFlexItem({ + body: getConnectionsPanel(), + minHeight: 300, + }), + ], + direction: "column", + }), + controls: [ + new VariableValueSelectors({}), + new SceneControlsSpacer(), + new SceneTimePicker({isOnCanvas: true}), + new SceneRefreshPicker({ + intervals: ["5s", "1m", "1h"], + isOnCanvas: true, + }), + ], + }); +} diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/DeliveryService.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/DeliveryService.tsx new file mode 100644 index 0000000000..97a06007e1 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/DeliveryService.tsx @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SceneApp, SceneAppPage } from "@grafana/scenes"; +import { ROUTES } from "const"; +import { getDeliveryServiceScene } from "pages/DeliveryService/scene"; +import React, { ReactElement, useMemo } from "react"; +import { prefixRoute } from "utils/utils.routing"; + +const getScene = (): SceneApp => + new SceneApp({ + pages: [ + new SceneAppPage({ + getScene: getDeliveryServiceScene, + hideFromBreadcrumbs: true, + title: "Delivery Services", + url: prefixRoute(`${ROUTES.deliveryService}`), + }), + ], + }); + +export const DeliveryServicePage = (): ReactElement => { + const scene = useMemo(() => getScene(), []); + + return ; +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/index.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/index.tsx new file mode 100644 index 0000000000..1edffd4314 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/index.tsx @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./DeliveryService"; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth-cg.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth-cg.tsx new file mode 100644 index 0000000000..6c6708fb63 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth-cg.tsx @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getBandwidthByCGPanel = (): VizPanel => { + const bandwidthByCacheGroupQuery = { + alias: "$tag_cachegroup", + query: "SELECT mean(value) FROM \"monthly\".\"kbps.cg.1min\" WHERE deliveryservice='$deliveryservice'" + + "AND cachegroup != 'all' and $timeFilter GROUP BY time(60s), cachegroup", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.deliveryServiceStats, + queries: [bandwidthByCacheGroupQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Bandwidth by CacheGroup") + .setData(qr) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setCustomFieldConfig("axisCenteredZero", true) + .setCustomFieldConfig("spanNulls", true) + .setUnit("bps") + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth.tsx new file mode 100644 index 0000000000..dfd5c89215 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/bandwidth.tsx @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getBandwidthPanel = (): VizPanel => { + const defaultBandwidthQuery = { + alias: "$tag_deliveryservice", + measurement: "bw", + query: "SELECT mean(value) FROM \"monthly\".\"kbps.ds.1min\" WHERE deliveryservice='$deliveryservice'" + + "AND cachegroup = 'total' and $timeFilter GROUP BY time(60s), deliveryservice ORDER BY asc", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.deliveryServiceStats, + queries: [defaultBandwidthQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Bandwidth") + .setData(qr) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setCustomFieldConfig("axisCenteredZero", true) + .setUnit("bps") + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/tps.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/tps.tsx new file mode 100644 index 0000000000..341c9e268f --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/panels/tps.tsx @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getTpsPanel = (): VizPanel => { + const tpsQueries = [ + { + measurement: "tps_2xx", + query: "SELECT mean(value) FROM \"monthly\".\"tps_2xx.ds.1min\" WHERE $timeFilter AND deliveryservice='$deliveryservice'" + + " GROUP BY time(60s) ORDER BY asc", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }, + { + query: "SELECT mean(value) FROM \"monthly\".\"tps_3xx.ds.1min\" WHERE $timeFilter AND deliveryservice='$deliveryservice'" + + " GROUP BY time(60s) ORDER BY asc", + rawQuery: true, + refId: "B", + resultFormat: "time_series", + }, + { + query: "SELECT mean(value) FROM \"monthly\".\"tps_4xx.ds.1min\" WHERE $timeFilter AND deliveryservice='$deliveryservice'" + + " GROUP BY time(60s) ORDER BY asc", + rawQuery: true, + refId: "C", + resultFormat: "time_series", + }, + { + query: "SELECT mean(value) FROM \"monthly\".\"tps_5xx.ds.1min\" WHERE $timeFilter AND deliveryservice='$deliveryservice' " + + "GROUP BY time(60s) ORDER BY asc", + rawQuery: true, + refId: "D", + resultFormat: "time_series", + }, + ]; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.deliveryServiceStats, + queries: [...tpsQueries], + }); + + return PanelBuilders.timeseries() + .setTitle("TPS") + .setData(qr) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setCustomFieldConfig("axisCenteredZero", true) + .setCustomFieldConfig("spanNulls", true) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/scene.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/scene.tsx new file mode 100644 index 0000000000..771f3bd83b --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/DeliveryService/scene.tsx @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + EmbeddedScene, + QueryVariable, + SceneControlsSpacer, + SceneFlexItem, + SceneFlexLayout, + SceneRefreshPicker, + SceneTimePicker, + SceneTimeRange, + SceneVariableSet, + VariableValueSelectors, +} from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +import { getBandwidthPanel } from "./panels/bandwidth"; +import { getBandwidthByCGPanel } from "./panels/bandwidth-cg"; +import { getTpsPanel } from "./panels/tps"; + +/** + * Returns an EmbeddedScene representing the delivery service scene. + * + * @returns EmbeddedScene representing the delivery service scene + */ +export function getDeliveryServiceScene(): EmbeddedScene { + const timeRange = new SceneTimeRange({ + from: "now-6h", + to: "now", + }); + + const deliveryService = new QueryVariable({ + datasource: INFLUXDB_DATASOURCES_REF.deliveryServiceStats, + name: "deliveryservice", + query: 'SHOW TAG VALUES ON "deliveryservice_stats" FROM "monthly"."kbps" with key = "deliveryservice"', + }); + + return new EmbeddedScene({ + $timeRange: timeRange, + $variables: new SceneVariableSet({ + variables: [deliveryService], + }), + body: new SceneFlexLayout({ + children: [ + new SceneFlexItem({ + body: getBandwidthPanel(), + minHeight: 300, + }), + new SceneFlexItem({ + body: getTpsPanel(), + minHeight: 300, + }), + new SceneFlexItem({ + body: getBandwidthByCGPanel(), + minHeight: 300, + }), + ], + direction: "column", + }), + controls: [ + new VariableValueSelectors({}), + new SceneControlsSpacer(), + new SceneTimePicker({isOnCanvas: true}), + new SceneRefreshPicker({ + intervals: ["5s", "1m", "1h"], + isOnCanvas: true, + }), + ], + }); +} diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/Server.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/Server.tsx new file mode 100644 index 0000000000..27552fe4ae --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/Server.tsx @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SceneApp, SceneAppPage } from "@grafana/scenes"; +import { ROUTES } from "const"; +import { getServerScene } from "pages/Server/scene"; +import React, { ReactElement, useMemo } from "react"; +import { prefixRoute } from "utils/utils.routing"; + +const getScene = (): SceneApp => + new SceneApp({ + pages: [ + new SceneAppPage({ + getScene: getServerScene, + hideFromBreadcrumbs: true, + title: "Server", + url: prefixRoute(`${ROUTES.server}`), + }), + ], + }); + +export const ServerPage = (): ReactElement => { + const scene = useMemo(() => getScene(), []); + + return ; +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/index.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/index.tsx new file mode 100644 index 0000000000..c219d65245 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/index.tsx @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./Server"; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/bandwidth.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/bandwidth.tsx new file mode 100644 index 0000000000..236c6b1ce0 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/bandwidth.tsx @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getBandwidthPanel = (): VizPanel => { + const defaultBandwidthQuery = { + alias: "bandwidth", + query: "SELECT mean(value) FROM \"monthly\".\"bandwidth.1min\" WHERE hostname='$hostname' AND $timeFilter GROUP BY time(60s)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + queries: [defaultBandwidthQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Bandwidth") + .setData(qr) + .setCustomFieldConfig("fillOpacity", 20) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setUnit("kbps") + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/connections.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/connections.tsx new file mode 100644 index 0000000000..49c31a3633 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/connections.tsx @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getConnectionsPanel = (): VizPanel => { + const defaultConnectionsQuery = [ + { + alias: "connections", + query: "SELECT mean(value) FROM \"monthly\".\"connections.1min\" WHERE hostname='$hostname' AND $timeFilter GROUP BY time(60s)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }, + ]; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + queries: [...defaultConnectionsQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Connections") + .setData(qr) + .setCustomFieldConfig("fillOpacity", 20) + .setOption("legend", {calcs: ["max"], showLegend: true}) + .setCustomFieldConfig("spanNulls", true) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/cpu.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/cpu.tsx new file mode 100644 index 0000000000..df7e670b4e --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/cpu.tsx @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getCPUPanel = (): VizPanel => { + const defaultQuery = { + alias: "$col", + query: "SELECT mean(\"usage_system\") AS \"cpu_system\", mean(\"usage_iowait\") AS \"cpu_iowait\"," + + " mean(\"usage_user\") AS \"cpu_user\", mean(\"usage_guest\") AS \"cpu_guest\"," + + " mean(\"usage_steal\") AS \"cpu_steal\" FROM \"cpu\"" + + " WHERE host='$hostname' AND $timeFilter GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.telegraf, + queries: [defaultQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("CPU Usage") + .setData(qr) + .setUnit("%") + .setCustomFieldConfig("spanNulls", true) + .setCustomFieldConfig("fillOpacity", 20) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/index.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/index.tsx new file mode 100644 index 0000000000..18eb1e4f2f --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/index.tsx @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export * from "./bandwidth"; +export * from "./connections"; +export * from "./cpu"; +export * from "./load-average"; +export * from "./memory"; +export * from "./netstat"; +export * from "./read-write-time"; +export * from "./wrap-count"; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/load-average.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/load-average.tsx new file mode 100644 index 0000000000..259dd2c038 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/load-average.tsx @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getLoadAveragePanel = (): VizPanel => { + const defaultQuery = { + alias: "$col", + query: "SELECT mean(\"load1\") AS \"load1\", mean(\"load5\") AS \"load5\", mean(\"load15\") AS \"load15\" FROM \"system\"" + + " WHERE host='$hostname' AND $timeFilter GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.telegraf, + queries: [defaultQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Load Average") + .setData(qr) + .setCustomFieldConfig("fillOpacity", 20) + .setCustomFieldConfig("spanNulls", true) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/memory.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/memory.tsx new file mode 100644 index 0000000000..009fa43e6e --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/memory.tsx @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getMemoryPanel = (): VizPanel => { + const defaultQuery = { + alias: "$col", + query: "SELECT mean(\"used_percent\") AS \"mem_used\" FROM \"mem\" WHERE host='$hostname' AND $timeFilter" + + " GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.telegraf, + queries: [defaultQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Memory Usage") + .setData(qr) + .setCustomFieldConfig("spanNulls", true) + .setCustomFieldConfig("fillOpacity", 20) + .setUnit("%") + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/netstat.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/netstat.tsx new file mode 100644 index 0000000000..3e92e4aa72 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/netstat.tsx @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneObject, SceneQueryRunner } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getNetstatPanel = (): SceneObject => { + const defaultQuery = { + alias: "$col", + query: "SELECT mean(\"tcp_close\") AS \"tcp_close\", mean(\"tcp_close_wait\") AS \"tcp_close_wait\"," + + " mean(\"tcp_established\") AS \"tcp_established\", mean(\"tcp_time_wait\") AS \"tcp_time_wait\"," + + " mean(\"tcp_closing\") AS \"tcp_closing\", mean(\"tcp_fin_wait1\") AS \"tcp_fin_wait1\"," + + " mean(\"tcp_fin_wait2\") AS \"tcp_fin_wait2\", mean(\"tcp_last_ack\") AS \"tcp_last_ack\"," + + " mean(\"tcp_syn_recv\") AS \"tcp_syn_recv\", mean(\"tcp_syn_sent\") AS \"tcp_syn_sent\" " + + " FROM \"netstat\" WHERE host='$hostname' AND $timeFilter GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.telegraf, + queries: [defaultQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Netstat") + .setData(qr) + .setCustomFieldConfig("spanNulls", true) + .setCustomFieldConfig("fillOpacity", 20) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/read-write-time.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/read-write-time.tsx new file mode 100644 index 0000000000..e4d45a485e --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/read-write-time.tsx @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getReadWriteTimePanel = (): VizPanel => { + const defaultQueries = [ + { + alias: "$col", + query: "SELECT non_negative_derivative(sum(\"read_time\"), 10s) AS \"read_time\" FROM \"diskio\" " + + " WHERE host='$hostname' AND $timeFilter GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }, + { + alias: "$col", + query: "SELECT non_negative_derivative(sum(\"write_time\"), 10s) AS \"write_time\" FROM \"diskio\" " + + " WHERE host='$hostname' AND $timeFilter GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "B", + resultFormat: "time_series", + }, + ]; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.telegraf, + queries: [...defaultQueries], + }); + + return PanelBuilders.timeseries() + .setTitle("Read/Write Time") + .setData(qr) + .setCustomFieldConfig("spanNulls", true) + .setCustomFieldConfig("fillOpacity", 20) + .setUnit("ns") + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/wrap-count.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/wrap-count.tsx new file mode 100644 index 0000000000..cce17f64d0 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/panels/wrap-count.tsx @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PanelBuilders, SceneQueryRunner, VizPanel } from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +export const getWrapCountPanel = (): VizPanel => { + const defaultQuery = { + alias: "$col", + query: "SELECT mean(\"vol1_wrap_count\") AS \"vol1\", mean(\"vol2_wrap_count\") AS \"vol2\" " + + "FROM \"monthly\".\"wrap_count.1min\" WHERE hostname='$hostname' AND $timeFilter GROUP BY time($interval) fill(null)", + rawQuery: true, + refId: "A", + resultFormat: "time_series", + }; + + const qr = new SceneQueryRunner({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + queries: [defaultQuery], + }); + + return PanelBuilders.timeseries() + .setTitle("Wrap Count") + .setData(qr) + .setCustomFieldConfig("spanNulls", true) + .setCustomFieldConfig("fillOpacity", 20) + .build(); +}; diff --git a/traffic_stats/trafficcontrol-scenes/src/pages/Server/scene.tsx b/traffic_stats/trafficcontrol-scenes/src/pages/Server/scene.tsx new file mode 100644 index 0000000000..a4716ede75 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/pages/Server/scene.tsx @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + EmbeddedScene, + QueryVariable, + SceneControlsSpacer, + SceneFlexItem, + SceneFlexLayout, + SceneRefreshPicker, + SceneTimePicker, + SceneTimeRange, + SceneVariableSet, + VariableValueSelectors, +} from "@grafana/scenes"; +import { INFLUXDB_DATASOURCES_REF } from "const"; + +import { + getBandwidthPanel, + getConnectionsPanel, + getCPUPanel, + getLoadAveragePanel, + getMemoryPanel, + getNetstatPanel, + getReadWriteTimePanel, + getWrapCountPanel, +} from "./panels"; + +/** + * Returns an EmbeddedScene with a specific time range and variables, consisting of multiple + * SceneFlexLayout and SceneFlexItem components for displaying various panels and controls. + * + * @returns The EmbeddedScene with the specified time range, variables, body, and controls. + */ +export function getServerScene(): EmbeddedScene { + const timeRange = new SceneTimeRange({ + from: "now-6h", + to: "now", + }); + + const hostname = new QueryVariable({ + datasource: INFLUXDB_DATASOURCES_REF.cacheStats, + name: "hostname", + query: 'SHOW TAG VALUES ON "cache_stats" FROM "monthly"."bandwidth" with key = "hostname"', + }); + + return new EmbeddedScene({ + $timeRange: timeRange, + $variables: new SceneVariableSet({ + variables: [hostname], + }), + body: new SceneFlexLayout({ + children: [ + new SceneFlexItem({ + body: getBandwidthPanel(), + height: 250, + }), + new SceneFlexItem({ + body: getConnectionsPanel(), + height: 250, + }), + new SceneFlexLayout({ + children: [ + new SceneFlexItem({ + body: getCPUPanel(), + width: "50%", + }), + new SceneFlexItem({ + body: getMemoryPanel(), + width: "50%", + }), + ], + direction: "row", + height: 250, + }), + new SceneFlexLayout({ + children: [ + new SceneFlexItem({ + body: getLoadAveragePanel(), + width: "50%", + }), + new SceneFlexItem({ + body: getReadWriteTimePanel(), + width: "50%", + }), + ], + direction: "row", + height: 250, + }), + new SceneFlexLayout({ + children: [ + new SceneFlexItem({ + body: getWrapCountPanel(), + width: "50%", + }), + new SceneFlexItem({ + body: getNetstatPanel(), + width: "50%", + }), + ], + direction: "row", + height: 250, + }), + ], + direction: "column", + }), + controls: [ + new VariableValueSelectors({}), + new SceneControlsSpacer(), + new SceneTimePicker({isOnCanvas: true}), + new SceneRefreshPicker({ + intervals: ["5s", "1m", "1h"], + isOnCanvas: true, + }), + ], + }); +} diff --git a/traffic_stats/trafficcontrol-scenes/src/plugin.json b/traffic_stats/trafficcontrol-scenes/src/plugin.json new file mode 100644 index 0000000000..792c45473b --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/plugin.json @@ -0,0 +1,53 @@ +{ + "$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json", + "type": "app", + "name": "TrafficControl Grafana Scenes", + "id": "trafficcontrol-scenes-app", + "info": { + "keywords": [ + "trafficcontrol", + "app" + ], + "description": "Visualize Traffic Stats", + "author": { + "name": "ntheanh201" + }, + "logos": { + "small": "https://raw.githubusercontent.com/apache/trafficcontrol/master/misc/logos/ATC-SVG.svg", + "large": "https://raw.githubusercontent.com/apache/trafficcontrol/master/misc/logos/ATC-SVG.svg" + }, + "screenshots": [], + "version": "%VERSION%", + "updated": "%TODAY%" + }, + "includes": [ + { + "type": "page", + "name": "Cache Group", + "path": "/a/%PLUGIN_ID%/cache-group", + "role": "Admin", + "addToNav": true, + "defaultNav": false + }, + { + "type": "page", + "name": "Delivery Service", + "path": "/a/%PLUGIN_ID%/delivery-service", + "role": "Admin", + "addToNav": true, + "defaultNav": false + }, + { + "type": "page", + "name": "Server", + "path": "/a/%PLUGIN_ID%/server", + "role": "Admin", + "addToNav": true, + "defaultNav": false + } + ], + "dependencies": { + "grafanaDependency": ">=10.0.3", + "plugins": [] + } +} diff --git a/traffic_stats/trafficcontrol-scenes/src/utils/utils.plugin.ts b/traffic_stats/trafficcontrol-scenes/src/utils/utils.plugin.ts new file mode 100644 index 0000000000..de851338a9 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/utils/utils.plugin.ts @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AppRootProps } from "@grafana/data"; +import React from "react"; + +// This is used to be able to retrieve the root plugin props anywhere inside the app. +export const PluginPropsContext = React.createContext(null); diff --git a/traffic_stats/trafficcontrol-scenes/src/utils/utils.routing.ts b/traffic_stats/trafficcontrol-scenes/src/utils/utils.routing.ts new file mode 100644 index 0000000000..fa740d0646 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/src/utils/utils.routing.ts @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PLUGIN_BASE_URL } from "const"; + +/** + * Prefixes the route with the base URL of the plugin + * @param route - The route to be prefixed + * @returns The prefixed route + */ +export function prefixRoute(route: string): string { + return `${PLUGIN_BASE_URL}/${route}`; +} diff --git a/traffic_stats/trafficcontrol-scenes/tsconfig.json b/traffic_stats/trafficcontrol-scenes/tsconfig.json new file mode 100644 index 0000000000..128a1dbe13 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/tsconfig.json @@ -0,0 +1,40 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "baseUrl": "./src", + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "importHelpers": true, + "module": "es2020", + "moduleResolution": "node", + "noImplicitReturns": true, + "noImplicitOverride": false, + "esModuleInterop": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "./dist", + "strict": true, + "target": "ES2022", + "lib": [ + "es2020", + "dom" + ], + "useDefineForClassFields": false, + "resolveJsonModule": true, + }, + "ts-node": { + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "esModuleInterop": true + }, + "transpileOnly": true + }, + "include": [ + "./src", + "./types" + ], + "extends": "@grafana/tsconfig" +} diff --git a/traffic_stats/trafficcontrol-scenes/webpack/constants.ts b/traffic_stats/trafficcontrol-scenes/webpack/constants.ts new file mode 100644 index 0000000000..acc65bb14d --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/webpack/constants.ts @@ -0,0 +1,16 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +export const SOURCE_DIR = "src"; +export const DIST_DIR = "dist"; diff --git a/traffic_stats/trafficcontrol-scenes/webpack/utils.ts b/traffic_stats/trafficcontrol-scenes/webpack/utils.ts new file mode 100644 index 0000000000..5affd5ffbc --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/webpack/utils.ts @@ -0,0 +1,93 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import fs from "fs"; +import os from "os"; +import path from "path"; +import process from "process"; + +import { glob } from "glob"; + +import { SOURCE_DIR } from "./constants"; + +/** + * Check if the current environment is Windows Subsystem for Linux (WSL). + * + * @returns true if the current environment is WSL, false otherwise + */ +export function isWSL(): boolean { + if (process.platform !== "linux") { + return false; + } + + if (os.release().toLowerCase().includes("microsoft")) { + return true; + } + + try { + return fs.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft"); + } catch { + return false; + } +} + +/** + * getPackageJson + * + * @returns package.json content + */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/explicit-function-return-type +export function getPackageJson() { + // eslint-disable-next-line @typescript-eslint/no-require-imports + return require(path.resolve(process.cwd(), "package.json")); +} + +/** + * Check if a README.md file exists in the SOURCE_DIR directory. + * + * @returns true if README.md exists, false otherwise + */ +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/explicit-function-return-type +export function getPluginJson() { + // eslint-disable-next-line @typescript-eslint/no-require-imports + return require(path.resolve(process.cwd(), `${SOURCE_DIR}/plugin.json`)); +} + +// Support bundling nested plugins by finding all plugin.json files in src directory +// then checking for a sibling module.[jt]sx? file. +/** + * Asynchronously retrieves entries for plugins. + * + * @returns a Promise that resolves to a record of plugin entries + */ +export async function getEntries(): Promise> { + const pluginsJson = await glob("**/src/**/plugin.json", { absolute: true }); + + const plugins = await Promise.all( + pluginsJson.map(async (pluginJson) => { + const folder = path.dirname(pluginJson); + return glob(`${folder}/module.{ts,tsx,js,jsx}`, { absolute: true }); + }) + ); + + return plugins.reduce((result, modules) => modules.reduce((result, module) => { + const pluginPath = path.dirname(module); + const pluginName = path.relative(process.cwd(), pluginPath).replace(/src\/?/i, ""); + const entryName = pluginName === "" ? "module" : `${pluginName}/module`; + + // @ts-ignore + result[entryName] = module; + return result; + }, result), {}); +} diff --git a/traffic_stats/trafficcontrol-scenes/webpack/webpack.config.ts b/traffic_stats/trafficcontrol-scenes/webpack/webpack.config.ts new file mode 100644 index 0000000000..cde8572087 --- /dev/null +++ b/traffic_stats/trafficcontrol-scenes/webpack/webpack.config.ts @@ -0,0 +1,231 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from "path"; + +import CopyWebpackPlugin from "copy-webpack-plugin"; +import ESLintPlugin from "eslint-webpack-plugin"; +import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; +import ReplaceInFileWebpackPlugin from "replace-in-file-webpack-plugin"; +import { Configuration } from "webpack"; +import LiveReloadPlugin from "webpack-livereload-plugin"; + +import { DIST_DIR, SOURCE_DIR } from "./constants"; +import { getEntries, getPackageJson, getPluginJson, isWSL } from "./utils"; + +const pluginJson = getPluginJson(); + +const config = async (env): Promise => { + const baseConfig: Configuration = { + cache: { + buildDependencies: { + config: [__filename], + }, + type: "filesystem", + }, + + context: path.join(process.cwd(), SOURCE_DIR), + + devtool: env.production ? "source-map" : "eval-source-map", + + entry: await getEntries(), + + externals: [ + "lodash", + "jquery", + "moment", + "slate", + "emotion", + "@emotion/react", + "@emotion/css", + "prismjs", + "slate-plain-serializer", + "@grafana/slate-react", + "react", + "react-dom", + "react-redux", + "redux", + "rxjs", + "react-router", + "react-router-dom", + "d3", + "angular", + "@grafana/ui", + "@grafana/runtime", + "@grafana/data", + + // Mark legacy SDK imports as external if their name starts with the "grafana/" prefix + ({request}, callback) => { + const prefix = "grafana/"; + const hasPrefix = (request) => request.indexOf(prefix) === 0; + const stripPrefix = (request) => request.substr(prefix.length); + + if (hasPrefix(request)) { + return callback(undefined, stripPrefix(request)); + } + + callback(); + }, + ], + + mode: env.production ? "production" : "development", + + module: { + rules: [ + { + exclude: /(node_modules)/, + test: /\.[tj]sx?$/, + use: { + loader: "swc-loader", + options: { + jsc: { + baseUrl: path.resolve(__dirname, "src"), + loose: false, + parser: { + decorators: false, + dynamicImport: true, + syntax: "typescript", + tsx: true, + }, + target: "es2015", + }, + }, + }, + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + }, + { + test: /\.s[ac]ss$/, + use: ["style-loader", "css-loader", "sass-loader"], + }, + { + generator: { + // Keep publicPath relative for host.com/grafana/ deployments + filename: Boolean(env.production) + ? "[hash][ext]" + : "[file]", + outputPath: "img/", + publicPath: `public/plugins/${pluginJson.id}/img/`, + }, + test: /\.(png|jpe?g|gif|svg)$/, + type: "asset/resource", + }, + { + generator: { + // Keep publicPath relative for host.com/grafana/ deployments + filename: Boolean(env.production) + ? "[hash][ext]" + : "[name][ext]", + outputPath: "fonts/", + publicPath: `public/plugins/${pluginJson.id}/fonts/`, + }, + test: /\.(woff|woff2|eot|ttf|otf)(\?v=\d+\.\d+\.\d+)?$/, + type: "asset/resource", + }, + ], + }, + + output: { + clean: { + keep: new RegExp( + "(.*?_(amd64|arm(64)?)(.exe)?|go_plugin_build_manifest)" + ), + }, + filename: "[name].js", + library: { + type: "amd", + }, + path: path.resolve(process.cwd(), DIST_DIR), + publicPath: `public/plugins/${pluginJson.id}/`, + uniqueName: pluginJson.id, + }, + + plugins: [ + new CopyWebpackPlugin({ + patterns: [ + // If src/README.md exists use it; otherwise the root README + // To `compiler.options.output` + {from: "plugin.json", to: "."}, + {from: "**/*.json", to: "."}, // TODO + {from: "**/*.svg", noErrorOnMissing: true, to: "."}, // Optional + {from: "**/*.png", noErrorOnMissing: true, to: "."}, // Optional + {from: "**/*.html", noErrorOnMissing: true, to: "."}, // Optional + {from: "img/**/*", noErrorOnMissing: true, to: "."}, // Optional + {from: "libs/**/*", noErrorOnMissing: true, to: "."}, // Optional + {from: "static/**/*", noErrorOnMissing: true, to: "."}, // Optional + { + from: "**/query_help.md", + noErrorOnMissing: true, + to: ".", + }, // Optional + ], + }), + // Replace certain template-variables in the README and plugin.json + new ReplaceInFileWebpackPlugin([ + { + dir: DIST_DIR, + files: ["plugin.json"], + rules: [ + { + replace: getPackageJson().version, + search: /\%VERSION\%/g, + }, + { + replace: new Date().toISOString().substring(0, 10), + search: /\%TODAY\%/g, + }, + { + replace: pluginJson.id, + search: /\%PLUGIN_ID\%/g, + }, + ], + }, + ]), + new ForkTsCheckerWebpackPlugin({ + async: Boolean(env.development), + issue: { + include: [{file: "**/*.{ts,tsx}"}], + }, + typescript: { + configFile: path.join(process.cwd(), "tsconfig.json"), + }, + }), + new ESLintPlugin({ + extensions: [".ts", ".tsx"], + lintDirtyModulesOnly: Boolean(env.development), // don't lint on start, only lint changed files + }), + ...(env.development ? [new LiveReloadPlugin()] : []), + ], + + resolve: { + extensions: [".js", ".jsx", ".ts", ".tsx"], + // handle resolving "rootDir" paths + modules: [path.resolve(process.cwd(), "src"), "node_modules"], + unsafeCache: true, + }, + }; + + if (isWSL()) { + baseConfig.watchOptions = { + ignored: /node_modules/, + poll: 3000, + }; + } + + return baseConfig; +}; + +export default config;