Defining ZEORAID storage servers
================================

The `gocept.zeoraid:server` recipe can be used to define ZEO storage servers
with management utilities for ZEORAID.

This recipe is internally built on top of `zc.zodbrecipes:server` and
instruments it, adding the generation of management scripts.

To define a storage server, you define a part for the server and specify
configuration data.  

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = zodb zeoraid
    ...
    ... [zodb]
    ... recipe = zc.recipe.egg:script
    ... eggs = ZODB3
    ... 
    ... [zeoraid]
    ... recipe = gocept.zeoraid:server
    ... zeo.conf = 
    ...    <zeo>
    ...       address 8100
    ...       monitor-address 8101
    ...       transaction-timeout 300
    ...    </zeo>
    ...    %import gocept.zeoraid
    ...    <raidstorage 1>
    ...       <zeoclient 1>
    ...           address 8101
    ...       </zeoclient>
    ...    </raidstorage>
    ... ''')

Here we specified a minimal ZEORAID configuration. When we run the buildout:

    >>> print system(buildout),
    Installing zodb.
    Generated script '/sample-buildout/bin/mkzeoinst'.
    Generated script '/sample-buildout/bin/fstail'.
    Generated script '/sample-buildout/bin/zeopack'.
    Generated script '/sample-buildout/bin/runzeo'.
    Generated script '/sample-buildout/bin/zeopasswd'.
    Generated script '/sample-buildout/bin/zeoctl'.
    Generated script '/sample-buildout/bin/fsdump'.
    Generated script '/sample-buildout/bin/fsrefs'.
    Generated script '/sample-buildout/bin/repozo'.
    Generated script '/sample-buildout/bin/fsoids'.
    Installing zeoraid.
    Generated script '/sample-buildout/bin/zeoraid'.
    Generated script '/sample-buildout/bin/zeoraid-1-manage'.

We get 2 things.  We get a directory in parts containing ZEO and
zdaemon configuration files:

    >>> ls('parts', 'zeoraid')
    -  zdaemon.conf
    -  zeo.conf

Let's look at the configuration files:

    >>> cat('parts', 'zeoraid', 'zeo.conf')
    %import gocept.zeoraid
    <BLANKLINE>
    <zeo>
      address 8100
      monitor-address 8101
      transaction-timeout 300
    </zeo>
    <BLANKLINE>
    <raidstorage 1>
      <zeoclient 1>
        address 8101
      </zeoclient>
    </raidstorage>
    <BLANKLINE>
    <eventlog>
      <logfile>
        path STDOUT
      </logfile>
    </eventlog>

We see the same data we input with the addition of an eventlog section that
directs logging to standard out.

Let's look at the scripts that were generated in our bin directory:

    >>> ls('bin')
    -  buildout
    -  fsdump
    -  fsoids
    -  fsrefs
    -  fstail
    -  mkzeoinst
    -  repozo
    -  runzeo
    -  zeoctl
    -  zeopack
    -  zeopasswd
    -  zeoraid
    -  zeoraid-1-manage


We have an additional RAID control script:

    >>> cat('bin', 'zeoraid-1-manage')
    #!/.../python
    <BLANKLINE>
    import sys
    sys.path[0:0] = [
      '.../src',
      '.../externals/ZODB/src',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      ]
    <BLANKLINE>
    import gocept.zeoraid.scripts.controller
    <BLANKLINE>
    if __name__ == '__main__':
        gocept.zeoraid.scripts.controller.main(port=8100, host="127.0.0.1", storage="1")


This is a console script with customized defaults.  We can use this to control
the RAID storage aspects of the ZEO server.

Unix deployment support
=======================

The management script's name is compatible with `zc.recipe.deployment`.

Let's create a deployment environmont and add a deployment section to our
buildout:

    >>> for d in 'cron', 'etc', 'log', 'rotate', 'rc', 'run':
    ...     mkdir(d)
    ...     globals()[d] = join(sample_buildout, d)

    >>> write('buildout.cfg',
    ... '''
    ... [buildout]
    ... parts = zodb zeoraid
    ... 
    ... [zodb]
    ... recipe = zc.recipe.egg:script
    ... eggs = ZODB3
    ... 
    ... [zeoraid]
    ... recipe = gocept.zeoraid:server
    ... zeo.conf = 
    ...    <zeo>
    ...       address 8100
    ...       monitor-address 8101
    ...       transaction-timeout 300
    ...    </zeo>
    ...    %%import gocept.zeoraid
    ...    <raidstorage main>
    ...       <zeoclient 1>
    ...         address 8101
    ...       </zeoclient>
    ...    </raidstorage>
    ... deployment = demo
    ...
    ... [demo]
    ... crontab-directory = %(cron)s
    ... etc-directory = %(etc)s
    ... log-directory = %(log)s
    ... logrotate-directory = %(rotate)s
    ... rc-directory = %(rc)s
    ... run-directory = %(run)s
    ... user = bob
    ... ''' % globals())

    >>> print system(buildout),
    Uninstalling zeoraid.
    Updating zodb.
    Installing zeoraid.
    Generated script '/sample-buildout/rc/demo-zeoraid'.
    Generated script '/sample-buildout/rc/demo-zeoraid-main-manage'.

Now, the parts directory and the control script will be gone:

    >>> import os
    >>> os.path.exists(join('parts', 'zeoraid'))
    False
    >>> os.path.exists(join('bin', 'zeoraid'))
    False

Instead, the control script will be in the rc directory:

    >>> ls('rc')
    -  demo-zeoraid
    -  demo-zeoraid-main-manage

    >>> cat('rc', 'demo-zeoraid-main-manage')
    #!/.../python
    <BLANKLINE>
    import sys
    sys.path[0:0] = [
      '.../src',
      '.../externals/ZODB/src',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      '/sample-pyN.N.egg',
      ]
    <BLANKLINE>
    import gocept.zeoraid.scripts.controller
    <BLANKLINE>
    if __name__ == '__main__':
        gocept.zeoraid.scripts.controller.main(port=8100, host="127.0.0.1", storage="main")


The run-control script name now combines the deployment name and the
script name.
