2021-06-13 10:58:39 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import os
|
2023-08-17 07:40:19 +00:00
|
|
|
import sys
|
2021-06-13 10:58:39 +00:00
|
|
|
from motor.motor_asyncio import AsyncIOMotorClient
|
2023-08-17 07:40:19 +00:00
|
|
|
from sanic import Sanic, exceptions
|
|
|
|
from sanic.log import logger
|
2021-06-13 10:58:39 +00:00
|
|
|
|
2021-06-13 11:11:44 +00:00
|
|
|
MONGODB_HOST = os.getenv("MONGODB_HOST")
|
|
|
|
if not MONGODB_HOST:
|
|
|
|
raise ValueError("No MONGODB_HOST specified")
|
2021-06-13 10:58:39 +00:00
|
|
|
|
|
|
|
PROMETHEUS_BEARER_TOKEN = os.getenv("PROMETHEUS_BEARER_TOKEN")
|
|
|
|
if not PROMETHEUS_BEARER_TOKEN:
|
|
|
|
raise ValueError("No PROMETHEUS_BEARER_TOKEN specified")
|
|
|
|
|
|
|
|
app = Sanic("exporter")
|
2023-08-17 07:40:19 +00:00
|
|
|
usernames = list(set(sys.argv[1:]))
|
2021-06-13 10:58:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.listener("before_server_start")
|
|
|
|
async def setup_db(app, loop):
|
2021-06-13 11:11:44 +00:00
|
|
|
app.ctx.db = AsyncIOMotorClient(MONGODB_HOST).get_default_database()
|
2021-06-13 10:58:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def wrap(i, prefix="wildduck_"):
|
|
|
|
metrics_seen = set()
|
|
|
|
async for name, tp, value, labels in i:
|
|
|
|
if name not in metrics_seen:
|
|
|
|
yield "# TYPE %s %s" % (name, tp)
|
|
|
|
metrics_seen.add(name)
|
|
|
|
yield "%s%s %d" % (
|
|
|
|
prefix + name,
|
|
|
|
("{%s}" % ",".join(["%s=\"%s\"" % j for j in labels.items()]) if labels else ""),
|
|
|
|
value)
|
|
|
|
|
|
|
|
|
|
|
|
async def fetch():
|
2023-08-17 07:40:19 +00:00
|
|
|
last_login = {}
|
|
|
|
user_labels = {}
|
|
|
|
args = []
|
|
|
|
if usernames:
|
|
|
|
args.append({"username": {"$in": usernames}})
|
|
|
|
async for u in app.ctx.db.users.find(*args):
|
2021-06-13 10:58:39 +00:00
|
|
|
labels = {
|
|
|
|
"username": u["username"],
|
|
|
|
"email": u["address"],
|
|
|
|
}
|
2023-08-17 07:40:19 +00:00
|
|
|
user_labels[u["_id"]] = labels
|
|
|
|
|
2021-06-13 10:58:39 +00:00
|
|
|
if u["lastLogin"]["time"]:
|
2023-08-17 07:40:19 +00:00
|
|
|
last_login[u["_id"]] = u["lastLogin"]["time"]
|
|
|
|
|
2021-06-13 10:58:39 +00:00
|
|
|
if u["storageUsed"]:
|
|
|
|
yield "storage_used", "gauge", u["storageUsed"], labels
|
|
|
|
if u["targets"]:
|
|
|
|
yield "forwarding_addresses", "gauge", len(u["targets"]), labels
|
|
|
|
yield "account_enabled", "gauge", not u["disabled"], labels
|
|
|
|
|
2023-08-17 07:40:19 +00:00
|
|
|
# Merge application specific passwords last used timestamps
|
|
|
|
async for a in app.ctx.db.asps.find({"user": {"$in": list(last_login.keys())}}):
|
2023-08-17 08:05:57 +00:00
|
|
|
if a["used"] and a["used"] > last_login[a["user"]]:
|
2023-08-17 07:40:19 +00:00
|
|
|
last_login[a["user"]] = a["used"]
|
|
|
|
|
|
|
|
for user, dt in last_login.items():
|
|
|
|
yield "last_login", "gauge", dt.timestamp(), user_labels[user]
|
|
|
|
|
2021-06-13 10:58:39 +00:00
|
|
|
|
|
|
|
@app.route("/metrics")
|
|
|
|
async def view_export(request):
|
|
|
|
if request.token != PROMETHEUS_BEARER_TOKEN:
|
|
|
|
raise exceptions.Forbidden("Invalid bearer token")
|
2023-08-17 07:40:19 +00:00
|
|
|
response = await request.respond(content_type="text/plain")
|
|
|
|
async for line in wrap(fetch()):
|
|
|
|
await response.send(line + "\n")
|
2021-06-13 10:58:39 +00:00
|
|
|
|
|
|
|
|
2023-08-17 06:24:32 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
app.run(host="0.0.0.0", port=3001, single_process=True)
|