Compare commits

...

9 commits

Author SHA1 Message Date
lucasheld
22ca1813ff bump version to 1.2.1 2023-09-26 22:32:04 +02:00
lucasheld
370b7e3e18 fix: drop first info event without a version
closes #55
2023-09-26 22:29:33 +02:00
Lucas Held
75a0b57eea
Update README.md 2023-09-23 13:59:27 +02:00
lucasheld
ba047114c9 bump version to 1.2.0 2023-08-29 18:41:23 +02:00
lucasheld
7902213ddb feat: add support for uptime kuma 1.23.0 and 1.23.1 2023-08-29 18:37:27 +02:00
lucasheld
0d49e97fe5 fix: validate accepted status codes types
closes #42
2023-08-12 18:20:59 +02:00
lucasheld
18107848f8 fix: convert sendUrl from bool to int 2023-08-12 16:40:25 +02:00
lucasheld
3543f09a5f fix: rstip url globally 2023-08-12 16:39:44 +02:00
lucasheld
2611b344f1 fix: remove name from maintenance monitors and status pages 2023-08-12 16:37:28 +02:00
20 changed files with 581 additions and 188 deletions

View file

@ -1,8 +1,24 @@
## Changelog
### Release 1.2.1
#### Bugfixes
- drop first info event without a version
### Release 1.2.0
#### Features
- add support for uptime kuma 1.23.0 and 1.23.1
#### Bugfixes
- remove `name` from maintenance monitors and status pages
- rstip url globally
- convert sendUrl from bool to int
- validate accepted status codes types
### Release 1.1.0
#### Feature
#### Features
- add support for uptime kuma 1.22.0 and 1.22.1
### Release 1.0.1

View file

@ -12,7 +12,7 @@ Supported Uptime Kuma versions:
| Uptime Kuma | uptime-kuma-api |
|-----------------|-----------------|
| 1.21.3 - 1.22.1 | 1.0.0 - 1.1.0 |
| 1.21.3 - 1.23.2 | 1.0.0 - 1.2.1 |
| 1.17.0 - 1.21.2 | 0.1.0 - 0.13.0 |
Installation

View file

@ -5,7 +5,7 @@ if [ $version ]
then
versions=("$version")
else
versions=(1.22.1 1.22.0 1.21.3)
versions=(1.23.2 1.23.0 1.22.1 1.22.0 1.21.3)
fi
for version in ${versions[*]}
@ -23,6 +23,7 @@ do
echo "Stopping uptime kuma..."
docker stop uptimekuma > /dev/null
sleep 1
echo ''
done

View file

@ -1,37 +1,57 @@
import glob
import re
from bs4 import BeautifulSoup
from utils import deduplicate_list, parse_vue_template
from utils import deduplicate_list, parse_vue_template, diff, type_html_to_py
ROOT = "uptime-kuma"
input_ignores = {
"settings": [
"$root.styleElapsedTime"
]
}
def parse_model_keys(content, object_name):
match = re.findall(object_name + r"\.[0-9a-zA-Z_$]+", content)
keys = []
for m in match:
key = m.replace(object_name + ".", "")
keys.append(key)
keys = deduplicate_list(keys)
return keys
soup = BeautifulSoup(content, "html.parser")
soup_inputs = soup.find_all(attrs={"v-model": True})
inputs = []
for soup_input in soup_inputs:
key = soup_input["v-model"]
if key in input_ignores.get(object_name, []):
continue
else:
key = re.sub(r'^' + object_name + r'\.', "", key)
type_ = soup_input.get("type", "text")
type_ = type_html_to_py(type_)
if type_ == "bool":
value = True if soup_input.get("checked") else False
else:
value = soup_input.get("value")
inputs.append({
"key": key,
"type": type_,
"default": value,
})
return inputs
def parse_proxy_keys():
content = parse_vue_template(f"{ROOT}/src/components/ProxyDialog.vue")
def parse_proxy_keys(root):
content = parse_vue_template(f"{root}/src/components/ProxyDialog.vue")
keys = parse_model_keys(content, "proxy")
return keys
def parse_notification_keys():
content = parse_vue_template(f"{ROOT}/src/components/NotificationDialog.vue")
def parse_notification_keys(root):
content = parse_vue_template(f"{root}/src/components/NotificationDialog.vue")
keys = parse_model_keys(content, "notification")
return keys
def parse_settings_keys():
def parse_settings_keys(root):
all_keys = []
for path in glob.glob('uptime-kuma/src/components/settings/*'):
for path in glob.glob(f'{root}/src/components/settings/*'):
content = parse_vue_template(path)
keys = parse_model_keys(content, "settings")
all_keys.extend(keys)
@ -39,20 +59,20 @@ def parse_settings_keys():
return all_keys
def parse_monitor_keys():
content = parse_vue_template(f"{ROOT}/src/pages/EditMonitor.vue")
def parse_monitor_keys(root):
content = parse_vue_template(f"{root}/src/pages/EditMonitor.vue")
keys = parse_model_keys(content, "monitor")
return keys
def parse_status_page_keys():
def parse_status_page_keys(root):
all_keys = ["id"]
content = parse_vue_template(f"{ROOT}/src/pages/StatusPage.vue")
content = parse_vue_template(f"{root}/src/pages/StatusPage.vue")
keys = parse_model_keys(content, "config")
all_keys.extend(keys)
content = parse_vue_template(f"{ROOT}/src/pages/ManageStatusPage.vue")
content = parse_vue_template(f"{root}/src/pages/ManageStatusPage.vue")
keys = parse_model_keys(content, "statusPage")
all_keys.extend(keys)
@ -60,30 +80,28 @@ def parse_status_page_keys():
return all_keys
def parse_maintenance_keys():
content = parse_vue_template(f"{ROOT}/src/pages/EditMaintenance.vue")
def parse_maintenance_keys(root):
content = parse_vue_template(f"{root}/src/pages/EditMaintenance.vue")
keys = parse_model_keys(content, "maintenance")
return keys
def main():
proxy_keys = parse_proxy_keys()
print("proxy:", proxy_keys)
root_old = "uptime-kuma-old"
root_new = "uptime-kuma"
notification_keys = parse_notification_keys()
print("notification:", notification_keys)
settings_keys = parse_settings_keys()
print("settings:", settings_keys)
monitor_keys = parse_monitor_keys()
print("monitor:", monitor_keys)
status_page_keys = parse_status_page_keys()
print("status_page:", status_page_keys)
maintenance_keys = parse_maintenance_keys()
print("maintenance:", maintenance_keys)
for name, func in [
["proxy", parse_proxy_keys],
["notification", parse_notification_keys],
["settings", parse_settings_keys],
["monitor", parse_monitor_keys],
["status_page", parse_status_page_keys],
["maintenance", parse_maintenance_keys],
]:
keys_old = func(root_old)
keys_new = func(root_new)
print(f"{name}:")
diff(keys_old, keys_new)
if __name__ == "__main__":

View file

@ -1,10 +1,6 @@
import re
from pprint import pprint
from utils import deduplicate_list
ROOT = "uptime-kuma"
from utils import deduplicate_list, diff
def parse_json_keys(data):
@ -22,17 +18,8 @@ def parse_json_keys(data):
return keys
# def parse_object_keys(code, object_name):
# match = re.findall(object_name + r'\.[0-9a-zA-Z_$]+', code)
# keys = []
# for m in match:
# key = m.replace(object_name + ".", "")
# keys.append(key)
# return list(set(keys))
def parse_heartbeat():
with open(f'{ROOT}/server/model/heartbeat.js') as f:
def parse_heartbeat(root):
with open(f'{root}/server/model/heartbeat.js') as f:
content = f.read()
all_keys = []
match = re.search(r'toJSON\(\) {\s+return.*{([^}]+)}', content)
@ -47,8 +34,8 @@ def parse_heartbeat():
return all_keys
def parse_incident():
with open(f'{ROOT}/server/model/incident.js') as f:
def parse_incident(root):
with open(f'{root}/server/model/incident.js') as f:
content = f.read()
match = re.search(r'toPublicJSON\(\) {\s+return.*{([^}]+)}', content)
data = match.group(1)
@ -56,9 +43,9 @@ def parse_incident():
return keys
def parse_monitor():
def parse_monitor(root):
# todo: toPublicJSON ???
with open(f'{ROOT}/server/model/monitor.js') as f:
with open(f'{root}/server/model/monitor.js') as f:
content = f.read()
matches = re.findall(r'data = {([^}]+)}', content)
all_keys = []
@ -70,8 +57,8 @@ def parse_monitor():
return all_keys
def parse_proxy():
with open(f'{ROOT}/server/model/proxy.js') as f:
def parse_proxy(root):
with open(f'{root}/server/model/proxy.js') as f:
content = f.read()
match = re.search(r'toJSON\(\) {\s+return.*{([^}]+)}', content)
data = match.group(1)
@ -102,7 +89,7 @@ def parse_proxy():
# # input (add, edit proxy)
# def parse_proxy2():
# with open(f'{ROOT}/server/proxy.js') as f:
# with open(f'{root}/server/proxy.js') as f:
# content = f.read()
#
# code = parse_function(r'async save\([^)]+\) ', content)
@ -110,8 +97,8 @@ def parse_proxy():
# return keys
def parse_status_page():
with open(f'{ROOT}/server/model/status_page.js') as f:
def parse_status_page(root):
with open(f'{root}/server/model/status_page.js') as f:
content = f.read()
all_keys = []
match = re.search(r'toJSON\(\) {\s+return.*{([^}]+)}', content)
@ -126,8 +113,8 @@ def parse_status_page():
return all_keys
def parse_tag():
with open(f'{ROOT}/server/model/tag.js') as f:
def parse_tag(root):
with open(f'{root}/server/model/tag.js') as f:
content = f.read()
match = re.search(r'toJSON\(\) {\s+return.*{([^}]+)}', content)
data = match.group(1)
@ -135,33 +122,22 @@ def parse_tag():
return keys
print("heartbeat")
pprint(parse_heartbeat())
print("")
if __name__ == "__main__":
root_old = "uptime-kuma-old"
root_new = "uptime-kuma"
print("incident")
pprint(parse_incident())
print("")
print("monitor")
pprint(parse_monitor())
print("")
print("proxy")
pprint(parse_proxy())
print("")
# print("prox2")
# pprint(parse_proxy2())
# print("")
print("status page")
pprint(parse_status_page())
print("")
print("tag")
pprint(parse_tag())
print("")
for name, func in [
["heartbeat", parse_heartbeat],
["incident", parse_incident],
["monitor", parse_monitor],
["proxy", parse_proxy],
["status page", parse_status_page],
["tag", parse_tag],
]:
keys_old = func(root_old)
keys_new = func(root_new)
print(f"{name}:")
diff(keys_old, keys_new)
# TODO:

View file

@ -3,6 +3,32 @@ from bs4 import BeautifulSoup
from utils import parse_vue_template, write_to_file
titles = {
"http": "HTTP(s)",
"port": "TCP Port",
"ping": "Ping",
"keyword": "HTTP(s) - Keyword",
"grpc-keyword": "gRPC(s) - Keyword",
"dns": "DNS",
"docker": "Docker Container",
"push": "Push",
"steam": "Steam Game Server",
"gamedig": "GameDig",
"mqtt": "MQTT",
"sqlserver": "Microsoft SQL Server",
"postgres": "PostgreSQL",
"mysql": "MySQL/MariaDB",
"mongodb": "MongoDB",
"radius": "Radius",
"redis": "Redis",
"group": "Group",
"json-query": "HTTP(s) - Json Query",
"real-browser": "HTTP(s) - Browser Engine (Chrome/Chromium)",
"kafka-producer": "Kafka Producer",
"tailscale-ping": "Tailscale Ping"
}
def parse_monitor_types():
content = parse_vue_template("uptime-kuma/src/pages/EditMonitor.vue")
@ -10,10 +36,13 @@ def parse_monitor_types():
select = soup.find("select", id="type")
options = select.find_all("option")
types = []
types = {}
for o in options:
type_ = o.attrs["value"]
types.append(type_)
types[type_] = {
"value": type_,
"title": titles[type_]
}
return types

View file

@ -3,7 +3,7 @@ import re
from bs4 import BeautifulSoup
from utils import deduplicate_list, write_to_file
from utils import deduplicate_list, write_to_file, type_html_to_py
# deprecated or wrong inputs
@ -26,6 +26,10 @@ ignored_inputs = {
]
}
input_overwrites = {
"showAdditionalHeadersField": "webhookAdditionalHeaders"
}
titles = {
"alerta": "Alerta",
"AlertNow": "AlertNow",
@ -48,6 +52,7 @@ titles = {
"OneBot": "OneBot",
"Opsgenie": "Opsgenie",
"PagerDuty": "PagerDuty",
"PagerTree": "PagerTree",
"pushbullet": "Pushbullet",
"PushByTechulus": "Push by Techulus",
"pushover": "Pushover",
@ -76,10 +81,14 @@ titles = {
"SMSManager": "SmsManager (smsmanager.cz)",
"WeCom": "WeCom",
"ServerChan": "ServerChan",
"nostr": "Nostr",
"FlashDuty": "FlashDuty",
"smsc": "SMSC",
}
def build_notification_providers(root):
def build_notification_providers():
root = "uptime-kuma"
providers = {}
# get providers and input names
@ -96,7 +105,7 @@ def build_notification_providers(root):
inputs = [i.strip() for i in inputs]
providers[name] = {
"title": titles.get(name, name),
"title": titles[name],
"inputs": {},
}
for input_ in inputs:
@ -117,15 +126,15 @@ def build_notification_providers(root):
conditions = {}
attrs = input_.attrs
v_model = attrs.get("v-model")
param_name = re.match(r'\$parent.notification.(.*)$', v_model).group(1)
v_model_overwrite = input_overwrites.get(v_model)
if v_model_overwrite:
param_name = v_model_overwrite
else:
param_name = re.match(r'\$parent.notification.(.*)$', v_model).group(1)
type_ = attrs.get("type")
if type_ == "number":
type_ = "int"
elif type_ == "checkbox":
type_ = "bool"
else:
type_ = "str"
type_ = type_html_to_py(type_)
required_true_values = ['', 'true']
if attrs.get("required") in required_true_values or attrs.get(":required") in required_true_values:
@ -157,17 +166,7 @@ def build_notification_providers(root):
return providers
def diff(old, new):
for i in new:
if i not in old:
print("+", i)
for i in old:
if i not in new:
print("-", i)
print("")
notification_providers = build_notification_providers("uptime-kuma")
notification_providers = build_notification_providers()
notification_provider_conditions = {}
for notification_provider in notification_providers:
@ -181,11 +180,3 @@ write_to_file(
notification_providers=notification_providers,
notification_provider_conditions=notification_provider_conditions
)
# notification_providers_old = build_notification_providers("uptime-kuma-old")
# notification_providers_new = build_notification_providers("uptime-kuma")
# diff(notification_providers_old, notification_providers_new)
#
# notification_provider_conditions_old = build_notification_provider_conditions("uptime-kuma-old")
# notification_provider_conditions_new = build_notification_provider_conditions("uptime-kuma")
# diff(notification_provider_conditions_old, notification_provider_conditions_new)

View file

@ -1,6 +0,0 @@
notification = [
"type",
"isDefault",
"userId",
"applyExisting",
]

View file

@ -2,7 +2,10 @@ from enum import Enum
class MonitorType(str, Enum):
{%- for name in monitor_types %}
{{ name.upper() }} = "{{ name }}"
{%- endfor %}
"""Enumerate monitor types."""
{{""}}
{%- for type_ in monitor_types.values() %}
{{ type_["value"].upper().replace("-", "_") }} = "{{ type_["value"] }}"
"""{{ type_["title"] }}"""
{% endfor -%}

View file

@ -24,3 +24,23 @@ def write_to_file(template, destination, **kwargs):
rendered = template.render(**kwargs)
with open(destination, "w") as f:
f.write(rendered)
def diff(old, new):
for i in new:
if i not in old:
print("+", i)
for i in old:
if i not in new:
print("-", i)
print("")
def type_html_to_py(type_):
if type_ == "number":
type_ = "int"
elif type_ == "checkbox":
type_ = "bool"
else:
type_ = "str"
return type_

View file

@ -1,4 +1,5 @@
import unittest
from packaging.version import parse as parse_version
from uptime_kuma_api import DockerType, UptimeKumaException
from uptime_kuma_test_case import UptimeKumaTestCase
@ -16,8 +17,10 @@ class TestDockerHost(UptimeKumaTestCase):
}
# test docker host
with self.assertRaisesRegex(UptimeKumaException, r'connect ENOENT /var/run/docker.sock'):
self.api.test_docker_host(**expected_docker_host)
if parse_version(self.api.version) != parse_version("1.23.0"):
# test_docker_host does not work in 1.23.0 (https://github.com/louislam/uptime-kuma/issues/3605)
with self.assertRaisesRegex(UptimeKumaException, r'connect ENOENT /var/run/docker.sock'):
self.api.test_docker_host(**expected_docker_host)
# add docker host
r = self.api.add_docker_host(**expected_docker_host)

View file

@ -1,5 +1,6 @@
import unittest
from uptime_kuma_api import UptimeKumaApi
from uptime_kuma_test_case import UptimeKumaTestCase
@ -9,6 +10,16 @@ class TestInfo(UptimeKumaTestCase):
self.assertIn("version", info)
self.assertIn("latestVersion", info)
def test_info_with_version(self):
# If wait_events is set to 0, the first info event is normally used.
# The info event handler needs to drop this first event without a version.
self.api.logout()
self.api.disconnect()
self.api = UptimeKumaApi(self.url, wait_events=0)
self.api.login(self.username, self.password)
info = self.api.info()
self.assertIn("version", info)
if __name__ == '__main__':
unittest.main()

View file

@ -59,8 +59,7 @@ class TestMaintenance(UptimeKumaTestCase):
monitor_id = self.add_monitor(monitor_name)
monitors = [
{
"id": monitor_id,
"name": monitor_name
"id": monitor_id
},
]
r = self.api.add_monitor_maintenance(maintenance_id, monitors)
@ -76,8 +75,7 @@ class TestMaintenance(UptimeKumaTestCase):
status_page_id = self.add_status_page(status_page_title)
status_pages = [
{
"id": status_page_id,
"name": status_page_title
"id": status_page_id
}
]
r = self.api.add_status_page_maintenance(maintenance_id, status_pages)

View file

@ -324,6 +324,53 @@ class TestMonitor(UptimeKumaTestCase):
}
self.do_test_monitor_type(expected_monitor)
def test_monitor_type_json_query(self):
if parse_version(self.api.version) < parse_version("1.23"):
self.skipTest("Unsupported in this Uptime Kuma version")
expected_monitor = {
"type": MonitorType.JSON_QUERY,
"name": "monitor 1",
"url": "http://127.0.0.1",
"jsonPath": "address.country",
"expectedValue": "germany",
}
self.do_test_monitor_type(expected_monitor)
def test_monitor_type_real_browser(self):
if parse_version(self.api.version) < parse_version("1.23"):
self.skipTest("Unsupported in this Uptime Kuma version")
expected_monitor = {
"type": MonitorType.REAL_BROWSER,
"name": "monitor 1",
"url": "http://127.0.0.1",
}
self.do_test_monitor_type(expected_monitor)
def test_monitor_type_kafka_producer(self):
if parse_version(self.api.version) < parse_version("1.23"):
self.skipTest("Unsupported in this Uptime Kuma version")
expected_monitor = {
"type": MonitorType.KAFKA_PRODUCER,
"name": "monitor 1",
"kafkaProducerTopic": "topic",
"kafkaProducerMessage": "message",
}
self.do_test_monitor_type(expected_monitor)
def test_monitor_type_tailscale_ping(self):
if parse_version(self.api.version) < parse_version("1.23"):
self.skipTest("Unsupported in this Uptime Kuma version")
expected_monitor = {
"type": MonitorType.TAILSCALE_PING,
"name": "monitor 1",
"hostname": "127.0.0.1"
}
self.do_test_monitor_type(expected_monitor)
def test_delete_not_existing_monitor(self):
with self.assertRaises(UptimeKumaException):
self.api.delete_monitor(42)

View file

@ -1,5 +1,5 @@
__title__ = "uptime_kuma_api"
__version__ = "1.1.0"
__version__ = "1.2.1"
__author__ = "Lucas Held"
__license__ = "MIT"
__copyright__ = "Copyright 2023 Lucas Held"

View file

@ -278,7 +278,11 @@ def _check_arguments_monitor(kwargs) -> None:
MonitorType.MONGODB: [],
MonitorType.RADIUS: ["radiusUsername", "radiusPassword", "radiusSecret", "radiusCalledStationId", "radiusCallingStationId"],
MonitorType.REDIS: [],
MonitorType.GROUP: []
MonitorType.GROUP: [],
MonitorType.JSON_QUERY: ["url", "jsonPath", "expectedValue"],
MonitorType.REAL_BROWSER: ["url"],
MonitorType.KAFKA_PRODUCER: ["kafkaProducerTopic", "kafkaProducerMessage"],
MonitorType.TAILSCALE_PING: ["hostname"],
}
type_ = kwargs["type"]
required_args = required_args_by_type[type_]
@ -304,6 +308,46 @@ def _check_arguments_monitor(kwargs) -> None:
)
_check_argument_conditions(conditions, kwargs)
allowed_accepted_statuscodes = [
"100-199",
"200-299",
"300-399",
"400-499",
"500-599",
] + [
str(i) for i in range(100, 999 + 1)
]
accepted_statuscodes = kwargs["accepted_statuscodes"]
for accepted_statuscode in accepted_statuscodes:
if accepted_statuscode not in allowed_accepted_statuscodes:
raise ValueError(f"Unknown accepted_statuscodes value: {allowed_accepted_statuscodes}")
dns_resolve_type = kwargs["dns_resolve_type"]
if dns_resolve_type not in [
"A",
"AAAA",
"CAA",
"CNAME",
"MX",
"NS",
"PTR",
"SOA",
"SRV",
"TXT",
]:
raise ValueError(f"Unknown dns_resolve_type value: {dns_resolve_type}")
if type_ == MonitorType.KAFKA_PRODUCER:
kafkaProducerSaslOptions_mechanism = kwargs["kafkaProducerSaslOptions"]["mechanism"]
if kafkaProducerSaslOptions_mechanism not in [
"None",
"plain",
"scram-sha-256",
"scram-sha-512",
"aws",
]:
raise ValueError(f"Unknown kafkaProducerSaslOptions[\"mechanism\"] value: {kafkaProducerSaslOptions_mechanism}")
def _check_arguments_notification(kwargs) -> None:
required_args = ["type", "name"]
@ -421,7 +465,7 @@ class UptimeKumaApi(object):
ssl_verify: bool = True,
wait_events: float = 0.2
) -> None:
self.url = url
self.url = url.rstrip("/")
self.timeout = timeout
self.headers = headers
self.wait_events = wait_events
@ -582,6 +626,9 @@ class UptimeKumaApi(object):
self._event_data[Event.IMPORTANT_HEARTBEAT_LIST][monitor_id] = [data] + self._event_data[Event.IMPORTANT_HEARTBEAT_LIST][monitor_id]
def _event_info(self, data) -> None:
if "version" not in data:
# wait for the info event that is sent after login and contains the version
return
self._event_data[Event.INFO] = data
def _event_cert_info(self, monitor_id, data) -> None:
@ -616,9 +663,8 @@ class UptimeKumaApi(object):
:raises UptimeKumaException: When connection to server failed.
"""
url = self.url.rstrip("/")
try:
self.sio.connect(f'{url}/socket.io/', wait_timeout=self.timeout, headers=self.headers)
self.sio.connect(f'{self.url}/socket.io/', wait_timeout=self.timeout, headers=self.headers)
except:
raise UptimeKumaException("unable to connect")
@ -651,12 +697,16 @@ class UptimeKumaApi(object):
notificationIDList: list = None,
httpBodyEncoding: str = "json",
# HTTP, KEYWORD
# HTTP, KEYWORD, JSON_QUERY, REAL_BROWSER
url: str = None,
# HTTP, KEYWORD, GRPC_KEYWORD
maxredirects: int = 10,
accepted_statuscodes: list[str] = None,
# HTTP, KEYWORD, JSON_QUERY
expiryNotification: bool = False,
ignoreTls: bool = False,
maxredirects: int = 10,
accepted_statuscodes: list = None,
proxyId: int = None,
method: str = "GET",
body: str = None,
@ -669,9 +719,16 @@ class UptimeKumaApi(object):
basic_auth_pass: str = None,
authDomain: str = None,
authWorkstation: str = None,
oauth_auth_method: str = "client_secret_basic",
oauth_token_url: str = None,
oauth_client_id: str = None,
oauth_client_secret: str = None,
oauth_scopes: str = None,
timeout: int = 48,
# KEYWORD
keyword: str = None,
invertKeyword: bool = False,
# GRPC_KEYWORD
grpcUrl: str = None,
@ -682,13 +739,13 @@ class UptimeKumaApi(object):
grpcBody: str = None,
grpcMetadata: str = None,
# DNS, PING, STEAM, MQTT
# PORT, PING, DNS, STEAM, MQTT, RADIUS, TAILSCALE_PING
hostname: str = None,
# PING
packetSize: int = 56,
# DNS, STEAM, MQTT, RADIUS
# PORT, DNS, STEAM, MQTT, RADIUS
port: int = None,
# DNS
@ -696,10 +753,10 @@ class UptimeKumaApi(object):
dns_resolve_type: str = "A",
# MQTT
mqttUsername: str = None,
mqttPassword: str = None,
mqttTopic: str = None,
mqttSuccessMessage: str = None,
mqttUsername: str = "",
mqttPassword: str = "",
mqttTopic: str = "",
mqttSuccessMessage: str = "",
# SQLSERVER, POSTGRES, MYSQL, MONGODB, REDIS
databaseConnectionString: str = None,
@ -719,8 +776,27 @@ class UptimeKumaApi(object):
radiusCallingStationId: str = None,
# GAMEDIG
game: str = None
game: str = None,
gamedigGivenPortOnly: bool = True,
# JSON_QUERY
jsonPath: str = None,
expectedValue: str = None,
# KAFKA_PRODUCER
kafkaProducerBrokers: list[str] = None,
kafkaProducerTopic: str = None,
kafkaProducerMessage: str = None,
kafkaProducerSsl: bool = False,
kafkaProducerAllowAutoTopicCreation: bool = False,
kafkaProducerSaslOptions: dict = None,
) -> dict:
if accepted_statuscodes is None:
accepted_statuscodes = ["200-299"]
if notificationIDList is None:
notificationIDList = {}
data = {
"type": type,
"name": name,
@ -731,26 +807,37 @@ class UptimeKumaApi(object):
"upsideDown": upsideDown,
"resendInterval": resendInterval,
"description": description,
"httpBodyEncoding": httpBodyEncoding
"httpBodyEncoding": httpBodyEncoding,
}
if parse_version(self.version) >= parse_version("1.22"):
data.update({
"parent": parent
"parent": parent,
})
if type in [MonitorType.KEYWORD, MonitorType.GRPC_KEYWORD]:
data.update({
"keyword": keyword,
})
if parse_version(self.version) >= parse_version("1.23"):
data.update({
"invertKeyword": invertKeyword,
})
# HTTP, KEYWORD
# HTTP, KEYWORD, JSON_QUERY, REAL_BROWSER
data.update({
"url": url,
"expiryNotification": expiryNotification,
"ignoreTls": ignoreTls,
})
# HTTP, KEYWORD, GRPC_KEYWORD
data.update({
"maxredirects": maxredirects,
"accepted_statuscodes": accepted_statuscodes,
})
data.update({
"expiryNotification": expiryNotification,
"ignoreTls": ignoreTls,
"proxyId": proxyId,
"method": method,
"body": body,
@ -758,6 +845,11 @@ class UptimeKumaApi(object):
"authMethod": authMethod,
})
if parse_version(self.version) >= parse_version("1.23"):
data.update({
"timeout": timeout,
})
if authMethod in [AuthMethod.HTTP_BASIC, AuthMethod.NTLM]:
data.update({
"basic_auth_user": basic_auth_user,
@ -777,6 +869,15 @@ class UptimeKumaApi(object):
"tlsCa": tlsCa,
})
if authMethod == AuthMethod.OAUTH2_CC:
data.update({
"oauth_auth_method": oauth_auth_method,
"oauth_token_url": oauth_token_url,
"oauth_client_id": oauth_client_id,
"oauth_client_secret": oauth_client_secret,
"oauth_scopes": oauth_scopes,
})
# GRPC_KEYWORD
if type == MonitorType.GRPC_KEYWORD:
data.update({
@ -789,7 +890,7 @@ class UptimeKumaApi(object):
"grpcMetadata": grpcMetadata,
})
# PORT, PING, DNS, STEAM, MQTT
# PORT, PING, DNS, STEAM, MQTT, RADIUS, TAILSCALE_PING
data.update({
"hostname": hostname,
})
@ -838,7 +939,7 @@ class UptimeKumaApi(object):
if type == MonitorType.DOCKER:
data.update({
"docker_container": docker_container,
"docker_host": docker_host
"docker_host": docker_host,
})
# RADIUS
@ -848,15 +949,42 @@ class UptimeKumaApi(object):
"radiusPassword": radiusPassword,
"radiusSecret": radiusSecret,
"radiusCalledStationId": radiusCalledStationId,
"radiusCallingStationId": radiusCallingStationId
"radiusCallingStationId": radiusCallingStationId,
})
# GAMEDIG
if type == MonitorType.GAMEDIG:
data.update({
"game": game
"game": game,
})
if parse_version(self.version) >= parse_version("1.23"):
data.update({
"gamedigGivenPortOnly": gamedigGivenPortOnly,
})
# JSON_QUERY
if type == MonitorType.JSON_QUERY:
data.update({
"jsonPath": jsonPath,
"expectedValue": expectedValue,
})
# KAFKA_PRODUCER
if type == MonitorType.KAFKA_PRODUCER:
if kafkaProducerBrokers is None:
kafkaProducerBrokers = []
if not kafkaProducerSaslOptions:
kafkaProducerSaslOptions = {
"mechanism": "None",
}
data.update({
"kafkaProducerBrokers": kafkaProducerBrokers,
"kafkaProducerTopic": kafkaProducerTopic,
"kafkaProducerMessage": kafkaProducerMessage,
"kafkaProducerSsl": kafkaProducerSsl,
"kafkaProducerAllowAutoTopicCreation": kafkaProducerAllowAutoTopicCreation,
"kafkaProducerSaslOptions": kafkaProducerSaslOptions,
})
return data
def _build_maintenance_data(
@ -924,6 +1052,7 @@ class UptimeKumaApi(object):
customCSS: str = "",
footerText: str = None,
showPoweredBy: bool = True,
showCertificateExpiry: bool = False,
icon: str = "/icon.svg",
publicGroupList: list = None
@ -952,8 +1081,12 @@ class UptimeKumaApi(object):
"googleAnalyticsId": googleAnalyticsId,
"customCSS": customCSS,
"footerText": footerText,
"showPoweredBy": showPoweredBy
"showPoweredBy": showPoweredBy,
}
if parse_version(self.version) >= parse_version("1.23"):
config.update({
"showCertificateExpiry": showCertificateExpiry,
})
return slug, config, icon, publicGroupList
# monitor
@ -1080,9 +1213,11 @@ class UptimeKumaApi(object):
'dns_resolve_type': 'A',
'docker_container': None,
'docker_host': None,
'expectedValue': None,
'expiryNotification': False,
'forceInactive': False,
'game': None,
'gamedigGivenPortOnly': True,
'grpcBody': None,
'grpcEnableTls': False,
'grpcMetadata': None,
@ -1097,17 +1232,30 @@ class UptimeKumaApi(object):
'ignoreTls': False,
'includeSensitiveData': True,
'interval': 60,
'invertKeyword': False,
'jsonPath': None,
'kafkaProducerAllowAutoTopicCreation': False,
'kafkaProducerBrokers': None,
'kafkaProducerMessage': None,
'kafkaProducerSaslOptions': None,
'kafkaProducerSsl': False,
'kafkaProducerTopic': None,
'keyword': None,
'maintenance': False,
'maxredirects': 10,
'maxretries': 0,
'method': 'GET',
'mqttPassword': None,
'mqttSuccessMessage': None,
'mqttTopic': None,
'mqttUsername': None,
'mqttPassword': '',
'mqttSuccessMessage': '',
'mqttTopic': '',
'mqttUsername': '',
'name': 'monitor 1',
'notificationIDList': [1, 2],
'oauth_auth_method': None,
'oauth_client_id': None,
'oauth_client_secret': None,
'oauth_scopes': None,
'oauth_token_url': None,
'packetSize': 56,
'parent': None,
'pathName': 'monitor 1',
@ -1121,7 +1269,9 @@ class UptimeKumaApi(object):
'radiusUsername': None,
'resendInterval': 0,
'retryInterval': 60,
'screenshot': None,
'tags': [],
'timeout': 48,
'tlsCa': None,
'tlsCert': None,
'tlsKey': None,
@ -1277,6 +1427,23 @@ class UptimeKumaApi(object):
r = self._call('getGameList')
return r.get("gameList")
def test_chrome(self, executable) -> dict:
"""
Test if the chrome executable is valid and return the version.
:return: The server response.
:rtype: dict
:raises UptimeKumaException: If the server returns an error.
Example::
>>> api.test_chrome("/usr/bin/chromium")
{
'msg': 'Found Chromium/Chrome. Version: 90.0.4430.212'
}
"""
return self._call('testChrome', executable)
@append_docstring(monitor_docstring("add"))
def add_monitor(self, **kwargs) -> dict:
"""
@ -1797,8 +1964,8 @@ class UptimeKumaApi(object):
'description': 'description 1',
'domainNameList': [],
'footerText': None,
'icon': '/icon.svg',
'googleAnalyticsId': '',
'icon': '/icon.svg',
'id': 1,
'incident': {
'content': 'content 1',
@ -1817,7 +1984,8 @@ class UptimeKumaApi(object):
{
'id': 1,
'name': 'monitor 1',
'sendUrl': 0
'sendUrl': False,
'type': 'http'
}
],
'name': 'Services',
@ -1825,6 +1993,7 @@ class UptimeKumaApi(object):
}
],
'published': True,
'showCertificateExpiry': False,
'showPoweredBy': False,
'showTags': False,
'slug': 'slug1',
@ -1848,6 +2017,10 @@ class UptimeKumaApi(object):
"maintenanceList": r2["maintenanceList"]
}
parse_incident_style(data["incident"])
# convert sendUrl from int to bool
for i in data["publicGroupList"]:
for j in i["monitorList"]:
int_to_bool(j, ["sendUrl"])
return data
def add_status_page(self, slug: str, title: str) -> dict:
@ -1903,7 +2076,7 @@ class UptimeKumaApi(object):
:param str slug: Slug
:param int id: Id of the status page to save
:param str title: Title
:param str, optional title: Title, defaults to None
:param str, optional description: Description, defaults to None
:param str, optional theme: Switch Theme, defaults to "auto"
:param bool, optional published: Published, defaults to True
@ -1913,6 +2086,7 @@ class UptimeKumaApi(object):
:param str, optional customCSS: Custom CSS, defaults to ""
:param str, optional footerText: Custom Footer, defaults to None
:param bool, optional showPoweredBy: Show Powered By, defaults to True
:param bool, optional showCertificateExpiry: Show Certificate Expiry, defaults to False
:param str, optional icon: Icon, defaults to "/icon.svg"
:param list, optional publicGroupList: Public Group List, defaults to None
:return: The server response.
@ -2321,11 +2495,12 @@ class UptimeKumaApi(object):
>>> api.info()
{
'version': '1.19.2',
'latestVersion': '1.19.2',
'primaryBaseURL': None,
'isContainer': True,
'latestVersion': '1.23.1',
'primaryBaseURL': '',
'serverTimezone': 'Europe/Berlin',
'serverTimezoneOffset': '+01:00'
'serverTimezoneOffset': '+02:00',
'version': '1.23.1'
}
"""
r = self._get_event_data(Event.INFO)
@ -2519,10 +2694,12 @@ class UptimeKumaApi(object):
{
'checkBeta': False,
'checkUpdate': False,
'chromeExecutable': '',
'disableAuth': False,
'dnsCache': True,
'entryPage': 'dashboard',
'keepDataPeriodDays': 180,
'nscd': False,
'primaryBaseURL': '',
'searchEngineIndex': False,
'serverTimezone': 'Europe/Berlin',
@ -2555,7 +2732,9 @@ class UptimeKumaApi(object):
searchEngineIndex: bool = False,
primaryBaseURL: str = "",
steamAPIKey: str = "",
nscd: bool = False,
dnsCache: bool = False,
chromeExecutable: str = "",
# notifications
tlsExpiryNotifyDays: list = None,
@ -2578,7 +2757,9 @@ class UptimeKumaApi(object):
:param bool, optional searchEngineIndex: Search Engine Visibility, defaults to False
:param str, optional primaryBaseURL: Primary Base URL, defaults to ""
:param str, optional steamAPIKey: Steam API Key. For monitoring a Steam Game Server you need a Steam Web-API key., defaults to ""
:param bool, optional nscd: Enable NSCD (Name Service Cache Daemon) for caching all DNS requests, defaults to False
:param bool, optional dnsCache: True to enable DNS Cache. It may be not working in some IPv6 environments, disable it if you encounter any issues., defaults to False
:param str, optional chromeExecutable: Chrome/Chromium Executable, defaults to ""
:param list, optional tlsExpiryNotifyDays: TLS Certificate Expiry. HTTPS Monitors trigger notification when TLS certificate expires in., defaults to None
:param bool, optional disableAuth: Disable Authentication, defaults to False
:param bool, optional trustProxy: Trust Proxy. Trust 'X-Forwarded-\*' headers. If you want to get the correct client IP and your Uptime Kuma is behind such as Nginx or Apache, you should enable this., defaults to False
@ -2628,6 +2809,16 @@ class UptimeKumaApi(object):
"disableAuth": disableAuth,
"trustProxy": trustProxy
}
if parse_version(self.version) >= parse_version("1.23"):
data.update({
"chromeExecutable": chromeExecutable,
})
if parse_version(self.version) >= parse_version("1.23.1"):
data.update({
"nscd": nscd,
})
return self._call('setSettings', (data, password))
def change_password(self, old_password: str, new_password: str) -> dict:
@ -2682,7 +2873,7 @@ class UptimeKumaApi(object):
}
"""
if import_handle not in ["overwrite", "skip", "keep"]:
raise ValueError()
raise ValueError(f"Unknown import_handle value: {import_handle}")
return self._call('uploadBackup', (json_data, import_handle))
# 2FA
@ -3521,12 +3712,10 @@ class UptimeKumaApi(object):
>>> monitors = [
... {
... "id": 1,
... "name": "monitor 1"
... "id": 1
... },
... {
... "id": 2,
... "name": "monitor 2"
... "id": 2
... }
... ]
>>> api.add_monitor_maintenance(1, monitors)
@ -3575,12 +3764,10 @@ class UptimeKumaApi(object):
>>> status_pages = [
... {
... "id": 1,
... "name": "status page 1"
... "id": 1
... },
... {
... "id": 2,
... "name": "status page 2"
... "id": 2
... }
... ]
>>> api.add_status_page_maintenance(1, status_pages)

View file

@ -15,3 +15,6 @@ class AuthMethod(str, Enum):
MTLS = "mtls"
"""mTLS Authentication."""
OAUTH2_CC = "oauth2-cc"
"""OAuth2: Client Credentials"""

View file

@ -44,12 +44,30 @@ def monitor_docstring(mode) -> str:
:param str, optional basic_auth_pass: Password for ``authMethod`` :attr:`~.AuthMethod.HTTP_BASIC` and :attr:`~.AuthMethod.NTLM`, defaults to None
:param str, optional authDomain: Domain for ``authMethod`` :attr:`~.AuthMethod.NTLM`, defaults to None
:param str, optional authWorkstation: Workstation for ``authMethod`` :attr:`~.AuthMethod.NTLM`, defaults to None
:param str, optional oauth_auth_method: Authentication Method, defaults to None
:param str, optional oauth_token_url: OAuth Token URL, defaults to None
:param str, optional oauth_client_id: Client ID, defaults to None
:param str, optional oauth_client_secret: Client Secret, defaults to None
:param str, optional oauth_scopes: OAuth Scope, defaults to None
:param int, optional timeout: Request Timeout, defaults to None
:param str, optional keyword: Keyword. Search keyword in plain HTML or JSON response. The search is case-sensitive., defaults to None
:param bool, optional invertKeyword: Invert Keyword. Look for the keyword to be absent rather than present., defaults to False
:param str, optional hostname: Hostname, defaults to None
:param int, optional packetSize: Packet Size, defaults to None
:param int, optional port: Port, ``type`` :attr:`~.MonitorType.DNS` defaults to ``53`` and ``type`` :attr:`~.MonitorType.RADIUS` defaults to ``1812``
:param str, optional dns_resolve_server: Resolver Server, defaults to "1.1.1.1"
:param str, optional dns_resolve_type: Resource Record Type, defaults to "A"
:param str, optional dns_resolve_type: Resource Record Type, defaults to "A". Available values are:
- "A"
- "AAAA"
- "CAA"
- "CNAME"
- "MX"
- "NS"
- "PTR"
- "SOA"
- "SRV"
- "TXT"
:param str, optional mqttUsername: MQTT Username, defaults to None
:param str, optional mqttPassword: MQTT Password, defaults to None
:param str, optional mqttTopic: MQTT Topic, defaults to None
@ -64,6 +82,29 @@ def monitor_docstring(mode) -> str:
:param str, optional radiusCalledStationId: Called Station Id. Identifier of the called device., defaults to None
:param str, optional radiusCallingStationId: Calling Station Id. Identifier of the calling device., defaults to None
:param str, optional game: Game, defaults to None
:param bool, optional gamedigGivenPortOnly: Gamedig: Guess Port. The port used by Valve Server Query Protocol may be different from the client port. Try this if the monitor cannot connect to your server., defaults to False
:param str, optional jsonPath: Json Query, defaults to None
:param str, optional expectedValue: Expected Value, defaults to None
:param str, optional kafkaProducerBrokers: Kafka Broker list, defaults to None
:param str, optional kafkaProducerTopic: Kafka Topic Name, defaults to None
:param str, optional kafkaProducerMessage: Kafka Producer Message, defaults to None
:param bool, optional kafkaProducerSsl: Enable Kafka SSL, defaults to False
:param bool, optional kafkaProducerAllowAutoTopicCreation: Enable Kafka Producer Auto Topic Creation, defaults to False
:param dict, optional kafkaProducerSaslOptions: Kafka SASL Options
- **mechanism** (*str*, *optional*): Mechanism, defaults to "None". Available values are:
- "None"
- "plain"
- "scram-sha-256"
- "scram-sha-512"
- "aws"
- **username** (*str*, *optional*): Username, defaults to None
- **password** (*str*, *optional*): Password, defaults to None
- **authorizationIdentity** (*str*, *optional*): Authorization Identity, defaults to None
- **accessKeyId** (*str*, *optional*): AccessKey Id, defaults to None
- **secretAccessKey** (*str*, *optional*): Secret AccessKey, defaults to None
- **sessionToken** (*str*, *optional*): Session Token, defaults to None
"""
@ -100,6 +141,8 @@ def notification_docstring(mode) -> str:
:param str, optional discordWebhookUrl: Notification option for ``type`` :attr:`~.NotificationType.DISCORD`.
:param str discordPrefixMessage: Notification option for ``type`` :attr:`~.NotificationType.DISCORD`.
:param str, optional feishuWebHookUrl: Notification option for ``type`` :attr:`~.NotificationType.FEISHU`.
:param str, optional flashdutySeverity: Notification option for ``type`` :attr:`~.NotificationType.FLASHDUTY`.
:param str flashdutyIntegrationKey: Notification option for ``type`` :attr:`~.NotificationType.FLASHDUTY`.
:param str, optional freemobileUser: Notification option for ``type`` :attr:`~.NotificationType.FREEMOBILE`.
:param str, optional freemobilePass: Notification option for ``type`` :attr:`~.NotificationType.FREEMOBILE`.
:param str, optional goAlertBaseURL: Notification option for ``type`` :attr:`~.NotificationType.GOALERT`.
@ -134,6 +177,9 @@ def notification_docstring(mode) -> str:
:param str mattermostchannel: Notification option for ``type`` :attr:`~.NotificationType.MATTERMOST`.
:param str mattermosticonemo: Notification option for ``type`` :attr:`~.NotificationType.MATTERMOST`.
:param str mattermosticonurl: Notification option for ``type`` :attr:`~.NotificationType.MATTERMOST`.
:param str, optional sender: Notification option for ``type`` :attr:`~.NotificationType.NOSTR`.
:param str, optional recipients: Notification option for ``type`` :attr:`~.NotificationType.NOSTR`.
:param str, optional relays: Notification option for ``type`` :attr:`~.NotificationType.NOSTR`.
:param str ntfyAuthenticationMethod: Notification option for ``type`` :attr:`~.NotificationType.NTFY`. Authentication Method.
:param str ntfyusername: Notification option for ``type`` :attr:`~.NotificationType.NTFY`.
:param str ntfypassword: Notification option for ``type`` :attr:`~.NotificationType.NTFY`.
@ -192,6 +238,7 @@ def notification_docstring(mode) -> str:
- ``4``: SMS SPEED - Highest priority in system. Very quick and reliable but costly (about twice of SMS FULL price).
:param str promosmsSenderName: Notification option for ``type`` :attr:`~.NotificationType.PROMOSMS`.
:param str, optional pushbulletAccessToken: Notification option for ``type`` :attr:`~.NotificationType.PUSHBULLET`.
:param str pushdeerServer: Notification option for ``type`` :attr:`~.NotificationType.PUSHDEER`.
:param str, optional pushdeerKey: Notification option for ``type`` :attr:`~.NotificationType.PUSHDEER`.
:param str, optional pushoveruserkey: Notification option for ``type`` :attr:`~.NotificationType.PUSHOVER`.
:param str, optional pushoverapptoken: Notification option for ``type`` :attr:`~.NotificationType.PUSHOVER`.
@ -214,10 +261,16 @@ def notification_docstring(mode) -> str:
:param str, optional signalNumber: Notification option for ``type`` :attr:`~.NotificationType.SIGNAL`.
:param str, optional signalRecipients: Notification option for ``type`` :attr:`~.NotificationType.SIGNAL`.
:param str, optional signalURL: Notification option for ``type`` :attr:`~.NotificationType.SIGNAL`.
:param bool slackchannelnotify: Notification option for ``type`` :attr:`~.NotificationType.SLACK`.
:param str slackchannel: Notification option for ``type`` :attr:`~.NotificationType.SLACK`.
:param str slackusername: Notification option for ``type`` :attr:`~.NotificationType.SLACK`.
:param str slackiconemo: Notification option for ``type`` :attr:`~.NotificationType.SLACK`.
:param str, optional slackwebhookURL: Notification option for ``type`` :attr:`~.NotificationType.SLACK`.
:param str smscTranslit: Notification option for ``type`` :attr:`~.NotificationType.SMSC`.
:param str, optional smscLogin: Notification option for ``type`` :attr:`~.NotificationType.SMSC`.
:param str, optional smscPassword: Notification option for ``type`` :attr:`~.NotificationType.SMSC`.
:param str, optional smscToNumber: Notification option for ``type`` :attr:`~.NotificationType.SMSC`.
:param str smscSenderName: Notification option for ``type`` :attr:`~.NotificationType.SMSC`.
:param bool smseagleEncoding: Notification option for ``type`` :attr:`~.NotificationType.SMSEAGLE`. True to send messages in unicode.
:param int smseaglePriority: Notification option for ``type`` :attr:`~.NotificationType.SMSEAGLE`. Message priority (0-9, default = 0).
:param str smseagleRecipientType: Notification option for ``type`` :attr:`~.NotificationType.SMSEAGLE`. Recipient type.
@ -275,10 +328,12 @@ def notification_docstring(mode) -> str:
:param str telegramMessageThreadID: Notification option for ``type`` :attr:`~.NotificationType.TELEGRAM`.
:param str, optional telegramBotToken: Notification option for ``type`` :attr:`~.NotificationType.TELEGRAM`.
:param str, optional twilioAccountSID: Notification option for ``type`` :attr:`~.NotificationType.TWILIO`. Account SID.
:param str twilioApiKey: Notification option for ``type`` :attr:`~.NotificationType.TWILIO`.
:param str, optional twilioAuthToken: Notification option for ``type`` :attr:`~.NotificationType.TWILIO`. Auth Token.
:param str, optional twilioToNumber: Notification option for ``type`` :attr:`~.NotificationType.TWILIO`. To Number.
:param str, optional twilioFromNumber: Notification option for ``type`` :attr:`~.NotificationType.TWILIO`. From Number.
:param str, optional webhookContentType: Notification option for ``type`` :attr:`~.NotificationType.WEBHOOK`.
:param str webhookCustomBody: Notification option for ``type`` :attr:`~.NotificationType.WEBHOOK`.
:param str webhookAdditionalHeaders: Notification option for ``type`` :attr:`~.NotificationType.WEBHOOK`.
:param str, optional webhookURL: Notification option for ``type`` :attr:`~.NotificationType.WEBHOOK`.
:param str, optional weComBotKey: Notification option for ``type`` :attr:`~.NotificationType.WECOM`.

View file

@ -3,6 +3,9 @@ from enum import Enum
class MonitorType(str, Enum):
"""Enumerate monitor types."""
GROUP = "group"
"""Group"""
HTTP = "http"
"""HTTP(s)"""
@ -16,6 +19,9 @@ class MonitorType(str, Enum):
KEYWORD = "keyword"
"""HTTP(s) - Keyword"""
JSON_QUERY = "json-query"
"""HTTP(s) - Json Query"""
GRPC_KEYWORD = "grpc-keyword"
"""gRPC(s) - Keyword"""
@ -25,6 +31,9 @@ class MonitorType(str, Enum):
DOCKER = "docker"
"""Docker Container"""
REAL_BROWSER = "real-browser"
"""HTTP(s) - Browser Engine (Chrome/Chromium)"""
PUSH = "push"
"""Push"""
@ -37,6 +46,9 @@ class MonitorType(str, Enum):
MQTT = "mqtt"
"""MQTT"""
KAFKA_PRODUCER = "kafka-producer"
"""Kafka Producer"""
SQLSERVER = "sqlserver"
"""Microsoft SQL Server"""
@ -55,5 +67,5 @@ class MonitorType(str, Enum):
REDIS = "redis"
"""Redis"""
GROUP = "group"
"""Group"""
TAILSCALE_PING = "tailscale-ping"
"""Tailscale Ping"""

View file

@ -31,6 +31,9 @@ class NotificationType(str, Enum):
FEISHU = "Feishu"
"""Feishu"""
FLASHDUTY = "FlashDuty"
"""FlashDuty"""
FREEMOBILE = "FreeMobile"
"""FreeMobile (mobile.free.fr)"""
@ -67,6 +70,9 @@ class NotificationType(str, Enum):
MATTERMOST = "mattermost"
"""Mattermost"""
NOSTR = "nostr"
"""Nostr"""
NTFY = "ntfy"
"""Ntfy"""
@ -115,6 +121,9 @@ class NotificationType(str, Enum):
SLACK = "slack"
"""Slack"""
SMSC = "smsc"
"""SMSC"""
SMSEAGLE = "SMSEagle"
"""SMSEagle"""
@ -200,6 +209,10 @@ notification_provider_options = {
NotificationType.FEISHU: dict(
feishuWebHookUrl=dict(type="str", required=True),
),
NotificationType.FLASHDUTY: dict(
flashdutySeverity=dict(type="str", required=True),
flashdutyIntegrationKey=dict(type="str", required=False),
),
NotificationType.FREEMOBILE: dict(
freemobileUser=dict(type="str", required=True),
freemobilePass=dict(type="str", required=True),
@ -258,6 +271,11 @@ notification_provider_options = {
mattermosticonemo=dict(type="str", required=False),
mattermosticonurl=dict(type="str", required=False),
),
NotificationType.NOSTR: dict(
sender=dict(type="str", required=True),
recipients=dict(type="str", required=True),
relays=dict(type="str", required=True),
),
NotificationType.NTFY: dict(
ntfyAuthenticationMethod=dict(type="str", required=False),
ntfyusername=dict(type="str", required=False),
@ -310,6 +328,7 @@ notification_provider_options = {
pushbulletAccessToken=dict(type="str", required=True),
),
NotificationType.PUSHDEER: dict(
pushdeerServer=dict(type="str", required=False),
pushdeerKey=dict(type="str", required=True),
),
NotificationType.PUSHOVER: dict(
@ -346,11 +365,19 @@ notification_provider_options = {
signalURL=dict(type="str", required=True),
),
NotificationType.SLACK: dict(
slackchannelnotify=dict(type="bool", required=False),
slackchannel=dict(type="str", required=False),
slackusername=dict(type="str", required=False),
slackiconemo=dict(type="str", required=False),
slackwebhookURL=dict(type="str", required=True),
),
NotificationType.SMSC: dict(
smscTranslit=dict(type="str", required=False),
smscLogin=dict(type="str", required=True),
smscPassword=dict(type="str", required=True),
smscToNumber=dict(type="str", required=True),
smscSenderName=dict(type="str", required=False),
),
NotificationType.SMSEAGLE: dict(
smseagleEncoding=dict(type="bool", required=False),
smseaglePriority=dict(type="int", required=False),
@ -409,12 +436,14 @@ notification_provider_options = {
),
NotificationType.TWILIO: dict(
twilioAccountSID=dict(type="str", required=True),
twilioApiKey=dict(type="str", required=False),
twilioAuthToken=dict(type="str", required=True),
twilioToNumber=dict(type="str", required=True),
twilioFromNumber=dict(type="str", required=True),
),
NotificationType.WEBHOOK: dict(
webhookContentType=dict(type="str", required=True),
webhookCustomBody=dict(type="str", required=False),
webhookAdditionalHeaders=dict(type="str", required=False),
webhookURL=dict(type="str", required=True),
),