server/app/plugins/uptime.py (70 lines of code) (raw):

#!/usr/bin/env python3 # 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. """ASF Infrastructure Reporting Dashboard - Uptime Statistics Tasks""" import asyncio from ..lib import config from .. import plugins import aiohttp import aiohttp.client_exceptions import datetime import dateutil.relativedelta import functools DEFAULT_TIMESPAN_MONTHS = 13 # Show last 12 months, plus current one _stats: dict = {} def get_stats(): return _stats async def uptime_scan(months=DEFAULT_TIMESPAN_MONTHS): """Performs a full uptime scan from NodePing""" nodeping_summary_url = config.reporting.uptime["summary_url"] now = datetime.datetime.now() cutoff_date = (now - dateutil.relativedelta.relativedelta(months=months)).strftime("%Y-%m") async with aiohttp.ClientSession() as hc: try: async with hc.get(nodeping_summary_url) as req: if req.status == 200: hosts_json = await req.json() tmpstats = {} for host_entry in hosts_json.values(): uuid = host_entry["uuid"] host_stats = { "uuid": uuid, "label": host_entry["label"], "uptime_monthly": {}, "uptime_average": 100.0, "uptime_past_week": 100.0, } # Monthly stats per host host_url = config.reporting.uptime["host_url"].format(uuid=uuid) async with hc.get(host_url, params={"format": "json"}) as hreq: if req.status == 200: host_data = await hreq.json() uptimes = [] for month in host_data: mid = month["id"] if mid > cutoff_date and mid != "total": uptime_val = month["uptime"] if uptime_val != "-": host_stats["uptime_monthly"][mid] = uptime_val uptimes.append(uptime_val) host_stats["uptime_average"] = ( functools.reduce(lambda x, y: x + y, uptimes) / float(len(uptimes)) if uptimes else 100.0 ) # Last week's stats per host weekly_url = config.reporting.uptime["results_url"].format(uuid=uuid) async with hc.get(weekly_url, params={"format": "json", "span": 168, "limit": 20000}) as wreq: if wreq.status == 200: weekly_json = await wreq.json() checks_done = len(weekly_json) checks_failed = len([x for x in weekly_json if x["su"] is False]) weekly_uptime = 100.0 if checks_done: weekly_uptime -= float((checks_failed / checks_done) * 100) host_stats["uptime_past_week"] = weekly_uptime tmpstats[uuid] = host_stats _stats.update(tmpstats) _stats.clear() _stats.update(tmpstats) except aiohttp.client_exceptions.ClientError as e: # Request went awry?? print(f"Connection to {nodeping_summary_url} failed: {e}") print("Retrying later..") async def scan_loop(): while True: await uptime_scan() await asyncio.sleep(3600) plugins.root.register(scan_loop, slug="uptime", title="Uptime Statistics", icon="bi-router-fill")