Browse Source

Big reorganization:

- Move all packages into "src" directory.

- Use setuptools rather than distutils for setup.py

- Add configuration knob for specifying rpc interface namespaces.
Chris McDonough 18 years ago
parent
commit
dbc77205e4
7 changed files with 93 additions and 61 deletions
  1. 3 0
      sample.conf
  2. 13 26
      setup.py
  3. 1 1
      src/supervisor/__init__.py
  4. 14 1
      src/supervisor/http.py
  5. 31 1
      src/supervisor/options.py
  6. 23 22
      src/supervisor/tests.py
  7. 8 10
      src/supervisor/xmlrpc.py

+ 3 - 0
sample.conf

@@ -23,6 +23,9 @@ minprocs=200                ; (min. avail process descriptors;default 200)
 ;environment=KEY=value       ; (key value pairs to add to environment)
 ;strip_ansi=false            ; (strip ansi escape codes from stdout; def. false)
 
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.xmlrpc:make_main_rpcinterface
+
 [supervisorctl]
 serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
 ;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket

+ 13 - 26
setup.py

@@ -1,8 +1,10 @@
 
 __revision__ = '$Id$'
 
+import os
 import sys
 import string
+
 version, extra = string.split(sys.version, ' ', 1)
 maj, minor = string.split(version, '.', 1)
 
@@ -11,8 +13,8 @@ if not maj[0] >= '2' and minor[0] >= '3':
            "install it using version %s.  Please install with a "
            "supported version" % version)
 
-from distutils.core import setup
-
+from setuptools import setup, find_packages
+here = os.path.abspath(os.path.normpath(os.path.dirname(__file__)))
 
 DESC = """\
 Supervisor is a client/server system that allows its users to
@@ -29,13 +31,11 @@ CLASSIFIERS = [
     'Topic :: System :: Systems Administration',
     ]
 
-from options import VERSION
-
 dist = setup(
     name = 'supervisor',
-    version = VERSION,
-    license = 'ZPL/BSD (see LICENSES.txt)',
-    url = 'http://www.plope.com/software',
+    version = '2.3b1',
+    license = 'ZPL 2.0/BSD (see LICENSES.txt)',
+    url = 'http://www.plope.com/software/supervisor2',
     description = "A system for controlling process state under UNIX",
     long_description= DESC,
     platform = 'UNIX',
@@ -44,23 +44,10 @@ dist = setup(
     author_email = "chrism@plope.com",
     maintainer = "Chris McDonough",
     maintainer_email = "chrism@plope.com",
-    scripts=['supervisord', 'supervisorctl'],
-    packages = ['supervisor', 'supervisor.medusa', 'supervisor.meld3',
-                'supervisor.meld3.elementtree'],
-    package_dir = {'supervisor':'.'},
-    # package_data doesn't work under 2.3
-    package_data= {'supervisor':['ui/*.gif', 'ui/*.css', 'ui/*.html']},
+    package_dir = {'':'src'},
+    packages = find_packages(os.path.join(here, 'src')),
+    scripts=['src/supervisor/supervisord', 'src/supervisor/supervisorctl'],
+    include_package_data = True,
+    zip_safe = False,
+    namespace_packages = ['supervisor'],
     )
-
-if __name__ == '__main__':
-    # if pre-2.4 distutils was a joke, i suspect nobody laughed
-    if minor[0] <= '3':
-        if 'install' in sys.argv:
-            from distutils import dir_util
-            import os
-            pkg_dir = dist.command_obj['install'].install_purelib
-            for dirname in ['ui']:
-                dir_util.copy_tree(
-                    os.path.join(dirname),
-                    os.path.join(pkg_dir, 'supervisor',  dirname)
-                    )

+ 1 - 1
src/supervisor/__init__.py

@@ -1 +1 @@
-# poof.
+__import__('pkg_resources').declare_namespace(__name__)

+ 14 - 1
src/supervisor/http.py

@@ -748,8 +748,21 @@ def make_http_server(options, supervisord):
         raise ValueError('Cannot determine socket type %r' % family)
 
     from xmlrpc import supervisor_xmlrpc_handler
+    from xmlrpc import SystemNamespaceRPCInterface
     from web import supervisor_ui_handler
-    xmlrpchandler = supervisor_xmlrpc_handler(supervisord)
+    rpcfactories = options.configroot.supervisord.rpcinterface_factories
+
+    subinterfaces = []
+    for name, factory, d in rpcfactories:
+        try:
+            inst = factory(supervisord, **d)
+        except:
+            import traceback; traceback.print_exc()
+            raise ValueError('Could not make %s rpc interface' % name)
+        subinterfaces.append((name, inst))
+        
+    subinterfaces.append(('system', SystemNamespaceRPCInterface(subinterfaces)))
+    xmlrpchandler = supervisor_xmlrpc_handler(supervisord, subinterfaces)
     tailhandler = logtail_handler(supervisord)
     maintailhandler = mainlogtail_handler(supervisord)
     here = os.path.abspath(os.path.dirname(__file__))

+ 31 - 1
src/supervisor/options.py

@@ -17,11 +17,12 @@ import pwd
 import grp
 import resource
 import stat
+import pkg_resources
 
 from fcntl import fcntl
 from fcntl import F_SETFL, F_GETFL
 
-VERSION = '2.2b1'
+VERSION = '2.3b1'
 
 class FileHandler(logging.StreamHandler):
     """File handler which supports reopening of logs.
@@ -674,6 +675,7 @@ class ServerOptions(Options):
         section.environment = datatypes.dict_of_key_value_pairs(environment)
 
         section.programs = self.programs_from_config(config)
+        section.rpcinterface_factories = self.rpcinterfaces_from_config(config)
         return section
 
     def programs_from_config(self, config):
@@ -749,6 +751,34 @@ class ServerOptions(Options):
         programs.sort() # asc by priority
         return programs
 
+    def import_spec(self, spec):
+        return pkg_resources.EntryPoint.parse("x="+spec).load(False)
+
+    def rpcinterfaces_from_config(self, config):
+        factories = []
+        factory_key = 'supervisor.rpcinterface_factory'
+
+        for section in config.sections():
+            if not section.startswith('rpcinterface:'):
+                continue
+            options = config.options(section)
+            name = section.split(':', 1)[1]
+            realoptions = []
+            factory_spec = config.saneget(section, factory_key, None)
+            if factory_spec is None:
+                raise ValueError('section [%s] does not specify a %s'  %
+                                 (section, factory_key))
+            try:
+                factory = self.import_spec(factory_spec)
+            except ImportError:
+                raise ValueError('%s cannot be resolved within [%s]' % (
+                    factory_spec, section))
+            items = config.items(section)
+            items.remove((factory_key, factory_spec))
+            factories.append((name, factory, dict(items)))
+
+        return factories
+
     def daemonize(self):
         # To daemonize, we need to become the leader of our own session
         # (process) group.  If we do not, signals sent to our

+ 23 - 22
src/supervisor/tests.py

@@ -347,20 +347,18 @@ class TestBase(unittest.TestCase):
 class MainXMLRPCInterfaceTests(TestBase):
 
     def _getTargetClass(self):
-        return xmlrpc.RPCInterface
+        return xmlrpc.RootRPCInterface
 
     def _makeOne(self, *args, **kw):
         return self._getTargetClass()(*args, **kw)
 
     def test_ctor(self):
-        supervisord = DummySupervisor()
-        interface = self._makeOne(supervisord)
-        self.assertEqual(interface.supervisor.supervisord, supervisord)
-        self.failUnless(interface.system)
+        interface = self._makeOne([('supervisor', None)])
+        self.assertEqual(interface.supervisor, None)
 
     def test_traverse(self):
-        supervisord = DummySupervisor()
-        interface = self._makeOne(supervisord)
+        dummy = DummyRPCInterface()
+        interface = self._makeOne([('dummy', dummy)])
         from xmlrpc import traverse
         self._assertRPCError(xmlrpc.Faults.UNKNOWN_METHOD,
                              traverse, interface, 'notthere.hello', [])
@@ -368,10 +366,8 @@ class MainXMLRPCInterfaceTests(TestBase):
                              traverse, interface, 'supervisor._readFile', [])
         self._assertRPCError(xmlrpc.Faults.INCORRECT_PARAMETERS,
                              traverse, interface,
-                             'supervisor.getIdentification', [1])
-        self.assertEqual(
-            traverse(interface, 'supervisor.getIdentification', []),
-            'supervisor')
+                             'dummy.hello', [1])
+        self.assertEqual(traverse(interface, 'dummy.hello', []), 'Hello!')
             
 def makeExecutable(file, substitutions=None):
     if substitutions is None:
@@ -1860,20 +1856,21 @@ class XMLRPCHandlerTests(unittest.TestCase):
         from xmlrpc import supervisor_xmlrpc_handler
         return supervisor_xmlrpc_handler
     
-    def _makeOne(self, supervisord):
-        return self._getTargetClass()(supervisord)
+    def _makeOne(self, supervisord, subinterfaces):
+        return self._getTargetClass()(supervisord, subinterfaces)
 
     def test_ctor(self):
         supervisor = DummySupervisor()
-        handler = self._makeOne(supervisor)
+        subinterfaces = [('supervisor', DummySupervisorRPCNamespace())]
+        handler = self._makeOne(supervisor, subinterfaces)
         self.assertEqual(handler.supervisord, supervisor)
-        from xmlrpc import RPCInterface
-        self.assertEqual(handler.rpcinterface.__class__, RPCInterface)
+        from xmlrpc import RootRPCInterface
+        self.assertEqual(handler.rpcinterface.__class__, RootRPCInterface)
 
     def test_continue_request_nosuchmethod(self):
         supervisor = DummySupervisor()
-        handler = self._makeOne(supervisor)
-        handler.rpcinterface = DummyRPCServer()
+        subinterfaces = [('supervisor', DummySupervisorRPCNamespace())]
+        handler = self._makeOne(supervisor, subinterfaces)
         import xmlrpclib
         data = xmlrpclib.dumps(('a', 'b'), 'supervisor.noSuchMethod')
         request = DummyRequest('/what/ever', None, None, None)
@@ -1891,8 +1888,8 @@ class XMLRPCHandlerTests(unittest.TestCase):
 
     def test_continue_request_methodsuccess(self):
         supervisor = DummySupervisor()
-        handler = self._makeOne(supervisor)
-        handler.rpcinterface = DummyRPCServer()
+        subinterfaces = [('supervisor', DummySupervisorRPCNamespace())]
+        handler = self._makeOne(supervisor, subinterfaces)
         import xmlrpclib
         data = xmlrpclib.dumps((), 'supervisor.getProtocolVersion')
         request = DummyRequest('/what/ever', None, None, None)
@@ -1913,8 +1910,8 @@ class XMLRPCHandlerTests(unittest.TestCase):
 
     def test_continue_request_500(self):
         supervisor = DummySupervisor()
-        handler = self._makeOne(supervisor)
-        handler.rpcinterface = DummyRPCServer()
+        subinterfaces = [('supervisor', DummySupervisorRPCNamespace())]
+        handler = self._makeOne(supervisor, subinterfaces)
         import xmlrpclib
         data = xmlrpclib.dumps((), 'supervisor.raiseError')
         request = DummyRequest('/what/ever', None, None, None)
@@ -3161,6 +3158,10 @@ class DummyRequest:
 
     def done(self):
         self._done = True
+
+class DummyRPCInterface:
+    def hello(self):
+        return 'Hello!'
         
 def test_suite():
     suite = unittest.TestSuite()

+ 8 - 10
src/supervisor/xmlrpc.py

@@ -875,17 +875,14 @@ class AttrDict(dict):
     def __getattr__(self, name):
         return self[name]
 
-class RPCInterface:
-    def __init__(self, supervisord):
-        self.supervisord = supervisord
-        self.supervisor = SupervisorNamespaceRPCInterface(supervisord)
-        self.system = SystemNamespaceRPCInterface(
-            [('supervisor', self.supervisor)]
-            )
+class RootRPCInterface:
+    def __init__(self, subinterfaces):
+        for name, rpcinterface in subinterfaces:
+            setattr(self, name, rpcinterface)
 
 class supervisor_xmlrpc_handler(xmlrpc_handler):
-    def __init__(self, supervisord):
-        self.rpcinterface = RPCInterface(supervisord)
+    def __init__(self, supervisord, subinterfaces):
+        self.rpcinterface = RootRPCInterface(subinterfaces)
         self.supervisord = supervisord
         
     def continue_request (self, data, request):
@@ -958,4 +955,5 @@ def traverse(ob, method, params):
     except TypeError:
         raise RPCError(Faults.INCORRECT_PARAMETERS)
 
-
+def make_main_rpcinterface(supervisord):
+    return SupervisorNamespaceRPCInterface(supervisord)