From 17a6585ea4515a8860206a35a2988910cd510535 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Thu, 17 Oct 2019 05:16:28 +0200 Subject: [PATCH] first xml rpc api --- ejabberdrpc.py | 210 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100755 ejabberdrpc.py diff --git a/ejabberdrpc.py b/ejabberdrpc.py new file mode 100755 index 0000000..4dd089b --- /dev/null +++ b/ejabberdrpc.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from xmlrpc import client +import ipaddress + +class EjabberdMetrics(): + """ + class to fetch metrics per xmlrpc + """ + def __init__(self, url, login = None): + self._server = client.ServerProxy(url) + self._login = login + + def _cmd(self, command, data): + fn = getattr(self._server, command) + if self._login is not None: + return fn(self._login, data) + return fn(data) + + def fetch_onlineuser(self): + data = None + tmp = self._cmd("connected_users_info", {}) + if "connected_users_info" not in tmp: + return None + data = [] + for c in tmp["connected_users_info"]: + if "session" not in c: + continue + user = {} + for attrs in c["session"]: + for k, v in attrs.items(): + user[k] = v + data.append(user) + return data + + def fetch_nodes(self): + result = self._cmd("list_cluster",{}) + if "nodes" not in result: + return None + data = [] + for node in result["nodes"]: + data.append(node["node"]) + return data + + def fetch_vhosts(self): + result = self._cmd("registered_vhosts",{}) + if "vhosts" not in result: + return None + data = [] + for vhost in result["vhosts"]: + data.append(vhost["vhost"]) + return data + + def fetch_registered(self, vhost=None): + if vhost is None: + result = self._cmd("stats", {"name":"registeredusers"}) + if "stat" in result: + return result["stat"] + else: + result = self._cmd("stats_host", {"name":"registeredusers", "host": vhost}) + if "stat" in result: + return result["stat"] + + 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() + for vhost in self._vhosts: + self._registered[vhost] = self.fetch_registered(vhost) + # online user + self._onlineuser = self.fetch_onlineuser() + + + 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): + def client(r): + clientmap = { + "Conv6ations for Sum7": ["Conversations with IPv6"], + "Conversations": [], + "Pix-Art Messenger": [], + "jitsi": [], + "dino": [], + "poezio": [], + } + for client,names in clientmap.items(): + for c in names: + if c in r: + return client + if client in r: + return client + return "other" + return self.get_online_by("resource", parse=client, vhost=vhost, node=node) + + def get_online_by_ipversion(self, vhost=None, node=None): + # rfc6052: IPv6 Addressing of IPv4/IPv6 Translators + nat64 = ipaddress.ip_network("64:ff9b::/96") + 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 + return self.get_online_by("ip", parse=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(vhost) + return self._registered[vhost] + + def get_vhosts(self): + if not hasattr(self, "_vhosts"): + self._vhosts = self.fetch_vhosts() + return self._vhosts + + def get_vhost_metrics(self, vhost): + data = {} + data["registered"] = self.get_registered(vhost) + data["online_by_status"] = self.get_online_by_status(vhost) + data["online_by_client"] = self.get_online_by_client(vhost) + data["online_by_ipversion"] = self.get_online_by_ipversion(vhost) + data["online_by_connection"] = self.get_online_by_connection(vhost) + + data["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 = {} + data["online_by_status"] = self.get_online_by_status(node=node) + data["online_by_client"] = self.get_online_by_client(node=node) + data["online_by_ipversion"] = self.get_online_by_ipversion(node=node) + data["online_by_connection"] = self.get_online_by_connection(node=node) + + data["online_by_vhost"] = self.get_online_by_vhost(node=node) + return data + + def get_all(self): + data = {} + data["registered"] = self.get_registered() + data["online_by_status"] = self.get_online_by_status() + data["online_by_client"] = self.get_online_by_client() + data["online_by_ipversion"] = self.get_online_by_ipversion() + data["online_by_connection"] = self.get_online_by_connection() + + data["online_by_node"] = self.get_online_by_node() + data["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["nodes"] = nodes + + return data + + +if __name__ == "__main__": + from json import dumps + metric = EjabberdMetrics("http://[::1]:4560") + + data = metric.get_all() + print(dumps(data, indent=True))