-
Notifications
You must be signed in to change notification settings - Fork 0
/
supervisord_xmlrpc.py
93 lines (69 loc) · 2.87 KB
/
supervisord_xmlrpc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import sys
import socket
import logging
import os.path
import xmlrpclib
from supervisor.xmlrpc import SupervisorTransport
LOGGER=logging.getLogger(__name__)
SUPERVISOR_SOCK="etc/supervisor.sock"
def connect_domain_socket(env_path):
"""Connects to a domain socket using the env_path"""
path = os.path.join(env_path, SUPERVISOR_SOCK)
transport = SupervisorTransport(None, None,
serverurl="unix://%s" % (path,))
# xmlrpc needs a URI that starts with http(s) even if it is a dummy
dummy_uri = "http://127.0.0.1"
proxy = xmlrpclib.ServerProxy(dummy_uri, transport)
return proxy
class DomainSocketSupervisor(object):
def __init__(self, env_path=sys.exec_prefix):
"""Defaults to current environment as the path to find supervisord"""
self._logger = logging.getLogger(self.__class__.__name__)
self._env_path = env_path
self._conn = connect_domain_socket(env_path)
try:
self._construct_methods_from_server()
except socket.error as e:
if e.errno == 2:
self._logger.critical("Cannot find domain socket. Supervisord "
"isn't running or is misconfigured")
raise
def list_methods(self):
return self.system.listMethods()
def _get_methods(self):
return self._conn.system.listMethods()
def _construct_methods_from_server(self):
"""
Lookup all XML-RPC methods using the system.listMethods()
call and build up pseudo attributes and methods to allow
tab-completion and normal python function calls
"""
# Add actual methods to class
for method in self._get_methods():
#self._logger.debug("Adding method {} to class attributes".format(
# method))
# Methods have namespaces, and Python needs actual objects
# delmited by ".". Create dummy objects and assign methods there
# This only works 2 layers deep: self.system.listMethods() e.g.
obj, method_name = method.split(".")
# create new Dummy or use existing one
temp = self.__dict__.get(obj, Dummy(obj))
# add new method to dummy obj
temp.set_method(method_name, getattr(self._conn, method))
self.__dict__[obj] = temp
class Dummy(object):
def __init__(self, name):
self._name = name
def set_method(self, name, method):
self.__dict__[name] = method
def __getattr__(self, name):
"Clean attribute error to hide Dummy name"
raise AttributeError("'%s' object has no attribute '%s'" %
(self._name, name))
def main():
from muster.logger import setup_logging
setup_logging()
p = DomainSocketSupervisor()
p.system.listMethods()
if __name__ == "__main__":
main()