blob: bdf9f490a067b840e1b340d34309a2d7a0cf6c9c [file] [log] [blame]
#!/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")