#!/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 = { "blabber.im": [], "ChatSecure": ["chatsecure"], "Conv6ations": ["Conversations with IPv6", "Conv6ations for Sum7"], "Conversations": [], "Dino": ["dino"], "Gajim": ["gajim"], "jitsi": [], "Monal": [], "Pix-Art Messenger": [], "poezio": [], "profanity": [], "Psi+": [], "Xabber": ["xabber", "xabber-android"], } 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))