272 lines
8.7 KiB
Python
Executable File
272 lines
8.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
import ipaddress
|
|
|
|
from calls import EjabberdApiCalls
|
|
|
|
# rfc6052: IPv6 Addressing of IPv4/IPv6 Translators
|
|
nat64 = ipaddress.ip_network("64:ff9b::/96")
|
|
|
|
|
|
class EjabberdMetrics(EjabberdApiCalls):
|
|
"""
|
|
class to fetch metrics per xmlrpc
|
|
"""
|
|
|
|
def __init__(self, url, login=None, api="rpc", muc_host: str = "conference"):
|
|
# init ejabberd api
|
|
super().__init__(url, login, api)
|
|
|
|
# variables
|
|
self.muc_host = muc_host
|
|
|
|
def _client(self, resource):
|
|
clientmap = {
|
|
"Conv6ations": ["Conversations with IPv6", "Conv6ations for Sum7"],
|
|
"Conversations": [],
|
|
"Pix-Art Messenger": [],
|
|
"Gajim": ["gajim"],
|
|
"Psi+": [],
|
|
"jitsi": [],
|
|
"Dino": ["dino"],
|
|
"poezio": [],
|
|
"profanity": [],
|
|
"Xabber": ["xabber", "xabber-android"],
|
|
"ChatSecure": ["chatsecure"],
|
|
"Monal": [],
|
|
}
|
|
|
|
for client, names in clientmap.items():
|
|
for c in names:
|
|
if c in resource:
|
|
return client
|
|
if client in resource:
|
|
return client
|
|
return "other"
|
|
|
|
@staticmethod
|
|
def _ipversion(ip):
|
|
addr = ipaddress.ip_address(ip)
|
|
if addr.version == 6:
|
|
if addr.ipv4_mapped:
|
|
return 4
|
|
if addr in nat64:
|
|
return 4
|
|
return addr.version
|
|
|
|
def update(self):
|
|
# nodes
|
|
self._nodes = self.fetch_nodes()
|
|
|
|
# vhosts
|
|
self._vhosts = self.fetch_vhosts()
|
|
|
|
# registered
|
|
if not hasattr(self, "_registered"):
|
|
self._registered = {}
|
|
self._registered[None] = self.fetch_registered_count()
|
|
|
|
# muc
|
|
if not hasattr(self, "_muc"):
|
|
self._muc = {}
|
|
self._muc[None] = self.fetch_muc_count(muc_host=self.muc_host)
|
|
|
|
# registered + muc
|
|
for vhost in self._vhosts:
|
|
self._registered[vhost] = self.fetch_registered_count(vhost)
|
|
self._muc[vhost] = self.fetch_muc_count(vhost, muc_host=self.muc_host)
|
|
|
|
# online user
|
|
self._onlineuser = self.fetch_onlineuser()
|
|
|
|
# s2s
|
|
self._s2s_in = self.fetch_s2s_in()
|
|
self._s2s_out = self.fetch_s2s_out()
|
|
|
|
# misc
|
|
self._uptime = self.fetch_uptime()
|
|
self._processes = self.fetch_processes()
|
|
|
|
def get_online_by(self, by="node", parse=None, vhost=None, node=None):
|
|
parser = parse or (lambda a: a)
|
|
if not hasattr(self, "_onlineuser"):
|
|
self._onlineuser = self.fetch_onlineuser()
|
|
data = {}
|
|
|
|
for conn in self._onlineuser:
|
|
if vhost is not None and vhost not in conn["jid"]:
|
|
continue
|
|
if node is not None and node != conn["node"]:
|
|
continue
|
|
if by not in conn:
|
|
continue
|
|
value = parser(conn[by])
|
|
if value not in data:
|
|
data[value] = 1
|
|
else:
|
|
data[value] += 1
|
|
return data
|
|
|
|
def get_online_by_node(self, vhost=None):
|
|
return self.get_online_by("node", vhost=vhost)
|
|
|
|
def get_online_by_vhost(self, node=None):
|
|
return self.get_online_by("jid", parse=lambda jid: jid[jid.find("@") + 1 : jid.find("/")], node=node)
|
|
|
|
def get_online_by_status(self, vhost=None, node=None):
|
|
return self.get_online_by("status", vhost=vhost, node=node)
|
|
|
|
def get_online_by_connection(self, vhost=None, node=None):
|
|
return self.get_online_by("connection", vhost=vhost, node=node)
|
|
|
|
def get_online_by_client(self, vhost=None, node=None):
|
|
return self.get_online_by("resource", parse=self._client, vhost=vhost, node=node)
|
|
|
|
def get_online_by_ipversion(self, vhost=None, node=None):
|
|
return self.get_online_by("ip", parse=self._ipversion, vhost=vhost, node=node)
|
|
|
|
def get_online_client_by(self, by="ip", parse=None, vhost=None, node=None):
|
|
parser = parse or self._ipversion
|
|
if not hasattr(self, "_onlineuser"):
|
|
self._onlineuser = self.fetch_onlineuser()
|
|
data = {}
|
|
|
|
for conn in self._onlineuser:
|
|
client = "other"
|
|
if "resource" in conn:
|
|
client = self._client(conn["resource"])
|
|
if client not in data:
|
|
data[client] = {}
|
|
if vhost is not None and vhost not in conn["jid"]:
|
|
continue
|
|
if node is not None and node != conn["node"]:
|
|
continue
|
|
if by not in conn:
|
|
continue
|
|
value = parser(conn[by])
|
|
if value not in data[client]:
|
|
data[client][value] = 1
|
|
else:
|
|
data[client][value] += 1
|
|
return data
|
|
|
|
def get_online_client_by_ipversion(self, vhost=None, node=None):
|
|
return self.get_online_client_by("ip", parse=self._ipversion, vhost=vhost, node=node)
|
|
|
|
def get_registered(self, vhost=None):
|
|
if not hasattr(self, "_registered"):
|
|
self._registered = {}
|
|
if vhost not in self._registered:
|
|
self._registered[vhost] = self.fetch_registered_count(vhost)
|
|
return self._registered[vhost]
|
|
|
|
def get_muc(self, vhost=None):
|
|
if not hasattr(self, "_muc"):
|
|
self._muc = {}
|
|
if vhost not in self._muc:
|
|
self._muc[vhost] = self.fetch_muc_count(vhost, muc_host=self.muc_host)
|
|
return self._muc[vhost]
|
|
|
|
def get_vhosts(self):
|
|
if not hasattr(self, "_vhosts"):
|
|
self._vhosts = self.fetch_vhosts()
|
|
return self._vhosts
|
|
|
|
def get_s2s_in(self):
|
|
if not hasattr(self, "_s2s_in"):
|
|
self._s2s_in = self.fetch_s2s_in()
|
|
return self._s2s_in
|
|
|
|
def get_s2s_out(self):
|
|
if not hasattr(self, "_s2s_out"):
|
|
self._s2s_out = self.fetch_s2s_out()
|
|
return self._s2s_out
|
|
|
|
def get_uptime(self):
|
|
if not hasattr(self, "_uptime"):
|
|
self._uptime = self.fetch_uptime()
|
|
return self._uptime
|
|
|
|
def get_processes(self):
|
|
if not hasattr(self, "_processes"):
|
|
self._processes = self.fetch_processes()
|
|
return self._processes
|
|
|
|
def get_vhost_metrics(self, vhost):
|
|
data = {
|
|
"registered": self.get_registered(vhost),
|
|
"muc": self.get_muc(vhost),
|
|
"online_by_status": self.get_online_by_status(vhost),
|
|
"online_by_client": self.get_online_by_client(vhost),
|
|
"online_by_ipversion": self.get_online_by_ipversion(vhost),
|
|
"online_by_connection": self.get_online_by_connection(vhost),
|
|
"online_by_node": self.get_online_by_node(vhost),
|
|
}
|
|
|
|
return data
|
|
|
|
def get_nodes(self):
|
|
if not hasattr(self, "_nodes"):
|
|
self._nodes = self.fetch_nodes()
|
|
return self._nodes
|
|
|
|
def get_node_metrics(self, node):
|
|
data = {
|
|
"online_by_status": self.get_online_by_status(node=node),
|
|
"online_by_client": self.get_online_by_client(node=node),
|
|
"online_by_ipversion": self.get_online_by_ipversion(node=node),
|
|
"online_by_connection": self.get_online_by_connection(node=node),
|
|
"online_by_vhost": self.get_online_by_vhost(node=node),
|
|
}
|
|
|
|
return data
|
|
|
|
def get_all(self):
|
|
data = {
|
|
"registered": self.get_registered(),
|
|
"muc": self.get_muc(),
|
|
"s2s_in": self.get_s2s_in(),
|
|
"s2s_out": self.get_s2s_out(),
|
|
"uptime": self.get_uptime(),
|
|
"processes": self.get_processes(),
|
|
"online_by_status": self.get_online_by_status(),
|
|
"online_by_client": self.get_online_by_client(),
|
|
"online_by_ipversion": self.get_online_by_ipversion(),
|
|
"online_by_connection": self.get_online_by_connection(),
|
|
"online_by_node": self.get_online_by_node(),
|
|
"online_by_vhost": self.get_online_by_vhost(),
|
|
}
|
|
|
|
vhosts = {}
|
|
for host in self.get_vhosts():
|
|
vhosts[host] = self.get_vhost_metrics(host)
|
|
data["vhosts"] = vhosts
|
|
|
|
nodes = {}
|
|
for node in self.get_nodes():
|
|
nodes[node] = self.get_node_metrics(node)
|
|
|
|
data["online_client_by_ipversion"] = self.get_online_client_by_ipversion()
|
|
data["nodes"] = nodes
|
|
|
|
return data
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import json
|
|
from config import Config
|
|
|
|
# load config
|
|
config = Config()
|
|
|
|
# credentials and parameters
|
|
url = config.get("url", default="http://localhost:5280/api")
|
|
login = config.get("login", default=None)
|
|
api = config.get("api", default="rest")
|
|
|
|
# init handler
|
|
metrics = EjabberdMetrics(url, login, api)
|
|
|
|
data = metrics.get_all()
|
|
print(json.dumps(data, indent=True))
|