[Zodb-checkins] CVS: ZODB3/ZEO - runsvr.py:1.10
Guido van Rossum
guido@python.org
Fri, 22 Nov 2002 13:00:25 -0500
Update of /cvs-repository/ZODB3/ZEO
In directory cvs.zope.org:/tmp/cvs-serv26949
Modified Files:
runsvr.py
Log Message:
Add ZConfig support. The -s option goes away; if you want multiple
storages, it's much easier to specify those in a config file.
XXX This still needs a unit test suite.
=== ZODB3/ZEO/runsvr.py 1.9 => 1.10 ===
--- ZODB3/ZEO/runsvr.py:1.9 Thu Nov 21 16:34:33 2002
+++ ZODB3/ZEO/runsvr.py Fri Nov 22 13:00:25 2002
@@ -14,17 +14,16 @@
##############################################################################
"""Start the ZEO storage server.
-Usage: %s [-a ADDRESS] [-f FILENAME] [-s STORAGE]
+Usage: %s [-a ADDRESS] [-C URL] [-f FILENAME] [-h]
Options:
-a/--address ADDRESS -- server address of the form PORT, HOST:PORT, or PATH
(a PATH must contain at least one "/")
+-C/--configuration URL -- configuration file or URL
-f/--filename FILENAME -- filename for FileStorage
--s/--storage STORAGE -- storage specification of the form
- NAME=MODULE[:ATTRIBUTE]
- (multiple -s options are supported)
+-h/--help -- print this usage message and exit
--a is required; either -f must be used or -s must be used.
+Unless -C is specified, -a and -f are required.
"""
# The code here is designed to be reused by other, similar servers.
@@ -41,6 +40,10 @@
import zLOG
+import ZConfig
+import ZConfig.Common
+import ZConfig.Storage
+
class Options:
@@ -53,6 +56,9 @@
errors related to the command line.
"""
+ configuration = None
+ rootconf = None
+
args = []
def __init__(self, args=None, progname=None, doc=None):
@@ -90,8 +96,8 @@
self.check_options()
# Default set of options. Subclasses should override.
- _short_options = "h"
- _long_options = ["--help"]
+ _short_options = "C:h"
+ _long_options = ["--configuration=", "--help"]
def handle_option(self, opt, arg):
"""Handle one option. Subclasses should override.
@@ -100,15 +106,25 @@
When -h is detected, print the module docstring to stdout and exit(0).
"""
- if opt == "-h" or opt == "--help":
+ if opt in ("-C", "--configuration"):
+ self.set_configuration(arg)
+ if opt in ("-h", "--help"):
self.help()
+ def set_configuration(self, arg):
+ self.configuration = arg
+
def check_options(self):
"""Check options. Subclasses may override.
This can be used to ensure certain options are set, etc.
"""
- pass
+ self.load_configuration()
+
+ def load_configuration(self):
+ if self.rootconf or not self.configuration:
+ return
+ self.rootconf = ZConfig.load(self.configuration)
def help(self):
"""Print a long help message (self.doc) to stdout and exit(0).
@@ -130,17 +146,20 @@
class ZEOOptions(Options):
- family = None
- address = None
- storages = None
- filename = None
+ hostname = None # A subclass may set this
+ hostconf = None # <Host> section
+ zeoconf = None # <ZEO> section
+
+ family = None # set by -a; AF_UNIX or AF_INET
+ address = None # set by -a; string or (host, port)
+ storages = None # set by -f
- _short_options = "a:f:hs:"
+ _short_options = "a:C:f:h"
_long_options = [
"--address=",
+ "--configuration=",
"--filename=",
"--help",
- "--storage=",
]
def handle_option(self, opt, arg):
@@ -162,32 +181,74 @@
self.usage("invalid port number: %r" % port)
self.address = (host, port)
elif opt in ("-f", "--filename"):
- self.filename = arg
- elif opt in ("-s", "--storage"):
- if self.storages is None:
- self.storages = {}
- if not "=" in arg:
- self.usage("use -s/--storage storagename=module[:attribute]")
- name, rest = arg.split("=", 1)
- if ":" in rest:
- module, attr = rest.split(":", 1)
- else:
- module = rest
- attr = name
- self.storages[name] = module, attr
+ from ZODB.FileStorage import FileStorage
+ self.storages = {"1": (FileStorage, {"file_name": arg})}
else:
# Pass it to the base class, for --help/-h
Options.handle_option(self, opt, arg)
def check_options(self):
- if self.storages and self.filename:
- self.usage("can't use both -s/--storage and -f/--filename")
- if not self.storages and not self.filename:
- self.usage("need one of -s/--storage or -f/--filename")
+ Options.check_options(self) # Calls load_configuration()
+ if not self.storages:
+ self.usage("no storages specified; use -f or -C")
if self.family is None:
- self.usage("need -a/--address [host:]port or unix path")
+ self.usage("no server address specified; use -a or -C")
if self.args:
- self.usage("no positional arguments supported")
+ self.usage("positional arguments are not supported")
+
+ def load_configuration(self):
+ Options.load_configuration(self) # Sets self.rootconf
+ if not self.rootconf:
+ return
+ try:
+ self.hostconf = self.rootconf.getSection("Host")
+ except ZConfig.Common.ConfigurationConflictingSectionError:
+ if not self.hostname:
+ self.hostname = socket.getfqdn()
+ self.hostconf = self.rootconf.getSection("Host", self.hostname)
+ if self.hostconf is None:
+ # If no <Host> section exists, fall back to the root
+ self.hostconf = self.rootconf
+ self.zeoconf = self.hostconf.getSection("ZEO")
+ if self.zeoconf is None:
+ # If no <ZEO> section exists, fall back to the host (or root)
+ self.zeoconf = self.hostconf
+
+ # Now extract options from various configuration sections
+ self.load_zeoconf()
+ self.load_storages()
+
+ def load_zeoconf(self):
+ # Get some option defaults from the configuration
+ if self.family:
+ # -a option overrides
+ return
+ port = self.zeoconf.getint("server-port")
+ path = self.zeoconf.get("path")
+ if port and path:
+ self.usage(
+ "Configuration contains conflicting ZEO information:\n"
+ "Exactly one of 'path' and 'server-port' may be given.")
+ if port:
+ host = self.hostconf.get("hostname", "")
+ self.family = socket.AF_INET
+ self.address = (host, port)
+ elif path:
+ self.family = socket.AF_UNIX
+ self.address = path
+
+ def load_storages(self):
+ # Get the storage specifications
+ if self.storages:
+ # -f option overrides
+ return
+ storagesections = self.zeoconf.getChildSections("Storage")
+ self.storages = {}
+ for section in storagesections:
+ name = section.name
+ if not name:
+ name = str(1 + len(self.storages))
+ self.storages[name] = ZConfig.Storage.getStorageInfo(section)
class ZEOServer:
@@ -234,37 +295,11 @@
pass
def open_storages(self):
- if self.options.storages:
- self.load_storages(self.options.storages)
- else:
- from ZODB.FileStorage import FileStorage
- info("opening storage '1': %r" % self.options.filename)
- storage = FileStorage(self.options.filename)
- self.storages = {"1": storage}
-
- def load_storages(self, storages):
self.storages = {}
- for name, (module, attr) in storages.items():
- info("opening storage %r (%r:%r)" % (name, module, attr))
- self.storages[name] = self.get_storage(module, attr)
-
- _storage_cache = {}
-
- def get_storage(self, module, attr):
- # XXX This may fail with ImportError or AttributeError
- path = sys.path
- dir, module = os.path.split(module)
- if module.lower().endswith('.py'):
- module = module[:-3]
- im = self._storage_cache.get((dir, module))
- if im is None:
- if dir:
- path = [dir] + path
- import imp
- im = imp.find_module(module, path)
- im = imp.load_module(module, *im)
- self._storage_cache[(dir, module)] = im
- return getattr(im, attr)
+ for name, (cls, args) in self.options.storages.items():
+ info("open storage %r: %s.%s(**%r)" %
+ (name, cls.__module__, cls.__name__, args))
+ self.storages[name] = cls(**args)
def setup_signals(self):
"""Set up signal handlers.