From 87c3ba8faab246b4f977b2925123ccf47a44af9c Mon Sep 17 00:00:00 2001 From: FauFra Date: Thu, 27 Oct 2022 23:28:21 +0200 Subject: [PATCH] Added support to watchtower statistics --- public/locales/en/common.json | 5 +++ src/widgets/components.js | 1 + src/widgets/watchtower/component.jsx | 36 +++++++++++++++++ src/widgets/watchtower/proxy.js | 58 ++++++++++++++++++++++++++++ src/widgets/watchtower/widget.js | 14 +++++++ src/widgets/widgets.js | 2 + 6 files changed, 116 insertions(+) create mode 100644 src/widgets/watchtower/component.jsx create mode 100644 src/widgets/watchtower/proxy.js create mode 100644 src/widgets/watchtower/widget.js diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 62ef2102b37..39357f92fdf 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -293,6 +293,11 @@ "child_bridges": "Child Bridges", "child_bridges_status": "{{ok}}/{{total}}" }, + "watchtower":{ + "containers_scanned": "Scanned", + "containers_updated": "Updatded", + "containers_failed": "Failed" + }, "autobrr": { "approvedPushes": "Approved", "rejectedPushes": "Rejected", diff --git a/src/widgets/components.js b/src/widgets/components.js index f46808a50de..c2b50189010 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -37,6 +37,7 @@ const components = { traefik: dynamic(() => import("./traefik/component")), transmission: dynamic(() => import("./transmission/component")), unifi: dynamic(() => import("./unifi/component")), + watchtower: dynamic(() => import("./watchtower/component")), }; export default components; diff --git a/src/widgets/watchtower/component.jsx b/src/widgets/watchtower/component.jsx new file mode 100644 index 00000000000..68c5531f6f0 --- /dev/null +++ b/src/widgets/watchtower/component.jsx @@ -0,0 +1,36 @@ +import { useTranslation } from "next-i18next"; + +import Container from "components/services/widget/container"; +import Block from "components/services/widget/block"; +import useWidgetAPI from "utils/proxy/use-widget-api"; + + +export default function Component({ service }) { + const { t } = useTranslation(); + + const { widget } = service; + + const { data: watchData, error: watchError } = useWidgetAPI(widget, "watchtower"); + + if (watchError || !watchData) { + return ; + } + + if (!watchData) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} diff --git a/src/widgets/watchtower/proxy.js b/src/widgets/watchtower/proxy.js new file mode 100644 index 00000000000..4bb98504336 --- /dev/null +++ b/src/widgets/watchtower/proxy.js @@ -0,0 +1,58 @@ +import cache from "memory-cache"; + +import { httpProxy } from "utils/proxy/http"; +import { formatApiCall } from "utils/proxy/api-helpers"; +import getServiceWidget from "utils/config/service-helpers"; +import createLogger from "utils/logger"; +import widgets from "widgets/widgets"; + +const proxyName = "watchtowerProxyHandler"; +const headerCacheKey = `${proxyName}__headers`; +const logger = createLogger(proxyName); + +export default async function watchtowerProxyHandler(req, res) { + const { group, service, endpoint } = req.query; + + if (!group || !service) { + logger.debug("Invalid or missing service '%s' or group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + const widget = await getServiceWidget(group, service); + + if (!widget) { + logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); + } + + let headers = cache.get(headerCacheKey); + if (!headers) { + headers = { + "Authorization": `Bearer ${widget.key}`, + } + cache.put(headerCacheKey, headers); + } + + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + + const method = "GET" + const [status, contentType, data] = await httpProxy(url, { + method, + headers, + }); + + const cleanData = data.toString().split("\n").filter(s => s.startsWith("watchtower")) + const jsonRes={} + + cleanData.map(e => e.split(" ")).forEach(strArray => { + const [key, value] = strArray + jsonRes[key] = value + }) + + if (status !== 200) { + logger.error("Error getting data from WatchTower: %d. Data: %s", status, data); + } + + if (contentType) res.setHeader("Content-Type", contentType); + return res.status(status).send(jsonRes); +} diff --git a/src/widgets/watchtower/widget.js b/src/widgets/watchtower/widget.js new file mode 100644 index 00000000000..734c90ebe1c --- /dev/null +++ b/src/widgets/watchtower/widget.js @@ -0,0 +1,14 @@ +import watchtowerProxyHandler from "./proxy"; + +const widget = { + api: "{url}/{endpoint}", + proxyHandler: watchtowerProxyHandler, + + mappings: { + "watchtower": { + endpoint: "v1/metrics", + }, + }, +}; + +export default widget; \ No newline at end of file diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 577243a7ace..74f426b36a3 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -32,6 +32,7 @@ import tautulli from "./tautulli/widget"; import traefik from "./traefik/widget"; import transmission from "./transmission/widget"; import unifi from "./unifi/widget"; +import watchtower from './watchtower/widget' const widgets = { adguard, @@ -70,6 +71,7 @@ const widgets = { transmission, unifi, unifi_console: unifi, + watchtower, }; export default widgets;