[Checkins] SVN: zc.recipe.deployment/trunk/src/zc/recipe/deployment/ Fixed bug:

Jim Fulton jim at zope.com
Wed Feb 7 07:18:52 EST 2007


Log message for revision 72421:
  Fixed bug:
  Non-empty log and run directories were deleated in un- and
  re-install.
  

Changed:
  U   zc.recipe.deployment/trunk/src/zc/recipe/deployment/README.txt
  U   zc.recipe.deployment/trunk/src/zc/recipe/deployment/__init__.py
  A   zc.recipe.deployment/trunk/src/zc/recipe/deployment/rtests.py

-=-
Modified: zc.recipe.deployment/trunk/src/zc/recipe/deployment/README.txt
===================================================================
--- zc.recipe.deployment/trunk/src/zc/recipe/deployment/README.txt	2007-02-07 12:10:39 UTC (rev 72420)
+++ zc.recipe.deployment/trunk/src/zc/recipe/deployment/README.txt	2007-02-07 12:18:51 UTC (rev 72421)
@@ -1,36 +1,142 @@
-Unix Deployment Support
-=======================
+Using the deplyment recipe is pretty simple. Simply specify a
+deployment name, specified via the part name, and a deployment user.
 
-The zc.recipe.deployment recipe provides support for deploying
-applications with multiple processes on Unix systems.  It creates
-directories to hold application instance configuration, log and
-run-time files.  It also sets or reads options that can be read by
-other programs to find out where to place files:
+Let's add a deployment to a sample buildout:
 
-cron-directory
-    The name of the directory in which cron jobs should be placed.
-    This is /etc/cron.d.
+    >>> write('buildout.cfg',
+    ... '''
+    ... [buildout]
+    ... parts = foo
+    ...
+    ... [foo]
+    ... recipe = zc.recipe.deployment
+    ... user = jim
+    ... ''')
 
-etc-directory
-    The name of the directory where configuration files should be
-    placed.  This is /etc/NAME, where NAME is the deployment
-    name. 
+    >>> print system(join('bin', 'buildout')),
+    buildout: Installing foo
+    zc.recipe.deployment: 
+        Creating '/etc/foo',
+        mode 755, user 'root', group 'root'
+    zc.recipe.deployment: 
+        Creating '/var/log/foo',
+        mode 755, user 'jim', group 'jim'
+    zc.recipe.deployment: 
+        Creating '/var/run/foo',
+        mode 750, user 'jim', group 'jim'
 
-log-directory
-    The name of the directory where application instances should write
-    their log files.  This is /var/log/NAME, where NAME is
-    the deployment name.
 
-run-directory
-    The name of the directory where application instances should put
-    their run-time files such as pid files and inter-process
-    communication socket files.  This is /var/run/NAME, where
-    NAME is the deployment name.
+(Note that we have to be running as root and must have a user jim for
+this to work.)
 
-rc-directory
-    The name of the directory where run-control scripts should be
-    installed.  This is /etc/init.d.
+Now we can see that directories named foo in /etc, /var/log and
+/var/run have been created:
 
-The etc, log, and run directories are created in such a way that the 
-directories are owned by the user specified in the user option and are
-writable by the user and the user's group.
+    >>> print system('ls -ld /etc/foo'), 
+    drwxr-xr-x 2 root root 4096 2007-02-06 09:50 /etc/foo
+
+    >>> print system('ls -ld /var/log/foo'), 
+    drwxr-xr-x 2 jim jim 4096 2007-02-06 09:50 /var/log/foo
+
+    >>> print system('ls -ld /var/run/foo'), 
+    drwxr-x--- 2 jim jim 40 2007-02-06 09:50 /var/run/foo
+    
+By looking at .installed.cfg, we can see the options available for use
+by other recipes:
+
+    >>> cat('.installed.cfg')
+    ... # doctest: +ELLIPSIS
+    [buildout]
+    ...
+    [foo]
+    __buildout_installed__ = 
+    ...
+    crontab-directory = /etc/cron.d
+    etc-directory = /etc/foo
+    log-directory = /var/log/foo
+    rc-directory = /etc/init.d
+    recipe = zc.recipe.deployment
+    run-directory = /var/run/foo
+    user = jim
+
+If we ininstall, then the directories are removed.
+
+    >>> print system(join('bin', 'buildout')+' buildout:parts='),
+    buildout: Uninstalling foo
+    buildout: Running uninstall recipe
+    zc.recipe.deployment: Removing '/etc/foo'
+    zc.recipe.deployment: Removing '/var/log/foo'.
+    zc.recipe.deployment: Removing '/var/run/foo'.
+
+    >>> import os
+    >>> os.path.exists('/etc/foo')
+    False
+    >>> os.path.exists('/var/log/foo')
+    False
+    >>> os.path.exists('/var/run/foo')
+    False
+
+The log and run directories are only removed if they are non-empty.
+To see that, we'll put a file in each of the directories created:
+
+    >>> print system(join('bin', 'buildout')), # doctest: +ELLIPSIS
+    buildout: Installing foo
+    ...
+
+    >>> write('/etc/foo/x', '')
+    >>> write('/var/log/foo/x', '')
+    >>> write('/var/run/foo/x', '')
+
+And then uninstall:
+
+    >>> print system(join('bin', 'buildout')+' buildout:parts='),
+    buildout: Uninstalling foo
+    buildout: Running uninstall recipe
+    zc.recipe.deployment: Removing '/etc/foo'
+    zc.recipe.deployment: Can't remove non-empty directory '/var/log/foo'.
+    zc.recipe.deployment: Can't remove non-empty directory '/var/run/foo'.
+
+    >>> os.path.exists('/etc/foo')
+    False
+
+    >>> print system('ls -ld /var/log/foo'), 
+    drwxr-xr-x 2 jim jim 4096 2007-02-06 09:50 /var/log/foo
+
+    >>> print system('ls -ld /var/run/foo'), 
+    drwxr-x--- 2 jim jim 40 2007-02-06 09:50 /var/run/foo
+
+Here we see that the var and run directories are kept. The etc
+directory is discarded because only buildout recipes should write to
+it and all of it's data are expendible.
+
+If we reinstall, remove the files, and uninstall, then the directories
+are removed:
+
+    >>> print system(join('bin', 'buildout')),
+    buildout: Installing foo
+    zc.recipe.deployment: 
+        Creating '/etc/foo',
+        mode 755, user 'root', group 'root'
+    zc.recipe.deployment: 
+        Updating '/var/log/foo',
+        mode 755, user 'jim', group 'jim'
+    zc.recipe.deployment: 
+        Updating '/var/run/foo',
+        mode 750, user 'jim', group 'jim'
+
+    >>> os.remove('/var/log/foo/x')
+    >>> os.remove('/var/run/foo/x')
+
+    >>> print system(join('bin', 'buildout')+' buildout:parts='),
+    buildout: Uninstalling foo
+    buildout: Running uninstall recipe
+    zc.recipe.deployment: Removing '/etc/foo'
+    zc.recipe.deployment: Removing '/var/log/foo'.
+    zc.recipe.deployment: Removing '/var/run/foo'.
+
+    >>> os.path.exists('/etc/foo')
+    False
+    >>> os.path.exists('/var/log/foo')
+    False
+    >>> os.path.exists('/var/run/foo')
+    False

Modified: zc.recipe.deployment/trunk/src/zc/recipe/deployment/__init__.py
===================================================================
--- zc.recipe.deployment/trunk/src/zc/recipe/deployment/__init__.py	2007-02-07 12:10:39 UTC (rev 72420)
+++ zc.recipe.deployment/trunk/src/zc/recipe/deployment/__init__.py	2007-02-07 12:18:51 UTC (rev 72421)
@@ -16,10 +16,11 @@
 $Id: deployment.py 14934 2006-11-10 23:57:33Z jim $
 """
 
-import os, pwd, shutil
+import grp, logging, os, pwd, shutil
 
+logger = logging.getLogger('zc.recipe.deployment')
 
-class Recipe:
+class Install:
 
     def __init__(self, buildout, name, options):
         self.name, self.options = name, options
@@ -31,7 +32,8 @@
                                                 name)
         options['etc-directory'] = os.path.join(options.get('etc', '/etc'),
                                                 name)
-        options['crontab-directory'] = options.get('crontab-directory', '/etc/cron.d')
+        options['crontab-directory'] = options.get('crontab-directory',
+                                                   '/etc/cron.d')
         options['rc-directory'] = options.get('rc-directory', '/etc/init.d')
 
     def install(self):
@@ -43,7 +45,6 @@
             make_dir(options['etc-directory'],   0,   0, 0755, created)
             make_dir(options['log-directory'], uid, gid, 0755, created)
             make_dir(options['run-directory'], uid, gid, 0750, created)
-            return created
         except Exception, e:
             for d in created:
                 try:
@@ -53,11 +54,35 @@
                     pass
             raise e
 
+        return ()
+
     def update(self):
         pass
 
 
+def uninstall(name, options):
+    path = options['etc-directory']
+    shutil.rmtree(path)
+    logger.info("Removing %r", path)
+    for d in 'log', 'run':
+        path = options[d+'-directory']
+        if os.listdir(path):
+            logger.warn("Can't remove non-empty directory %r.", path)
+        else:
+            os.rmdir(path)
+            logger.info("Removing %r.", path)
+
 def make_dir(name, uid, gid, mode, created):
-    os.mkdir(name, mode)
-    created.append(name)
+    uname = pwd.getpwuid(uid)[0]
+    gname = grp.getgrgid(gid)[0]
+    if not os.path.isdir(name):
+        os.mkdir(name, mode)
+        created.append(name)
+        logger.info('\n    Creating %r,\n    mode %o, user %r, group %r',
+                    name, mode, uname, gname)
+    else:
+        os.chmod(name, mode)
+        logger.info('\n    Updating %r,\n    mode %o, user %r, group %r',
+                    name, mode, uname, gname)
+
     os.chown(name, uid, gid)

Added: zc.recipe.deployment/trunk/src/zc/recipe/deployment/rtests.py
===================================================================
--- zc.recipe.deployment/trunk/src/zc/recipe/deployment/rtests.py	2007-02-07 12:10:39 UTC (rev 72420)
+++ zc.recipe.deployment/trunk/src/zc/recipe/deployment/rtests.py	2007-02-07 12:18:51 UTC (rev 72421)
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+
+import re
+import zc.buildout.testing
+
+import unittest
+import zope.testing
+from zope.testing import doctest, renormalizing
+
+def setUp(test):
+    zc.buildout.testing.buildoutSetUp(test)
+    zc.buildout.testing.install_develop('zc.recipe.deployment', test)
+
+def test_suite():
+    return unittest.TestSuite((
+        #doctest.DocTestSuite(),
+        doctest.DocFileSuite(
+            'README.txt',
+            setUp=setUp, tearDown=zc.buildout.testing.buildoutTearDown,
+            checker=renormalizing.RENormalizing([
+                (re.compile('\d+ \d\d\d\d-\d\d-\d\d \d\d:\d\d'), ''),
+##                zc.buildout.testing.normalize_path,
+        
+##                zc.buildout.testing.normalize_script,
+##                zc.buildout.testing.normalize_egg_py,        
+##                (re.compile('#!\S+python\S*'), '#!python'),
+##                (re.compile('\d[.]\d+ seconds'), '0.001 seconds'),
+##                (re.compile('zope.testing-[^-]+-'), 'zope.testing-X-'),
+##                (re.compile('setuptools-[^-]+-'), 'setuptools-X-'),
+               ])
+            ),
+        
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: zc.recipe.deployment/trunk/src/zc/recipe/deployment/rtests.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native



More information about the Checkins mailing list