Compare commits

...

4 commits

Author SHA1 Message Date
sinavir
0ee4239e62 feat: add helper functions to filter probes in lib 2024-04-21 13:58:31 +02:00
sinavir
1c73542d29 feat: add status page declarative setup 2024-04-21 13:58:31 +02:00
sinavir
456f923905 feat: add host, password and username handling 2024-04-21 13:58:31 +02:00
sinavir
ae50084fcb fix: add optional client dependencies for socketio 2024-04-21 13:58:31 +02:00
6 changed files with 111 additions and 12 deletions

View file

@ -2,6 +2,18 @@
rec {
mkFqdn = _: cfg: cfg.networking.fqdn;
probesWithTag =
{
name,
value ? null,
}:
probesConfig:
lib.filterAttrs (
k: v: lib.any (tag: tag.name == name && (value == null || tag.value == value)) v.tags
) probesConfig.monitors;
probesWithType = type: probesConfig: lib.filterAttrs (_: v: v.type == type) probesConfig.monitors;
fromHive =
{
builder,

View file

@ -14,6 +14,10 @@ in
json = lib.mkOption { type = lib.types.package; };
script = lib.mkOption { type = lib.types.package; };
};
host = lib.mkOption {
default = null;
type = with lib.types; nullOr str;
};
extraFlags = lib.mkOption {
default = [ ];
example = [ "--scrape-http-keywords" ];
@ -36,17 +40,23 @@ in
type = with lib.types; attrsOf probesFormat.type;
default = { };
};
status_pages = lib.mkOption {
type = with lib.types; attrsOf probesFormat.type;
default = { };
};
};
};
config.statelessUptimeKuma = {
lib = import ../lib { inherit lib; };
extraFlags = lib.optional (cfg.host != null) "--host ${cfg.host}";
build = {
json = probesFormat.generate "probes.json" cfg.probesConfig;
script = pkgs.writeShellApplication {
name = "deploy-uptime-kuma-probes";
runtimeInputs = [ pkgs.statelessUptimeKuma ];
text = ''
stateless-uptime-kuma apply-json -f ${cfg.build.json} ${builtins.concatStringsSep " " cfg.extraFlags}
args=("$@")
stateless-uptime-kuma apply-json -f ${cfg.build.json} ${builtins.concatStringsSep " " cfg.extraFlags} "''${args[@]}"
'';
};
};

View file

@ -47,14 +47,35 @@ def cli():
help="Don't automatically create tags if not in tags section of input",
default=False,
)
def apply_json(file, scrape_http_keywords, no_autocreate_tags, keywords_fallback):
@click.option(
"--username",
prompt=True,
)
@click.option(
"--host",
prompt=True,
)
@click.option(
"--password",
prompt=True,
hide_input=True,
)
def apply_json(
file,
scrape_http_keywords,
no_autocreate_tags,
keywords_fallback,
username,
password,
host,
):
"""
Apply json probes
"""
logger.debug(
f"Flags value:\n - scrape_http_keywords: {scrape_http_keywords}\n - no_autocreate_tags: {no_autocreate_tags}\n - keywords_fallback: {keywords_fallback}"
)
with UptimeKumaApi("http://localhost:3001") as api:
with UptimeKumaApi(host) as api:
logging.debug("Reading json")
data = json.load(file)
logging.debug("Parsing json")
@ -62,9 +83,9 @@ def apply_json(file, scrape_http_keywords, no_autocreate_tags, keywords_fallback
if scrape_http_keywords:
hydrate_http_probes(tree)
logging.debug("Sync probes")
api.login("admin", "123456789a")
api.login(username, password)
Manager(api, tree).process()
if __name__ == "__main__":
cli()
cli(auto_envvar_prefix="STATELESS_UPTIME_KUMA")

View file

@ -5,7 +5,7 @@ Classes to generate the item tree from json spec
import logging
import sys
from .uptime_kuma import Monitor, Notification, Tag
from .uptime_kuma import Monitor, Notification, StatusPage, Tag # type: ignore
logger = logging.getLogger(__name__)
@ -44,8 +44,25 @@ def from_dict(api, tree, autocreate_tags=True):
]
monitor_kwargs["notifications"] = associated_notifications
indexed_monitors[monitor_name] = Monitor(api, monitor_name, **monitor_kwargs)
status_pages = tree.get("status_pages", [])
indexed_status_pages = {}
for slug, kwargs in status_pages.items():
for group in kwargs.get("publicGroupList", []):
if "monitorList" in group:
monitorList = []
for monitor in group["monitorList"]:
if monitor not in indexed_monitors:
logger.error(
"Fatal: status page is referencing a monitor that doesn't exist"
)
sys.exit(1)
monitorList.append(indexed_monitors[monitor])
group["monitorList"] = monitorList
indexed_status_pages[slug] = StatusPage(api, slug, **kwargs)
return {
"monitors": indexed_monitors.values(),
"tags": indexed_tags.values(),
"notifications": indexed_notifications.values(),
"status_pages": indexed_status_pages.values(),
}

View file

@ -18,6 +18,7 @@ class Manager:
self.sync_tags()
self.sync_notifications()
self.sync_monitors()
self.sync_status_pages()
self.save()
def save(self):
@ -28,20 +29,25 @@ class Manager:
def sync_monitors(self):
old = self.api.get_monitors()
new = self.target_tree.get("monitors", [])
self.sync(new, old)
self.sync(new, old, "name")
def sync_notifications(self):
old = self.api.get_notifications()
new = self.target_tree.get("notifications", [])
self.sync(new, old)
self.sync(new, old, "name")
def sync_tags(self):
old = self.api.get_tags()
new = self.target_tree.get("tags", [])
self.sync(new, old)
self.sync(new, old, "name")
def sync(self, new, old):
indexed_old = {elem["name"]: elem for elem in old}
def sync_status_pages(self):
old = self.api.get_status_pages()
new = self.target_tree.get("status_pages", [])
self.sync(new, old, "slug")
def sync(self, new, old, pk):
indexed_old = {elem[pk]: elem for elem in old}
for k in new:
if k.name in indexed_old:
k.id = indexed_old[k.name]["id"]
@ -194,3 +200,36 @@ class Notification(Item):
def __repr__(self):
return f"Notification({str(self)})"
class StatusPage(Item):
def __init__(self, api, name, id=None, old_name=None, **kwargs):
super().__init__(api, name, id, old_name)
self.kwargs = kwargs
def save(self):
if self.saved:
return
logger.debug(f"Saving {repr(self)}")
if self.id is None:
self.api.add_status_page(
slug=self.name,
title=self.kwargs["title"],
)
rslt = self.api.get_status_page(self.name)
self.id = rslt["id"]
kwargs = self.kwargs
for group in kwargs.get("publicGroupList", []):
if "monitorList" in group:
monitorList = []
for monitor in group["monitorList"]:
monitorList.append({"id": monitor.id})
group["monitorList"] = monitorList
self.api.save_status_page(
slug=self.name,
**kwargs,
)
self.saved = True
def __repr__(self):
return f"StatusPage({str(self)})"

View file

@ -30,7 +30,7 @@ buildPythonPackage rec {
packaging
python-socketio
requests
];
] ++ python-socketio.optional-dependencies.client;
pythonImportsCheck = [ "uptime_kuma_api" ];