[Checkins] SVN: Sandbox/J1m/zkzopeserver/ zope.server wrapper that registers w ZooKeeper

Jim Fulton jim at zope.com
Sat Dec 10 23:26:03 UTC 2011


Log message for revision 123671:
  zope.server wrapper that registers w ZooKeeper

Changed:
  D   Sandbox/J1m/zkzopeserver/README.txt
  A   Sandbox/J1m/zkzopeserver/README.txt
  U   Sandbox/J1m/zkzopeserver/buildout.cfg
  U   Sandbox/J1m/zkzopeserver/setup.py
  A   Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/
  A   Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/README.txt
  A   Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/__init__.py
  A   Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/tests.py

-=-
Deleted: Sandbox/J1m/zkzopeserver/README.txt
===================================================================
--- Sandbox/J1m/zkzopeserver/README.txt	2011-12-10 23:20:48 UTC (rev 123670)
+++ Sandbox/J1m/zkzopeserver/README.txt	2011-12-10 23:26:03 UTC (rev 123671)
@@ -1,14 +0,0 @@
-Title Here
-**********
-
-
-To learn more, see
-
-
-Changes
-*******
-
-0.1.0 (yyyy-mm-dd)
-==================
-
-Initial release

Added: Sandbox/J1m/zkzopeserver/README.txt
===================================================================
--- Sandbox/J1m/zkzopeserver/README.txt	                        (rev 0)
+++ Sandbox/J1m/zkzopeserver/README.txt	2011-12-10 23:26:03 UTC (rev 123671)
@@ -0,0 +1 @@
+link src/zc/zkzopeserver/README.txt
\ No newline at end of file


Property changes on: Sandbox/J1m/zkzopeserver/README.txt
___________________________________________________________________
Added: svn:special
   + *

Modified: Sandbox/J1m/zkzopeserver/buildout.cfg
===================================================================
--- Sandbox/J1m/zkzopeserver/buildout.cfg	2011-12-10 23:20:48 UTC (rev 123670)
+++ Sandbox/J1m/zkzopeserver/buildout.cfg	2011-12-10 23:26:03 UTC (rev 123671)
@@ -1,12 +1,27 @@
 [buildout]
-develop = .
-parts = test py
+develop = . zk
+parts = test py paste.ini
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = 
+eggs = zc.zkzopeserver [test]
 
 [py]
 recipe = zc.recipe.egg
 eggs = ${test:eggs}
+       PasteScript
+       bobo
+       
 interpreter = py
+
+[paste.ini]
+recipe = zc.recipe.deployment:configuration
+text =
+  [app:main]
+  use = egg:bobo
+  bobo_resources = zc.zkzopeserver.tests
+
+  [server:main]
+  use = egg:zc.zkzopeserver
+  zookeeper = 127.0.0.1:2181
+  path = /

Modified: Sandbox/J1m/zkzopeserver/setup.py
===================================================================
--- Sandbox/J1m/zkzopeserver/setup.py	2011-12-10 23:20:48 UTC (rev 123670)
+++ Sandbox/J1m/zkzopeserver/setup.py	2011-12-10 23:26:03 UTC (rev 123671)
@@ -11,12 +11,14 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-name, version = 'zc.', '0'
+name, version = 'zc.zkzopeserver', '0'
 
-install_requires = ['setuptools']
-extras_require = dict(test=['zope.testing'])
+install_requires = ['setuptools', 'zc.zk', 'zope.server']
+extras_require = dict(test=['zope.testing', 'zc.zk [static,test]'])
 
 entry_points = """
+[paste.server_runner]
+main = zc.zkzopeserver:run
 """
 
 from setuptools import setup
@@ -28,7 +30,7 @@
 
     name = name, version = version,
     long_description=open('README.txt').read(),
-    description = open('README.txt').read().strip().split('\n')[0],
+    description = open('README.txt').read().strip().split('\n')[1],
     packages = [name.split('.')[0], name],
     namespace_packages = [name.split('.')[0]],
     package_dir = {'': 'src'},

Added: Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/README.txt
===================================================================
--- Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/README.txt	                        (rev 0)
+++ Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/README.txt	2011-12-10 23:26:03 UTC (rev 123671)
@@ -0,0 +1,93 @@
+=================================================
+zope.server wrapper that registers with ZooKeeper
+=================================================
+
+``zc.zkzopeserver`` provides a wrapper for the zope.server WSGI runner
+that registers with ZooKeeper.  By registering with ZooKeeper, you can
+let the operating system assign ports and have clients find your
+server by looking in ZooKeeper.
+
+Basic Usage
+===========
+
+The wrapper is used in a past-deply configuration file::
+
+   [server:main]
+   use = egg:zc.zkzopeserver
+   zookeeper = zookeeper.example.com:2181
+   path = /fooservice/providers
+
+.. -> server_config
+
+The wrapper supports the following options:
+
+zookeeper
+   required ZooKeeper connection string
+
+path
+   required path at which to register your server.
+
+   Your server is registered by adding a ZooKeeper ephemeral node as a
+   child of the path with the server address as the name.
+
+host
+   host name or ip to listen on, defaultiong to ''
+
+port
+   The port to listen on, defaulting to 0
+
+session_timeout
+   A ZooKeeper session timeout in milliseconds
+
+threads
+   The size of the thread pool, defaulting to 1
+
+.. test
+
+    >>> import ConfigParser, StringIO
+    >>> parser = ConfigParser.RawConfigParser()
+    >>> parser.readfp(StringIO.StringIO(server_config))
+    >>> kw = dict(parser.items('server:main'))
+
+    >>> import pkg_resources
+    >>> dist = kw.pop('use').split(':')[1]
+    >>> [run] = [v.load()
+    ...          for v in pkg_resources.get_entry_map(
+    ...                 'zc.zkzopeserver', 'paste.server_runner'
+    ...                  ).values()]
+
+    >>> import wsgiref.simple_server, zc.thread
+    >>> @zc.thread.Thread
+    ... def server():
+    ...     run(wsgiref.simple_server.demo_app, {}, **kw)
+
+    >>> import time
+    >>> time.sleep(.1)
+
+    >>> import urllib, zc.zk
+    >>> zk = zc.zk.ZooKeeper('zookeeper.example.com:2181')
+
+    >>> [port] = [int(c.split(':')[1])
+    ...           for c in zk.get_children('/fooservice/providers')]
+    >>> print urllib.urlopen('http://127.0.0.1:%s/' % port).read()
+    ... # doctest: +ELLIPSIS
+    Hello world!
+    ...
+
+    Cleanup, sigh, violently close the server.
+
+    >>> import asyncore
+    >>> for s in asyncore.socket_map.values():
+    ...     s.close()
+    >>> server.join(1)
+    >>> zk.close()
+
+
+
+Change History
+==============
+
+0.1.0 (2011-12-??)
+------------------
+
+Initial release


Property changes on: Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/README.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/__init__.py
===================================================================
--- Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/__init__.py	                        (rev 0)
+++ Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/__init__.py	2011-12-10 23:26:03 UTC (rev 123671)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import asyncore
+import zc.zk
+import zope.server.taskthreads
+import zope.server.http.wsgihttpserver
+
+def run(wsgi_app, global_conf,
+        zookeeper, path, session_timeout=None,
+        name=__name__, host='', port=0, threads=1,
+        ):
+    port = int(port)
+    threads = int(threads)
+
+    task_dispatcher = zope.server.taskthreads.ThreadedTaskDispatcher()
+    task_dispatcher.setThreadCount(threads)
+    server = zope.server.http.wsgihttpserver.WSGIHTTPServer(
+        wsgi_app, name, host, port,
+        task_dispatcher=task_dispatcher)
+    server.ZooKeeper = zc.zk.ZooKeeper(
+        zookeeper, session_timeout and int(session_timeout))
+    server.ZooKeeper.register_server(
+        path, "%s:%s" % server.socket.getsockname())
+    try:
+        asyncore.loop()
+    finally:
+        server.ZooKeeper.close()


Property changes on: Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/__init__.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/tests.py
===================================================================
--- Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/tests.py	                        (rev 0)
+++ Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/tests.py	2011-12-10 23:26:03 UTC (rev 123671)
@@ -0,0 +1,126 @@
+##############################################################################
+#
+# Copyright Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import asyncore
+import doctest
+import manuel.capture
+import manuel.doctest
+import manuel.testing
+import re
+import time
+import unittest
+import urllib
+import zc.thread
+import zc.zk.testing
+import zope.testing.renormalizing
+
+maxactive = active = 0
+def reset():
+    global active, maxactive
+    r = maxactive
+    maxactive = active = 0
+    return r
+def slow_app(environ, start_response):
+    global active, maxactive
+    active += 1
+    maxactive = max(maxactive, active)
+    status = '200 OK'
+    response_headers = [('Content-type', 'text/plain')]
+    time.sleep(.1)
+    start_response(status, response_headers)
+    active -= 1
+    return ['Hello world!\n']
+
+def stop_server(thread):
+    for s in asyncore.socket_map.values():
+        s.close()
+    asyncore.socket_map.clear()
+    thread.join(1)
+
+def test_options():
+    """
+    Make sure various advertized options work:
+
+    >>> @zc.thread.Thread
+    ... def server():
+    ...     zc.zkzopeserver.run(
+    ...         slow_app, {},
+    ...         zookeeper='zookeeper.example.com:2181',
+    ...         path='/fooservice/providers',
+    ...         session_timeout='4242',
+    ...         host='127.0.0.1',
+    ...         port='3042',
+    ...         threads='3',
+    ...         )
+
+    >>> time.sleep(.1)
+    >>> zk = zc.zk.ZooKeeper('zookeeper.example.com:2181')
+
+    Did it get registered with the given host and port?
+
+    >>> zk.print_tree('/fooservice/providers')
+    /providers
+      /127.0.0.1:3042
+        pid = 3699
+
+    How many can we do at once? Should be 3
+
+    >>> [url] = [('http://%s/' % addr)
+    ...          for addr in zk.get_children('/fooservice/providers')]
+
+    >>> def get():
+    ...     f = urllib.urlopen(url)
+    ...     if not f.read().startwith('Hello world!'):
+    ...         print '?'
+    ...     f.close()
+
+    >>> _ = reset()
+    >>> threads = [zc.thread.Thread(get) for i in range(6)]
+    >>> _ = [t.join() for t in threads]
+
+    >>> reset()
+    3
+
+    Did session_timeout get passed? If we're using the mock ZooKeeper,
+    we camn tell:
+
+    >>> if ZooKeeper is not None:
+    ...    ZooKeeper.recv_timeout(0)
+    4242
+
+    When the server stops, it's unregistered:
+
+    >>> stop_server(server)
+    >>> zk.print_tree('/fooservice/providers')
+    /providers
+
+    >>> zk.close()
+    """
+
+
+def test_suite():
+    checker = zope.testing.renormalizing.RENormalizing([
+        (re.compile('pid = \d+'), 'pid = 9999'),
+        ])
+    suite = unittest.TestSuite((
+        manuel.testing.TestSuite(
+            manuel.doctest.Manuel(checker=checker) + manuel.capture.Manuel(),
+            'README.txt',
+            setUp=zc.zk.testing.setUp, tearDown=zc.zk.testing.tearDown,
+            ),
+        doctest.DocTestSuite(
+            setUp=zc.zk.testing.setUp, tearDown=zc.zk.testing.tearDown,
+            checker=checker,
+            ),
+        ))
+    return suite


Property changes on: Sandbox/J1m/zkzopeserver/src/zc/zkzopeserver/tests.py
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native



More information about the checkins mailing list