uptime-kuma-api/uptime_kuma_api/api.py

1003 lines
30 KiB
Python
Raw Normal View History

2022-07-05 22:12:37 +02:00
import json
2022-07-02 16:00:54 +02:00
import time
import string
import random
2022-07-02 16:00:54 +02:00
2022-08-26 14:04:43 +02:00
import requests
2022-07-02 16:00:54 +02:00
import socketio
2022-09-07 13:03:10 +02:00
from packaging.version import parse as parse_version
2022-07-02 16:00:54 +02:00
from . import AuthMethod
from . import MonitorType
2022-09-07 13:03:10 +02:00
from . import NotificationType, notification_provider_options, notification_provider_conditions
2022-07-02 20:26:18 +02:00
from . import ProxyProtocol
2022-07-02 21:29:16 +02:00
from . import IncidentStyle
2022-09-07 13:03:10 +02:00
from . import DockerType
2022-08-05 15:52:19 +02:00
from . import Event
from . import UptimeKumaException
2022-07-05 22:12:37 +02:00
2022-08-03 11:56:02 +02:00
def int_to_bool(data, keys):
2022-07-05 22:12:37 +02:00
if type(data) == list:
for d in data:
int_to_bool(d, keys)
else:
for key in keys:
if key in data:
data[key] = True if data[key] == 1 else False
def gen_secret(length: int) -> str:
chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
return ''.join(random.choice(chars) for _ in range(length))
def _convert_monitor_return(monitor):
if type(monitor["notificationIDList"]) == dict:
monitor["notificationIDList"] = [int(i) for i in monitor["notificationIDList"].keys()]
def _convert_monitor_input(kwargs):
2022-09-06 13:41:51 +02:00
if not kwargs["accepted_statuscodes"]:
kwargs["accepted_statuscodes"] = ["200-299"]
dict_notification_ids = {}
if kwargs["notificationIDList"]:
for notification_id in kwargs["notificationIDList"]:
dict_notification_ids[notification_id] = True
kwargs["notificationIDList"] = dict_notification_ids
2022-07-05 22:12:37 +02:00
2022-09-07 13:03:10 +02:00
if not kwargs["databaseConnectionString"]:
if kwargs["type"] == MonitorType.SQLSERVER:
kwargs["databaseConnectionString"] = "Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>"
elif kwargs["type"] == MonitorType.POSTGRES:
kwargs["databaseConnectionString"] = "postgres://username:password@host:port/database"
if kwargs["type"] == MonitorType.PUSH and not kwargs.get("pushToken"):
kwargs["pushToken"] = gen_secret(10)
2022-07-05 22:12:37 +02:00
2022-08-02 11:58:49 +02:00
def _build_notification_data(
name: str,
2022-08-03 11:56:02 +02:00
type: NotificationType,
isDefault: bool = False,
applyExisting: bool = False,
2022-08-02 11:58:49 +02:00
**kwargs
):
allowed_kwargs = []
for keys in notification_provider_options.values():
allowed_kwargs.extend(keys)
for key in kwargs.keys():
if key not in allowed_kwargs:
raise TypeError(f"unknown argument '{key}'")
data = {
2022-07-05 22:12:37 +02:00
"name": name,
2022-08-03 11:56:02 +02:00
"type": type,
"isDefault": isDefault,
"applyExisting": applyExisting,
2022-07-05 22:12:37 +02:00
**kwargs
}
return data
2022-07-05 22:12:37 +02:00
def _build_proxy_data(
protocol: ProxyProtocol,
host: str,
port: str,
auth: bool = False,
username: str = None,
password: str = None,
active: bool = True,
default: bool = False,
2022-08-03 11:56:02 +02:00
applyExisting: bool = False,
2022-07-05 22:12:37 +02:00
):
data = {
2022-07-05 22:12:37 +02:00
"protocol": protocol,
"host": host,
"port": port,
"auth": auth,
"username": username,
"password": password,
"active": active,
"default": default,
2022-08-03 11:56:02 +02:00
"applyExisting": applyExisting
2022-07-05 22:12:37 +02:00
}
return data
2022-07-02 16:00:54 +02:00
2022-07-06 21:29:40 +02:00
def _build_status_page_data(
slug: str,
# config
2022-08-03 11:56:02 +02:00
id: int,
2022-07-06 21:29:40 +02:00
title: str,
description: str = None,
theme: str = "light",
2022-07-06 21:29:40 +02:00
published: bool = True,
2022-08-03 11:56:02 +02:00
showTags: bool = False,
domainNameList: list = None,
customCSS: str = "",
footerText: str = None,
showPoweredBy: bool = True,
2022-07-06 21:29:40 +02:00
2022-08-03 11:56:02 +02:00
icon: str = "/icon.svg",
2022-08-26 14:04:43 +02:00
publicGroupList: list = None
2022-07-06 21:29:40 +02:00
):
if theme not in ["light", "dark"]:
raise ValueError
2022-08-03 11:56:02 +02:00
if not domainNameList:
domainNameList = []
2022-08-26 14:04:43 +02:00
if not publicGroupList:
publicGroupList = []
2022-07-06 21:29:40 +02:00
config = {
2022-08-03 11:56:02 +02:00
"id": id,
2022-07-06 21:29:40 +02:00
"slug": slug,
"title": title,
"description": description,
2022-08-03 11:56:02 +02:00
"icon": icon,
"theme": theme,
2022-07-06 21:29:40 +02:00
"published": published,
2022-08-03 11:56:02 +02:00
"showTags": showTags,
"domainNameList": domainNameList,
"customCSS": customCSS,
"footerText": footerText,
"showPoweredBy": showPoweredBy
2022-07-06 21:29:40 +02:00
}
2022-08-26 14:04:43 +02:00
return slug, config, icon, publicGroupList
2022-07-06 21:29:40 +02:00
def _convert_docker_host_input(kwargs):
2022-09-07 13:03:10 +02:00
if not kwargs["dockerDaemon"]:
if kwargs["dockerType"] == DockerType.SOCKET:
kwargs["dockerDaemon"] = "/var/run/docker.sock"
elif kwargs["dockerType"] == DockerType.TCP:
kwargs["dockerDaemon"] = "tcp://localhost:2375"
def _build_docker_host_data(
name: str,
dockerType: DockerType,
dockerDaemon: str = None
):
data = {
"name": name,
"dockerType": dockerType,
"dockerDaemon": dockerDaemon
}
return data
2022-08-03 11:56:02 +02:00
def _check_missing_arguments(required_params, kwargs):
2022-07-09 22:15:41 +02:00
missing_arguments = []
for required_param in required_params:
2022-08-03 11:56:02 +02:00
if kwargs.get(required_param) is None:
2022-07-09 22:15:41 +02:00
missing_arguments.append(required_param)
if missing_arguments:
missing_arguments_str = ", ".join([f"'{i}'" for i in missing_arguments])
raise TypeError(f"missing {len(missing_arguments)} required argument: {missing_arguments_str}")
2022-08-03 11:56:02 +02:00
def _check_argument_conditions(valid_params, kwargs):
2022-07-10 18:07:11 +02:00
for valid_param in valid_params:
2022-08-03 11:56:02 +02:00
if valid_param in kwargs:
value = kwargs[valid_param]
2022-07-10 18:07:11 +02:00
conditions = valid_params[valid_param]
min_ = conditions.get("min")
max_ = conditions.get("max")
if min_ is not None and value < min_:
raise ValueError(f"the value of {valid_param} must not be less than {min_}")
if max_ is not None and value > max_:
raise ValueError(f"the value of {valid_param} must not be larger than {max_}")
def _check_arguments_monitor(kwargs):
required_args = [
2022-08-03 11:56:02 +02:00
"type",
2022-07-09 22:15:41 +02:00
"name",
2022-08-03 11:56:02 +02:00
"interval",
"maxretries",
"retryInterval"
2022-07-09 22:15:41 +02:00
]
2022-08-03 11:56:02 +02:00
_check_missing_arguments(required_args, kwargs)
2022-07-09 22:15:41 +02:00
2022-07-10 18:07:11 +02:00
required_args_by_type = {
2022-08-03 11:56:02 +02:00
MonitorType.HTTP: ["url", "maxredirects"],
2022-07-09 22:15:41 +02:00
MonitorType.PORT: ["hostname", "port"],
MonitorType.PING: ["hostname"],
2022-08-03 11:56:02 +02:00
MonitorType.KEYWORD: ["url", "keyword", "maxredirects"],
2022-07-09 22:15:41 +02:00
MonitorType.DNS: ["hostname", "dns_resolve_server", "port"],
MonitorType.PUSH: [],
MonitorType.STEAM: ["hostname", "port"],
2022-08-03 11:56:02 +02:00
MonitorType.MQTT: ["hostname", "port", "mqttTopic"],
2022-07-09 22:15:41 +02:00
MonitorType.SQLSERVER: [],
2022-09-07 13:03:10 +02:00
MonitorType.POSTGRES: [],
MonitorType.DOCKER: ["docker_container", "docker_host"],
MonitorType.RADIUS: ["radiusUsername", "radiusPassword", "radiusSecret", "radiusCalledStationId", "radiusCallingStationId"]
2022-07-09 22:15:41 +02:00
}
2022-08-03 11:56:02 +02:00
type_ = kwargs["type"]
2022-07-10 18:07:11 +02:00
required_args = required_args_by_type[type_]
2022-08-03 11:56:02 +02:00
_check_missing_arguments(required_args, kwargs)
2022-07-10 18:07:11 +02:00
conditions = {
2022-08-03 11:56:02 +02:00
"interval": {
2022-07-10 18:07:11 +02:00
"min": 20
},
2022-08-03 11:56:02 +02:00
"maxretries": {
2022-07-10 18:07:11 +02:00
"min": 0
},
2022-08-03 11:56:02 +02:00
"retryInterval": {
2022-07-10 18:07:11 +02:00
"min": 20
},
2022-08-03 11:56:02 +02:00
"maxredirects": {
2022-07-10 18:07:11 +02:00
"min": 0
},
"port": {
"min": 0,
"max": 65535
}
}
2022-08-03 11:56:02 +02:00
_check_argument_conditions(conditions, kwargs)
2022-07-10 18:07:11 +02:00
def _check_arguments_notification(kwargs):
2022-08-03 11:56:02 +02:00
required_args = ["type", "name"]
_check_missing_arguments(required_args, kwargs)
2022-07-10 18:07:11 +02:00
2022-08-03 11:56:02 +02:00
type_ = kwargs["type"]
required_args = notification_provider_options[type_]
_check_missing_arguments(required_args, kwargs)
2022-09-07 13:03:10 +02:00
_check_argument_conditions(notification_provider_conditions, kwargs)
2022-07-09 22:15:41 +02:00
2022-07-10 18:07:11 +02:00
def _check_arguments_proxy(kwargs):
required_args = ["protocol", "host", "port"]
2022-08-02 23:47:56 +02:00
if kwargs.get("auth"):
2022-07-10 18:07:11 +02:00
required_args.extend(["username", "password"])
2022-08-03 11:56:02 +02:00
_check_missing_arguments(required_args, kwargs)
2022-07-10 18:07:11 +02:00
conditions = {
"port": {
"min": 0,
"max": 65535
}
}
2022-08-03 11:56:02 +02:00
_check_argument_conditions(conditions, kwargs)
2022-07-09 22:15:41 +02:00
2022-07-02 16:00:54 +02:00
class UptimeKumaApi(object):
def __init__(self, url):
self.url = url
2022-07-02 16:00:54 +02:00
self.sio = socketio.Client()
2022-08-02 21:32:28 +02:00
self._event_data: dict = {
2022-08-05 15:52:19 +02:00
Event.MONITOR_LIST: None,
Event.NOTIFICATION_LIST: None,
Event.PROXY_LIST: None,
Event.STATUS_PAGE_LIST: None,
Event.HEARTBEAT_LIST: None,
Event.IMPORTANT_HEARTBEAT_LIST: None,
Event.AVG_PING: None,
Event.UPTIME: None,
Event.HEARTBEAT: None,
Event.INFO: None,
2022-09-07 13:03:10 +02:00
Event.CERT_INFO: None,
Event.DOCKER_HOST_LIST: None,
Event.AUTO_LOGIN: None
2022-07-02 16:00:54 +02:00
}
2022-08-05 15:52:19 +02:00
self.sio.on(Event.CONNECT, self._event_connect)
self.sio.on(Event.DISCONNECT, self._event_disconnect)
self.sio.on(Event.MONITOR_LIST, self._event_monitor_list)
self.sio.on(Event.NOTIFICATION_LIST, self._event_notification_list)
self.sio.on(Event.PROXY_LIST, self._event_proxy_list)
self.sio.on(Event.STATUS_PAGE_LIST, self._event_status_page_list)
self.sio.on(Event.HEARTBEAT_LIST, self._event_heartbeat_list)
self.sio.on(Event.IMPORTANT_HEARTBEAT_LIST, self._event_important_heartbeat_list)
self.sio.on(Event.AVG_PING, self._event_avg_ping)
self.sio.on(Event.UPTIME, self._event_uptime)
self.sio.on(Event.HEARTBEAT, self._event_heartbeat)
self.sio.on(Event.INFO, self._event_info)
self.sio.on(Event.CERT_INFO, self._event_cert_info)
2022-09-07 13:03:10 +02:00
self.sio.on(Event.DOCKER_HOST_LIST, self._event_docker_host_list)
self.sio.on(Event.AUTO_LOGIN, self._event_auto_login)
2022-07-02 16:00:54 +02:00
self.connect()
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def _get_event_data(self, event):
2022-08-05 15:52:19 +02:00
monitor_events = [Event.AVG_PING, Event.UPTIME, Event.HEARTBEAT_LIST, Event.IMPORTANT_HEARTBEAT_LIST, Event.CERT_INFO, Event.HEARTBEAT]
2022-07-05 22:12:37 +02:00
while self._event_data[event] is None:
# do not wait for events that are not sent
2022-08-05 15:52:19 +02:00
if self._event_data[Event.MONITOR_LIST] == {} and event in monitor_events:
return []
2022-07-02 16:00:54 +02:00
time.sleep(0.01)
time.sleep(0.05) # wait for multiple messages
2022-07-05 22:12:37 +02:00
return self._event_data[event]
2022-07-02 16:00:54 +02:00
def _call(self, event, data=None):
r = self.sio.call(event, data)
if type(r) == dict and "ok" in r:
if not r["ok"]:
raise UptimeKumaException(r["msg"])
r.pop("ok")
return r
2022-07-02 16:00:54 +02:00
# event handlers
2022-07-05 22:12:37 +02:00
def _event_connect(self):
2022-07-02 16:00:54 +02:00
pass
2022-07-05 22:12:37 +02:00
def _event_disconnect(self):
2022-07-02 16:00:54 +02:00
pass
2022-07-05 22:12:37 +02:00
def _event_monitor_list(self, data):
2022-08-05 15:52:19 +02:00
self._event_data[Event.MONITOR_LIST] = data
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def _event_notification_list(self, data):
2022-08-05 15:52:19 +02:00
self._event_data[Event.NOTIFICATION_LIST] = data
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def _event_proxy_list(self, data):
2022-08-05 15:52:19 +02:00
self._event_data[Event.PROXY_LIST] = data
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def _event_status_page_list(self, data):
2022-08-05 15:52:19 +02:00
self._event_data[Event.STATUS_PAGE_LIST] = data
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def _event_heartbeat_list(self, id_, data, bool_):
2022-08-05 15:52:19 +02:00
if self._event_data[Event.HEARTBEAT_LIST] is None:
self._event_data[Event.HEARTBEAT_LIST] = []
self._event_data[Event.HEARTBEAT_LIST].append({
2022-07-02 16:00:54 +02:00
"id": id_,
"data": data,
"bool": bool_,
})
2022-07-05 22:12:37 +02:00
def _event_important_heartbeat_list(self, id_, data, bool_):
2022-08-05 15:52:19 +02:00
if self._event_data[Event.IMPORTANT_HEARTBEAT_LIST] is None:
self._event_data[Event.IMPORTANT_HEARTBEAT_LIST] = []
self._event_data[Event.IMPORTANT_HEARTBEAT_LIST].append({
2022-07-02 16:00:54 +02:00
"id": id_,
"data": data,
"bool": bool_,
})
2022-07-05 22:12:37 +02:00
def _event_avg_ping(self, id_, data):
2022-08-05 15:52:19 +02:00
if self._event_data[Event.AVG_PING] is None:
self._event_data[Event.AVG_PING] = []
self._event_data[Event.AVG_PING].append({
2022-07-02 16:00:54 +02:00
"id": id_,
"data": data,
})
2022-07-05 22:12:37 +02:00
def _event_uptime(self, id_, hours_24, days_30):
2022-08-05 15:52:19 +02:00
if self._event_data[Event.UPTIME] is None:
self._event_data[Event.UPTIME] = []
self._event_data[Event.UPTIME].append({
2022-07-02 16:00:54 +02:00
"id": id_,
"hours_24": hours_24,
"days_30": days_30,
})
2022-07-05 22:12:37 +02:00
def _event_heartbeat(self, data):
2022-08-05 15:52:19 +02:00
if self._event_data[Event.HEARTBEAT] is None:
self._event_data[Event.HEARTBEAT] = []
self._event_data[Event.HEARTBEAT].append(data)
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def _event_info(self, data):
2022-08-05 15:52:19 +02:00
self._event_data[Event.INFO] = data
2022-07-02 16:00:54 +02:00
def _event_cert_info(self, id_, data):
2022-08-05 15:52:19 +02:00
if self._event_data[Event.CERT_INFO] is None:
self._event_data[Event.CERT_INFO] = []
self._event_data[Event.CERT_INFO].append({
"id": id_,
"data": data,
})
2022-09-07 13:03:10 +02:00
def _event_docker_host_list(self, data):
self._event_data[Event.DOCKER_HOST_LIST] = data
def _event_auto_login(self):
self._event_data[Event.AUTO_LOGIN] = True
2022-07-02 16:00:54 +02:00
# connection
def connect(self):
url = self.url.rstrip("/")
try:
self.sio.connect(f'{url}/socket.io/')
except:
print("")
2022-07-02 16:00:54 +02:00
def disconnect(self):
self.sio.disconnect()
2022-09-07 13:03:10 +02:00
# builder
@property
def version(self):
info = self.info()
return info["version"]
def _build_monitor_data(
self,
type: MonitorType,
name: str,
interval: int = 60,
retryInterval: int = 60,
resendInterval: int = 0,
maxretries: int = 0,
upsideDown: bool = False,
notificationIDList: list = None,
# HTTP, KEYWORD
url: str = None,
expiryNotification: bool = False,
ignoreTls: bool = False,
maxredirects: int = 10,
accepted_statuscodes: list = None,
proxyId: int = None,
method: str = "GET",
body: str = None,
headers: str = None,
authMethod: AuthMethod = AuthMethod.NONE,
basic_auth_user: str = None,
basic_auth_pass: str = None,
authDomain: str = None,
authWorkstation: str = None,
# KEYWORD
keyword: str = None,
# DNS, PING, STEAM, MQTT
hostname: str = None,
# DNS, STEAM, MQTT
port: int = 53,
# DNS
dns_resolve_server: str = "1.1.1.1",
dns_resolve_type: str = "A",
# MQTT
mqttUsername: str = None,
mqttPassword: str = None,
mqttTopic: str = None,
mqttSuccessMessage: str = None,
# SQLSERVER, POSTGRES
databaseConnectionString: str = None,
databaseQuery: str = None,
# DOCKER
docker_container: str = "",
docker_host: int = None,
# RADIUS
radiusUsername: str = None,
radiusPassword: str = None,
radiusSecret: str = None,
radiusCalledStationId: str = None,
radiusCallingStationId: str = None
):
data = {
"type": type,
"name": name,
"interval": interval,
"retryInterval": retryInterval,
"maxretries": maxretries,
"notificationIDList": notificationIDList,
"upsideDown": upsideDown,
}
if parse_version(self.version) >= parse_version("1.18"):
data.update({
"resendInterval": resendInterval
})
if type == MonitorType.KEYWORD:
data.update({
"keyword": keyword,
})
# HTTP, KEYWORD
data.update({
"url": url,
"expiryNotification": expiryNotification,
"ignoreTls": ignoreTls,
"maxredirects": maxredirects,
"accepted_statuscodes": accepted_statuscodes,
"proxyId": proxyId,
"method": method,
"body": body,
"headers": headers,
"authMethod": authMethod,
})
if authMethod in [AuthMethod.HTTP_BASIC, AuthMethod.NTLM]:
data.update({
"basic_auth_user": basic_auth_user,
"basic_auth_pass": basic_auth_pass,
})
if authMethod == AuthMethod.NTLM:
data.update({
"authDomain": authDomain,
"authWorkstation": authWorkstation,
})
# PORT, PING, DNS, STEAM, MQTT
2022-09-07 13:03:10 +02:00
data.update({
"hostname": hostname,
})
# PORT, DNS, STEAM, MQTT
2022-09-07 13:03:10 +02:00
data.update({
"port": port,
})
# DNS
data.update({
"dns_resolve_server": dns_resolve_server,
"dns_resolve_type": dns_resolve_type,
})
# MQTT
data.update({
"mqttUsername": mqttUsername,
"mqttPassword": mqttPassword,
"mqttTopic": mqttTopic,
"mqttSuccessMessage": mqttSuccessMessage,
})
# SQLSERVER, POSTGRES
data.update({
"databaseConnectionString": databaseConnectionString
})
if type in [MonitorType.SQLSERVER, MonitorType.POSTGRES]:
data.update({
"databaseQuery": databaseQuery,
})
# DOCKER
if type == MonitorType.DOCKER:
data.update({
"docker_container": docker_container,
"docker_host": docker_host
})
# RADIUS
if type == MonitorType.RADIUS:
data.update({
"radiusUsername": radiusUsername,
"radiusPassword": radiusPassword,
"radiusSecret": radiusSecret,
"radiusCalledStationId": radiusCalledStationId,
"radiusCallingStationId": radiusCallingStationId
})
return data
2022-07-02 16:00:54 +02:00
# monitors
def get_monitors(self):
2022-08-05 15:52:19 +02:00
r = list(self._get_event_data(Event.MONITOR_LIST).values())
for monitor in r:
_convert_monitor_return(monitor)
int_to_bool(r, ["active"])
return r
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def get_monitor(self, id_: int):
r = self._call('getMonitor', id_)["monitor"]
_convert_monitor_return(r)
int_to_bool(r, ["active"])
return r
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def pause_monitor(self, id_: int):
2022-07-09 19:52:21 +02:00
return self._call('pauseMonitor', id_)
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def resume_monitor(self, id_: int):
2022-07-09 19:52:21 +02:00
return self._call('resumeMonitor', id_)
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def delete_monitor(self, id_: int):
return self._call('deleteMonitor', id_)
2022-07-02 16:00:54 +02:00
def get_monitor_beats(self, id_: int, hours: int):
r = self._call('getMonitorBeats', (id_, hours))["data"]
int_to_bool(r, ["important", "status"])
return r
2022-07-02 16:00:54 +02:00
2022-07-09 22:15:41 +02:00
def add_monitor(self, **kwargs):
2022-09-07 13:03:10 +02:00
data = self._build_monitor_data(**kwargs)
_convert_monitor_input(data)
2022-07-10 18:07:11 +02:00
_check_arguments_monitor(data)
r = self._call('add', data)
return r
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def edit_monitor(self, id_: int, **kwargs):
data = self.get_monitor(id_)
2022-07-09 19:52:21 +02:00
data.update(kwargs)
_convert_monitor_input(data)
2022-07-10 18:07:11 +02:00
_check_arguments_monitor(data)
r = self._call('editMonitor', data)
return r
2022-07-02 16:00:54 +02:00
# monitor tags
2022-07-05 22:12:37 +02:00
def add_monitor_tag(self, tag_id: int, monitor_id: int, value=""):
return self._call('addMonitorTag', (tag_id, monitor_id, value))
2022-07-02 16:00:54 +02:00
# editMonitorTag is unused in uptime-kuma
2022-07-05 22:12:37 +02:00
# def edit_monitor_tag(self, tag_id: int, monitor_id: int, value=""):
# return self._call('editMonitorTag', (tag_id, monitor_id, value))
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def delete_monitor_tag(self, tag_id: int, monitor_id: int, value=""):
return self._call('deleteMonitorTag', (tag_id, monitor_id, value))
2022-07-02 16:00:54 +02:00
# notifications
def get_notifications(self):
2022-08-05 15:52:19 +02:00
notifications = self._get_event_data(Event.NOTIFICATION_LIST)
r = []
for notification_raw in notifications:
2022-07-05 22:12:37 +02:00
notification = notification_raw.copy()
config = json.loads(notification["config"])
del notification["config"]
notification.update(config)
r.append(notification)
return r
2022-07-05 22:12:37 +02:00
def get_notification(self, id_: int):
notifications = self.get_notifications()
for notification in notifications:
if notification["id"] == id_:
return notification
raise UptimeKumaException("notification does not exist")
2022-07-02 16:00:54 +02:00
2022-07-09 22:15:41 +02:00
def test_notification(self, **kwargs):
data = _build_notification_data(**kwargs)
2022-07-10 18:07:11 +02:00
_check_arguments_notification(data)
return self._call('testNotification', data)
2022-07-02 16:00:54 +02:00
2022-07-09 22:15:41 +02:00
def add_notification(self, **kwargs):
data = _build_notification_data(**kwargs)
2022-07-10 18:07:11 +02:00
_check_arguments_notification(data)
return self._call('addNotification', (data, None))
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def edit_notification(self, id_: int, **kwargs):
notification = self.get_notification(id_)
2022-08-03 11:56:02 +02:00
# remove old notification provider options from notification object
if "type" in kwargs and kwargs["type"] != notification["type"]:
for provider in notification_provider_options:
provider_options = notification_provider_options[provider]
2022-08-03 11:56:02 +02:00
if provider != kwargs["type"]:
for option in provider_options:
if option in notification:
del notification[option]
notification.update(kwargs)
2022-07-10 18:07:11 +02:00
_check_arguments_notification(notification)
return self._call('addNotification', (notification, id_))
2022-07-02 16:00:54 +02:00
def delete_notification(self, id_: int):
return self._call('deleteNotification', id_)
2022-07-02 16:00:54 +02:00
def check_apprise(self):
return self._call('checkApprise')
2022-07-02 16:00:54 +02:00
# proxy
def get_proxies(self):
2022-08-05 15:52:19 +02:00
r = self._get_event_data(Event.PROXY_LIST)
2022-08-03 11:56:02 +02:00
int_to_bool(r, ["auth", "active", "default", "applyExisting"])
return r
2022-07-05 22:12:37 +02:00
def get_proxy(self, id_: int):
proxies = self.get_proxies()
for proxy in proxies:
if proxy["id"] == id_:
return proxy
raise UptimeKumaException("proxy does not exist")
2022-07-02 16:00:54 +02:00
2022-07-09 22:15:41 +02:00
def add_proxy(self, **kwargs):
data = _build_proxy_data(**kwargs)
2022-07-10 18:07:11 +02:00
_check_arguments_proxy(data)
return self._call('addProxy', (data, None))
2022-07-02 20:26:18 +02:00
2022-07-05 22:12:37 +02:00
def edit_proxy(self, id_: int, **kwargs):
proxy = self.get_proxy(id_)
proxy.update(kwargs)
2022-07-10 18:07:11 +02:00
_check_arguments_proxy(proxy)
return self._call('addProxy', (proxy, id_))
2022-07-02 20:26:18 +02:00
def delete_proxy(self, id_: int):
return self._call('deleteProxy', id_)
2022-07-02 20:26:18 +02:00
2022-07-02 16:00:54 +02:00
# status page
2022-07-02 20:40:14 +02:00
def get_status_pages(self):
2022-08-05 15:52:19 +02:00
r = list(self._get_event_data(Event.STATUS_PAGE_LIST).values())
return r
2022-07-02 20:40:14 +02:00
2022-07-02 21:29:16 +02:00
def get_status_page(self, slug: str):
2022-08-26 14:04:43 +02:00
r1 = self._call('getStatusPage', slug)
r2 = requests.get(f"{self.url}/api/status-page/{slug}").json()
config = r1["config"]
config.update(r2["config"])
return {
**config,
"incident": r2["incident"],
"publicGroupList": r2["publicGroupList"]
}
2022-07-06 21:29:40 +02:00
def add_status_page(self, slug: str, title: str):
return self._call('addStatusPage', (title, slug))
2022-07-05 22:12:37 +02:00
def delete_status_page(self, slug: str):
return self._call('deleteStatusPage', slug)
2022-07-05 22:12:37 +02:00
2022-07-06 21:29:40 +02:00
def save_status_page(self, slug: str, **kwargs):
status_page = self.get_status_page(slug)
2022-08-26 14:04:43 +02:00
status_page.pop("incident")
status_page.update(kwargs)
2022-07-06 21:29:40 +02:00
data = _build_status_page_data(**status_page)
return self._call('saveStatusPage', data)
2022-07-02 20:40:14 +02:00
2022-07-05 22:12:37 +02:00
def post_incident(
self,
slug: str,
title: str,
content: str,
style: IncidentStyle = IncidentStyle.PRIMARY
):
incident = {
"title": title,
"content": content,
"style": style
}
r = self._call('postIncident', (slug, incident))["incident"]
2022-07-06 21:29:40 +02:00
self.save_status_page(slug)
return r
2022-07-05 22:12:37 +02:00
def unpin_incident(self, slug: str):
r = self._call('unpinIncident', slug)
2022-07-06 21:29:40 +02:00
self.save_status_page(slug)
return r
2022-07-02 20:40:14 +02:00
2022-07-02 16:00:54 +02:00
# heartbeat
def get_heartbeats(self):
2022-08-05 15:52:19 +02:00
r = self._get_event_data(Event.HEARTBEAT_LIST)
for i in r:
int_to_bool(i["data"], ["important", "status"])
return r
2022-07-02 16:00:54 +02:00
def get_important_heartbeats(self):
2022-08-05 15:52:19 +02:00
r = self._get_event_data(Event.IMPORTANT_HEARTBEAT_LIST)
for i in r:
int_to_bool(i["data"], ["important", "status"])
return r
2022-07-02 16:00:54 +02:00
def get_heartbeat(self):
2022-08-05 15:52:19 +02:00
r = self._get_event_data(Event.HEARTBEAT)
int_to_bool(r, ["important", "status"])
return r
2022-07-02 16:00:54 +02:00
# avg ping
def avg_ping(self):
2022-08-05 15:52:19 +02:00
return self._get_event_data(Event.AVG_PING)
2022-07-02 16:00:54 +02:00
# cert info
def cert_info(self):
2022-08-05 15:52:19 +02:00
return self._get_event_data(Event.CERT_INFO)
2022-07-02 16:00:54 +02:00
# uptime
def uptime(self):
2022-08-05 15:52:19 +02:00
return self._get_event_data(Event.UPTIME)
2022-07-02 16:00:54 +02:00
# info
2022-09-07 13:03:10 +02:00
def info(self) -> dict:
2022-08-05 15:52:19 +02:00
r = self._get_event_data(Event.INFO)
return r
2022-07-02 16:00:54 +02:00
# clear
def clear_events(self, monitor_id: int):
return self._call('clearEvents', monitor_id)
2022-07-02 16:00:54 +02:00
def clear_heartbeats(self, monitor_id: int):
return self._call('clearHeartbeats', monitor_id)
2022-07-02 16:00:54 +02:00
def clear_statistics(self):
return self._call('clearStatistics')
2022-07-02 16:00:54 +02:00
# tags
def get_tags(self):
return self._call('getTags')["tags"]
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def get_tag(self, id_: int):
tags = self.get_tags()
for tag in tags:
if tag["id"] == id_:
return tag
raise UptimeKumaException("tag does not exist")
2022-07-05 22:12:37 +02:00
# not working, monitor id required?
2022-07-05 22:12:37 +02:00
# def edit_tag(self, id_: int, name: str, color: str):
# return self._call('editTag', {
2022-07-05 22:12:37 +02:00
# "id": id_,
# "name": name,
# "color": color
# })
def delete_tag(self, id_: int):
return self._call('deleteTag', id_)
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def add_tag(self, name: str, color: str):
return self._call('addTag', {
2022-07-02 16:00:54 +02:00
"name": name,
2022-07-05 22:12:37 +02:00
"color": color,
2022-07-02 16:00:54 +02:00
"new": True
})["tag"]
2022-07-02 16:00:54 +02:00
# settings
def get_settings(self):
r = self._call('getSettings')["data"]
return r
def set_settings(
self,
password: str = None, # only required if disableAuth is true
2022-07-02 16:00:54 +02:00
# about
2022-08-03 11:56:02 +02:00
checkUpdate: bool = True,
checkBeta: bool = False,
# monitor history
2022-08-03 11:56:02 +02:00
keepDataPeriodDays: int = 180,
# general
2022-08-03 11:56:02 +02:00
entryPage: str = "dashboard",
searchEngineIndex: bool = False,
primaryBaseURL: str = "",
steamAPIKey: str = "",
# notifications
2022-08-03 11:56:02 +02:00
tlsExpiryNotifyDays: list = None,
# security
2022-09-07 13:03:10 +02:00
disableAuth: bool = False,
# reverse proxy
trustProxy: bool = False
):
2022-08-03 11:56:02 +02:00
if not tlsExpiryNotifyDays:
tlsExpiryNotifyDays = [7, 14, 21]
data = {
2022-08-03 11:56:02 +02:00
"checkUpdate": checkUpdate,
"checkBeta": checkBeta,
"keepDataPeriodDays": keepDataPeriodDays,
"entryPage": entryPage,
"searchEngineIndex": searchEngineIndex,
"primaryBaseURL": primaryBaseURL,
"steamAPIKey": steamAPIKey,
"tlsExpiryNotifyDays": tlsExpiryNotifyDays,
"disableAuth": disableAuth
}
2022-09-07 13:03:10 +02:00
if parse_version(self.version) >= parse_version("1.18"):
data.update({
"trustProxy": trustProxy
})
return self._call('setSettings', (data, password))
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def change_password(self, old_password: str, new_password: str):
return self._call('changePassword', {
2022-07-02 16:00:54 +02:00
"currentPassword": old_password,
"newPassword": new_password,
})
2022-08-05 14:35:17 +02:00
def upload_backup(self, json_data, import_handle: str = "skip"):
2022-07-02 16:00:54 +02:00
if import_handle not in ["overwrite", "skip", "keep"]:
raise ValueError()
return self._call('uploadBackup', (json_data, import_handle))
2022-07-02 16:00:54 +02:00
# 2FA
def twofa_status(self):
return self._call('twoFAStatus')
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def prepare_2fa(self, password: str):
return self._call('prepare2FA', password)
2022-07-02 16:00:54 +02:00
2022-08-05 14:33:28 +02:00
def verify_token(self, token: str, password: str):
return self._call('verifyToken', (token, password))
2022-07-05 22:12:37 +02:00
def save_2fa(self, password: str):
return self._call('save2FA', password)
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def disable_2fa(self, password: str):
return self._call('disable2FA', password)
2022-07-02 16:00:54 +02:00
# login
def _wait_for_auto_login(self):
while self._event_data[Event.AUTO_LOGIN] is None:
time.sleep(0.01)
def login(self, username: str = None, password: str = None, token: str = ""):
# autologin
if username is None and password is None:
self._wait_for_auto_login()
return
return self._call('login', {
2022-07-02 16:00:54 +02:00
"username": username,
"password": password,
2022-08-26 17:02:55 +02:00
"token": token
2022-07-02 16:00:54 +02:00
})
2022-07-05 22:12:37 +02:00
def login_by_token(self, token: str):
return self._call('loginByToken', token)
2022-07-02 16:00:54 +02:00
def logout(self):
return self._call('logout')
2022-07-02 16:00:54 +02:00
# setup
def need_setup(self):
return self._call('needSetup')
2022-07-02 16:00:54 +02:00
2022-07-05 22:12:37 +02:00
def setup(self, username: str, password: str):
return self._call("setup", (username, password))
2022-07-02 20:40:14 +02:00
# database
def get_database_size(self):
return self._call('getDatabaseSize')
2022-07-02 20:40:14 +02:00
def shrink_database(self):
return self._call('shrinkDatabase')
2022-09-07 13:03:10 +02:00
# docker host
def get_docker_hosts(self):
r = self._get_event_data(Event.DOCKER_HOST_LIST)
return r
def get_docker_host(self, id_: int):
docker_hosts = self.get_docker_hosts()
for docker_host in docker_hosts:
if docker_host["id"] == id_:
return docker_host
raise UptimeKumaException("docker host does not exist")
def test_docker_host(self, **kwargs):
data = _build_docker_host_data(**kwargs)
return self._call('testDockerHost', data)
def add_docker_host(self, **kwargs):
data = _build_docker_host_data(**kwargs)
_convert_docker_host_input(data)
2022-09-07 13:03:10 +02:00
return self._call('addDockerHost', (data, None))
def edit_docker_host(self, id_: int, **kwargs):
data = self.get_docker_host(id_)
data.update(kwargs)
_convert_docker_host_input(data)
2022-09-07 13:03:10 +02:00
return self._call('addDockerHost', (data, id_))
def delete_docker_host(self, id_: int):
return self._call('deleteDockerHost', id_)