[Checkins] SVN: zc.sshtunnel/trunk/ basic recipe to manage an SSH tunnel in a development buildout

Fred L. Drake, Jr. fdrake at gmail.com
Mon Feb 26 12:15:20 EST 2007


Log message for revision 72824:
  basic recipe to manage an SSH tunnel in a development buildout

Changed:
  _U  zc.sshtunnel/trunk/
  A   zc.sshtunnel/trunk/buildout.cfg
  A   zc.sshtunnel/trunk/setup.py
  A   zc.sshtunnel/trunk/src/
  A   zc.sshtunnel/trunk/src/zc/
  A   zc.sshtunnel/trunk/src/zc/__init__.py
  A   zc.sshtunnel/trunk/src/zc/sshtunnel/
  A   zc.sshtunnel/trunk/src/zc/sshtunnel/README.txt
  A   zc.sshtunnel/trunk/src/zc/sshtunnel/__init__.py
  A   zc.sshtunnel/trunk/src/zc/sshtunnel/recipe.py
  A   zc.sshtunnel/trunk/src/zc/sshtunnel/tests.py

-=-

Property changes on: zc.sshtunnel/trunk
___________________________________________________________________
Name: svn:ignore
   + .installed.cfg
bin
develop-eggs
eggs
parts


Added: zc.sshtunnel/trunk/buildout.cfg
===================================================================
--- zc.sshtunnel/trunk/buildout.cfg	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/buildout.cfg	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1,9 @@
+[buildout]
+develop = .
+parts = test
+
+find-links = http://download.zope.org/distribution/
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zc.sshtunnel [test]


Property changes on: zc.sshtunnel/trunk/buildout.cfg
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: zc.sshtunnel/trunk/setup.py
===================================================================
--- zc.sshtunnel/trunk/setup.py	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/setup.py	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1,20 @@
+from setuptools import setup
+
+entry_points = """\
+
+[zc.buildout]
+default=zc.sshtunnel.recipe:Recipe
+
+"""
+
+setup(
+    name="zc.sshtunnel",
+    packages=["zc.sshtunnel"],
+    package_dir={"": "src"},
+    namespace_packages=["zc"],
+    install_requires=["setuptools"],
+    entry_points=entry_points,
+    extras_require={"test": "zc.buildout"},
+    include_package_data=True,
+    zip_safe=False,
+    )


Property changes on: zc.sshtunnel/trunk/setup.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Added: zc.sshtunnel/trunk/src/zc/__init__.py
===================================================================
--- zc.sshtunnel/trunk/src/zc/__init__.py	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/src/zc/__init__.py	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1,7 @@
+# This directory is a Python namespace package.
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)


Property changes on: zc.sshtunnel/trunk/src/zc/__init__.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Added: zc.sshtunnel/trunk/src/zc/sshtunnel/README.txt
===================================================================
--- zc.sshtunnel/trunk/src/zc/sshtunnel/README.txt	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/src/zc/sshtunnel/README.txt	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1,58 @@
+=================================
+Creating SSH tunnels in buildouts
+=================================
+
+This recipe creates a control script for an SSH tunnel.  This is only
+expected to work on systems with the OpenSSH "ssh" binary on $PATH,
+and may require setting up the SSH configuration to use the expected
+usernames for each system.
+
+Let's create a configuration that defines a single tunnel in a part
+called "my-tunnel"::
+
+  >>> write("buildout.cfg", """\
+  ...
+  ... [buildout]
+  ... parts = my-tunnel
+  ... find-links = http://download.zope.org/distribution/
+  ...
+  ... [my-tunnel]
+  ... recipe = zc.sshtunnel
+  ... python = sample-python
+  ... specification = 8080:server.example.net:6060
+  ... via = somehost.example.net
+  ...
+  ... [sample-python]
+  ... executable = /usr/bin/python
+  ...
+  ... """)
+
+Building this out creates a single script in the bin/ directory::
+
+  >>> print system(join("bin", "buildout")),
+  buildout: Installing my-tunnel
+
+  >>> ls("bin")
+  -  buildout
+  -  my-tunnel
+
+The script is a Python script; the tunnel parameters are stored at the
+top of the script::
+
+  >>> cat(join("bin", "my-tunnel"))
+  #!/usr/bin/python
+  ...
+  pid_file = "/sample-buildout/parts/my-tunnel.pid"
+  specification = "8080:server.example.net:6060"
+  via = "somehost.example.net"
+  wait_port = 8080
+  name = "my-tunnel"
+  ...
+
+The script accepts the "start", "stop", "restart", and "status"
+verbs.  Let's demonstrate "status", since that doesn't require
+actually establishing a tunnel::
+
+  >>> print system(join("bin", "my-tunnel") + " status")
+  Pid file /sample-buildout/parts/my-tunnel.pid doesn't exist
+  <BLANKLINE>


Property changes on: zc.sshtunnel/trunk/src/zc/sshtunnel/README.txt
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:eol-style
   + native

Added: zc.sshtunnel/trunk/src/zc/sshtunnel/__init__.py
===================================================================
--- zc.sshtunnel/trunk/src/zc/sshtunnel/__init__.py	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/src/zc/sshtunnel/__init__.py	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1 @@
+# This directory is a Python package.


Property changes on: zc.sshtunnel/trunk/src/zc/sshtunnel/__init__.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Added: zc.sshtunnel/trunk/src/zc/sshtunnel/recipe.py
===================================================================
--- zc.sshtunnel/trunk/src/zc/sshtunnel/recipe.py	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/src/zc/sshtunnel/recipe.py	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1,144 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation 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.
+#
+##############################################################################
+"""\
+`zc.buildout` recipe to create and manage an SSH tunnel using an rc script.
+
+"""
+__docformat__ = "reStructuredText"
+
+import os
+
+
+class Recipe(object):
+
+    def __init__(self, buildout, name, options):
+        self.name = name
+        self.options = options
+
+        self.via = options["via"]
+        self.specification = options["specification"]
+        parts = self.specification.split(":")
+        wait_port = int(parts[-3])
+        self.wait_port = str(wait_port)
+
+        python = options.get("python", "buildout")
+        self.executable = buildout[python]["executable"]
+
+        self.script = os.path.join(
+            buildout["buildout"]["bin-directory"], name)
+        self.pidfile = os.path.join(
+            buildout["buildout"]["parts-directory"], name + ".pid")
+
+        options["executable"] = self.executable
+        options["pidfile"] = self.pidfile
+        options["run-script"] = self.script
+
+    def install(self):
+        d = {
+            "name": self.name,
+            "pid_file": self.pidfile,
+            "python": self.executable,
+            "specification": self.specification,
+            "via": self.via,
+            "wait_port": self.wait_port,
+            }
+        text = tunnel_script_template % d
+        f = open(self.script, "w")
+        f.write(text)
+        f.close()
+        os.chmod(self.script, int("0770", 8))
+        return [self.script]
+
+
+tunnel_script_template = r"""#!%(python)s
+
+import os, sys, signal, socket, time, errno
+
+pid_file = "%(pid_file)s"
+specification = "%(specification)s"
+via = "%(via)s"
+wait_port = %(wait_port)s
+name = "%(name)s"
+
+def wait(port):
+    addr = 'localhost', port
+    for i in range(120):
+        time.sleep(0.25)
+        try:
+            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            s.connect(addr)
+            s.close()
+            break
+        except socket.error, e:
+            if e[0] not in (errno.ECONNREFUSED, errno.ECONNRESET):
+                raise
+            s.close()
+    else:
+        raise
+
+def main(args=None):
+    if args is None:
+        args = sys.argv[1:]
+
+    [verb] = args
+
+    if verb == 'start':
+        if os.path.exists(pid_file):
+            print "Pid file %%s already exists" %% pid_file
+            return
+
+        pid = os.fork()
+        if pid == 0:
+            # redirect output to /dev/null.  This will
+            # cause nohup to be unannoying
+            os.dup2(os.open('/dev/null', os.O_WRONLY), 1)
+            os.dup2(os.open('/dev/null', os.O_WRONLY), 2)
+            pid = os.spawnlp(os.P_NOWAIT, 'nohup', 'nohup',
+                             'ssh', '-TnaxqNL'+specification,  via)
+            open(pid_file, 'w').write("%%s\n" %% pid)
+        else:
+            wait(wait_port)
+            print name, 'started'
+    elif verb == 'status':
+        if os.path.exists(pid_file):
+            pid = int(open(pid_file).read().strip())
+            try:
+                os.kill(pid, 0)
+            except OSError, v:
+                print v
+            else:
+                print name, 'running'
+        else:
+            print "Pid file %%s doesn't exist" %% pid_file
+    elif verb == 'stop':
+        if os.path.exists(pid_file):
+            pid = int(open(pid_file).read().strip())
+            try:
+                os.kill(pid, signal.SIGINT)
+            except OSError, v:
+                print v
+            os.remove(pid_file)
+            print name, 'stopped'
+        else:
+            print "Pid file %%s doesn't exist" %% pid_file
+    elif verb == 'restart':
+        main(['stop'])
+        main(['start'])
+        return
+    else:
+        raise ValueError("Unknown verb", verb)
+
+if __name__ == '__main__':
+    main()
+"""


Property changes on: zc.sshtunnel/trunk/src/zc/sshtunnel/recipe.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Added: zc.sshtunnel/trunk/src/zc/sshtunnel/tests.py
===================================================================
--- zc.sshtunnel/trunk/src/zc/sshtunnel/tests.py	2007-02-26 16:45:47 UTC (rev 72823)
+++ zc.sshtunnel/trunk/src/zc/sshtunnel/tests.py	2007-02-26 17:15:19 UTC (rev 72824)
@@ -0,0 +1,43 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation 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.
+#
+##############################################################################
+"""\
+Test harness for zc.sshtunnel.
+
+"""
+__docformat__ = "reStructuredText"
+
+import unittest
+
+from zope.testing import doctest
+from zope.testing import renormalizing
+
+import zc.buildout.testing
+
+
+def setUp(test):
+    zc.buildout.testing.buildoutSetUp(test)
+    zc.buildout.testing.install_develop("zc.sshtunnel", test)
+    zc.buildout.testing.install("zope.testing", test)
+
+
+def test_suite():
+    return unittest.TestSuite([
+        doctest.DocFileSuite(
+            "README.txt",
+            setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown,
+            optionflags=doctest.ELLIPSIS,
+            checker=renormalizing.RENormalizing([
+                zc.buildout.testing.normalize_path])
+            ),
+        ])


Property changes on: zc.sshtunnel/trunk/src/zc/sshtunnel/tests.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native



More information about the Checkins mailing list