[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[minion-cvs] Start improve list-servers; refactor config types; less...
Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv20799/lib/mixminion
Modified Files:
ClientDirectory.py ClientMain.py ClientUtils.py Config.py
MMTPClient.py ServerInfo.py test.py testSupport.py
Log Message:
Start improve list-servers; refactor config types; less mem usage for flush.
ClientDirectory,ClientMain:
- New interface to display server information. Not done yet, but
better than groveling over directories by hand.
ClientMain, MMTPClient, ClientUtils:
- Change client queue flushing code so that we don't load everything
into memory when we flush the queue. Moved ClientQueue to use a
metadata store; added proxy class to lazy-load flushable messages
without changing sendMessages interface.
Config:
- Add resolveFeature/getFeature functions to generic config file
interface to make it easier for users to describe aspects of server
descriptors.
Config, ServerInfo, test, Modules, ServerConfig
- Change the way that types are specficied for _ConfigFile
derivitives: now they're by name instead of by by function. This
makes unparsing a snap, and keeps us from having to use private
(underscore-prefixed) names from Config.
Index: ClientDirectory.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientDirectory.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- ClientDirectory.py 19 Oct 2003 03:12:01 -0000 1.7
+++ ClientDirectory.py 7 Nov 2003 07:03:28 -0000 1.8
@@ -400,6 +400,44 @@
lines.append(line)
return lines
+ def listServers2(self, features, at=None, goodOnly=0):
+ """DOCDOC
+ Returns a dict from nickname to (va,vu) to feature to value."""
+ result = {}
+ if not self.fullServerList:
+ return {}
+ dirFeatures = [ 'status' ]
+ resFeatures = []
+ for f in features:
+ if f.lower() in dirFeatures:
+ resFeatures.append((f, ('+', f.lower())))
+ else:
+ feature = mixminion.Config.resolveFeatureName(
+ f, mixminion.ServerInfo.ServerInfo)
+ resFeatures.append((f, feature))
+ for sd, _ in self.fullServerList:
+ if at and not sd.isValidAt(at):
+ continue
+ nickname = sd.getNickname()
+ isGood = self.goodServerNicknames.get(nickname, 0)
+ if goodOnly and not isGood:
+ continue
+ va, vu = sd['Server']['Valid-After'], sd['Server']['Valid-Until']
+ d = result.setdefault(nickname, {}).setdefault((va,vu), {})
+ for feature,(sec,ent) in resFeatures:
+ if sec == '+':
+ if ent == 'status':
+ if isGood:
+ d['status'] = "(ok)"
+ else:
+ d['status'] = "(not recommended)"
+ else:
+ assert 0
+ else:
+ d[feature] = str(sd.getFeature(sec,ent))
+
+ return result
+
def __find(self, lst, startAt, endAt):
"""Helper method. Given a list of (ServerInfo, where), return all
elements that are valid for all time between startAt and endAt.
@@ -755,6 +793,87 @@
else:
LOG.warn("This software is newer than any version "
"on the recommended list.")
+
+#----------------------------------------------------------------------
+def compressServerList(featureMap, ignoreGaps=0, terse=0):
+ """DOCDOC
+ featureMap is nickname -> va,vu -> feature -> value .
+ result is same format, but time is compressed.
+ """
+ result = {}
+ for nickname in featureMap.keys():
+ byStartTime = featureMap[nickname].items()
+ byStartTime.sort()
+ r = []
+ for (va,vu),features in byStartTime:
+ if not r:
+ r.append((va,vu,features))
+ continue
+ lastva, lastvu, lastfeatures = r[-1]
+ if (ignoreGaps or lastvu == va) and lastfeatures == features:
+ r[-1] = lastva, vu, features
+ else:
+ r.append((va,vu,features))
+ result[nickname] = {}
+ for va,vu,features in r:
+ result[nickname][(va,vu)] = features
+
+ if not terse: continue
+ if not result[nickname]: continue
+
+ ritems = result[nickname].items()
+ minva = min([ va for (va,vu),features in ritems ])
+ maxvu = max([ vu for (va,vu),features in ritems ])
+ rfeatures = {}
+ for (va,vu),features in ritems:
+ for f,val in features.items():
+ if rfeatures.setdefault(f,val) != val:
+ rfeatures[f] += " / %s"%val
+ result[nickname] = { (minva,maxvu) : rfeatures }
+
+ return result
+
+def formatFeatureMap(features, featureMap, showTime=0, cascade=0, sep=" "):
+ # No cascade:
+ # nickname:time1: value value value
+ # nickname:time2: value value value
+
+ # Cascade=1:
+ # nickname:
+ # time1: value value value
+ # time2: value value value
+
+ # Cascade = 2:
+ # nickname:
+ # time:
+ # feature:value
+ # feature:value
+ # feature:value
+ nicknames = [ (nn.lower(), nn) for nn in featureMap.keys() ]
+ nicknames.sort()
+ lines = []
+ if not nicknames: return lines
+ for _, nickname in nicknames:
+ d = featureMap[nickname]
+ if not d: continue
+ items = d.items()
+ items.sort()
+ if cascade: lines.append("%s:"%nickname)
+ for (va,vu),fmap in items:
+ ftime = "%s to %s"%(formatDate(va),formatDate(vu))
+ if cascade and showTime:
+ lines.append(" %s:"%ftime)
+ if cascade:
+ for f in features:
+ v = fmap[f]
+ lines.append(" %s:%s"%(f,v))
+ elif showTime:
+ lines.append("%s:%s:%s" %(nickname,ftime,
+ sep.join([fmap[f] for f in features])))
+ else:
+ lines.append("%s:%s" %(nickname,
+ sep.join([fmap[f] for f in features])))
+ return lines
#----------------------------------------------------------------------
Index: ClientMain.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientMain.py,v
retrieving revision 1.123
retrieving revision 1.124
diff -u -d -r1.123 -r1.124
--- ClientMain.py 19 Oct 2003 03:41:45 -0000 1.123
+++ ClientMain.py 7 Nov 2003 07:03:28 -0000 1.124
@@ -444,8 +444,16 @@
"""
#XXXX write unit tests
+ class MessageProxy:
+ def __init__(self,h,queue):
+ self.h = h
+ self.queue = queue
+ def __str__(self):
+ return self.queue.getPacket(self.h)[0]
+ def __cmp__(self,other):
+ return cmp(id(self),id(other))
+
LOG.info("Flushing message queue")
- # XXXX This is inefficient in space!
clientLock()
try:
handles = self.queue.getHandles()
@@ -457,9 +465,10 @@
messagesByServer = {}
for h in handles:
try:
- message, routing, _ = self.queue.getPacket(h)
+ routing = self.queue.getRoutingt(h)
except mixminion.Filestore.CorruptedFile:
continue
+ message = MessageProxy(h,self.queue)
messagesByServer.setdefault(routing, []).append((message, h))
finally:
clientUnlock()
@@ -512,7 +521,7 @@
try:
clientLock()
for msg in msgList:
- h = self.queue.queuePacket(msg, routing)
+ h = self.queue.queuePacket(str(msg), routing)
handles.append(h)
finally:
clientUnlock()
@@ -1193,7 +1202,13 @@
parser.init()
directory = parser.directory
- for line in directory.listServers():
+ #for line in directory.listServers():
+ # print line
+ features = ["caps", "status", "secure-configuration"]
+ fm = directory.listServers2(features)
+ #fm = mixminion.ClientDirectory.compressServerList(fm)
+ for line in mixminion.ClientDirectory.formatFeatureMap(
+ features,fm,1,cascade=1):
print line
_UPDATE_SERVERS_USAGE = """\
Index: ClientUtils.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientUtils.py,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- ClientUtils.py 9 Oct 2003 15:26:16 -0000 1.3
+++ ClientUtils.py 7 Nov 2003 07:03:28 -0000 1.4
@@ -324,6 +324,7 @@
# )
# XXXX change this to be OO; add nicknames.
# XXXX006 write unit tests
+ # XXXX Switch to use metadata.
def __init__(self, directory, prng=None):
"""Create a new ClientQueue object, storing packets in 'directory'
and generating random filenames using 'prng'."""
@@ -339,16 +340,19 @@
fname_new = os.path.join(directory, "msg_"+handle)
os.rename(fname_old, fname_new)
- self.store = mixminion.Filestore.ObjectStore(
+ self.store = mixminion.Filestore.ObjectMetadataStore(
directory, create=1, scrub=1)
+ self.metadataLoaded = 0
+
def queuePacket(self, message, routing):
"""Insert the 32K packet 'message' (to be delivered to 'routing')
into the queue. Return the handle of the newly inserted packet."""
mixminion.ClientMain.clientLock()
try:
fmt = ("PACKET-0", message, routing, previousMidnight(time.time()))
- return self.store.queueObject(fmt)
+ meta = ("V0", routing, previousMidnight(time.time()))
+ return self.store.queueObjectAndMetadata(fmt,meta)
finally:
mixminion.ClientMain.clientUnlock()
@@ -361,9 +365,14 @@
finally:
mixminion.ClientMain.clientUnlock()
+ def getRouting(self, handle):
+ """DOCDOC"""
+ self.loadMetadata()
+ return self.getMetadata(handle)[1]
+
def getPacket(self, handle):
"""Given a handle, return a 3-tuple of the corresponding
- 32K packet, IPV4Info, and time of first queueing. (The time
+ 32K packet, {IPV4/Host}Info, and time of first queueing. (The time
is rounded down to the closest midnight GMT.) May raise
CorruptedFile."""
obj = self.store.getObject(handle)
@@ -384,6 +393,7 @@
def removePacket(self, handle):
"""Remove the packet named with the handle 'handle'."""
self.store.removeMessage(handle)
+ # XXXX006 This cleanQueue shouldn't need to happen so often!
self.store.cleanQueue()
def inspectQueue(self, now=None):
@@ -395,10 +405,11 @@
if not handles:
print "[Queue is empty.]"
return
+ self.loadMetadata()
timesByServer = {}
for h in handles:
try:
- _, routing, when = self.getPacket(h)
+ _, routing, when = self.store.getMetadata(h)
except mixminion.Filestore.CorruptedFile:
continue
timesByServer.setdefault(routing, []).append(when)
@@ -418,9 +429,10 @@
now = time.time()
cutoff = now - maxAge
remove = []
+ self.loadMetadata()
for h in self.getHandles():
try:
- when = self.getPacket(h)[2]
+ when = self.store.getMetadata(h)[2]
except mixminion.Filestore.CorruptedFile:
continue
if when < cutoff:
@@ -429,3 +441,16 @@
for h in remove:
self.store.removeMessage(h)
self.store.cleanQueue()
+
+ def loadMetadata(self):
+ """DOCDOC"""
+ if self.metadataLoaded:
+ return
+
+ def fixupHandle(h,self=self):
+ packet, routing, when = self.getPacket(h)
+ return "V0", routing, when
+
+ self.store.loadAllMetadata(fixupHandle)
+
+ self.metadataLoaded = 1
Index: Config.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Config.py,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -d -r1.61 -r1.62
--- Config.py 19 Oct 2003 03:12:02 -0000 1.61
+++ Config.py 7 Nov 2003 07:03:28 -0000 1.62
@@ -68,7 +68,7 @@
import mixminion.Crypto
from mixminion.Common import MixError, LOG, ceilDiv, englishSequence, \
- isPrintingAscii, stripSpace, stringContains, UIError
+ formatBase64, isPrintingAscii, stripSpace, stringContains, UIError
class ConfigError(MixError):
"""Thrown when an error is found in a configuration file."""
@@ -166,6 +166,27 @@
ilist.append(interval)
return ilist
+def _unparseIntervalList(lst):
+ if lst == []:
+ return ""
+ r = [ (lst[0], 1) ]
+ for dur in lst[1:]:
+ if dur == r[-1][0]:
+ r[-1] = (dur, r[-1][1]+1)
+ else:
+ r.append((dur,1))
+ result = []
+ for dur, reps in r:
+ d = mixminion.Common.Duration(dur)
+ t = mixminion.Common.Duration(dur*reps)
+ d.reduce()
+ t.reduce()
+ if reps>1:
+ result.append("every %s for %s"%(d,t))
+ else:
+ result.append(str(d))
+ return ", ".join(result)
+
def _parseInt(integer):
"""Validation function. Converts a config value to an int.
Raises ConfigError on failure."""
@@ -194,6 +215,16 @@
else:
return long(val)*unit
+def _unparseSize(size):
+ names = ["b", "KB", "MB", "GB"]
+ idx = 0
+ while 1:
+ if (size & 1023) or names[idx] == "GB":
+ return "%s %s"%(size,names[idx])
+ else:
+ idx += 1
+ size >>= 10
+
# Regular expression to match a dotted quad.
_ip_re = re.compile(r'^\d+\.\d+\.\d+\.\d+$')
@@ -261,7 +292,6 @@
return ip
-
def _parseHost(host):
"""DOCDOC"""
host = host.strip()
@@ -587,6 +617,46 @@
lines.append("") # so the last line ends with \n
return "\n".join(lines)
+
+def resolveFeatureName(name, klass):
+ """DOCDOC"""
+ #XXXX006 this should be case insensitive.
+ syn = klass._syntax
+ name = name.lower()
+ if klass._features.has_key(name):
+ return "-", name
+ elif ':' in name:
+ idx = name.index(':')
+ sec, ent = name[:idx], name[idx+1:]
+ goodSection = None
+ for section, entries in syn.items():
+ if section.lower() == sec:
+ goodSection = section
+ for entry in entries.keys():
+ if entry.lower() == ent:
+ return section, entry
+ if goodSection:
+ raise UIError("Section %s has no entry %r"%(section,ent))
+ else:
+ raise UIError("No such section as %s"%sec)
+ else:
+ result = []
+ for secname, secitems in syn.items():
+ if secname.lower() == name:
+ raise UIError("No key given for section %s"%secname)
+ for entname in secitems.keys():
+ if entname.lower() == name:
+ result.append((secname, entname))
+ if len(result) == 0:
+ raise UIError("No key named %r found"%name)
+ elif len(result) > 1:
+ secs = [ "%s:%s"%(secname,entname) for secname,entname
+ in result ]
+ raise UIError("%r is ambiguous. Did you mean %s?",
+ name, englishSequence(secs,compound="or"))
+ else:
+ return result[0]
+
class _ConfigFile:
"""Base class to parse, validate, and represent configuration files.
"""
@@ -603,7 +673,7 @@
# Fields to be set by a subclass:
# _syntax is map from sec->{key:
# (ALLOW/REQUIRE/ALLOW*/REQUIRE*,
- # parseFn,
+ # type,
# default, ) }
# _restrictFormat is 1/0: do we allow full RFC822ness, or do
# we insist on a tight data format?
@@ -624,6 +694,30 @@
# the entry's value will be set to default. Otherwise, the value
# will be set to None.
+ CODING_FNS = {
+ "boolean" : (_parseBoolean, lambda b: b and "yes" or "no"),
+ "severity" : (_parseSeverity, str),
+ "serverMode" : (_parseServerMode, str),
+ "interval" : (_parseInterval, str),
+ "intervalList" : (_parseIntervalList, _unparseIntervalList),
+ "int" : (_parseInt, str),
+ "size" : (_parseSize, _unparseSize),
+ "IP" : (_parseIP, str),
+ "IP6" : (_parseIP6, str),
+ "host" : (_parseHost, str),
+ "addressSet_allow" : (_parseAddressSet_allow, str), #XXXX
+ "addressSet_deny" : (_parseAddressSet_deny, str), #XXXX
+ "command" : (_parseCommand, lambda c,o: " ".join([c," ".join(o)])),
+ "base64" : (_parseBase64, mixminion.Common.formatBase64),
+ "hex" : (_parseHex, binascii.b2a_hex),
+ "publicKey" : (_parsePublicKey, lambda r: "<public key>"),
+ "date" : (_parseDate, mixminion.Common.formatDate),
+ "time" : (_parseTime, mixminion.Common.formatTime),
+ "nickname" : (_parseNickname, str),
+ "filename" : (_parseFilename, str),
+ "user" : (_parseUser, str),
+ }
+
_syntax = None
_features = {}
_restrictFormat = 0
@@ -698,7 +792,7 @@
# as we go.
for k,v,line in secEntries:
try:
- rule, parseFn, default = secConfig[k]
+ rule, parseType, default = secConfig[k]
except KeyError:
msg = "Unrecognized key %s on line %s"%(k,line)
acceptedIn = [ sn for sn,sc in self._syntax.items()
@@ -714,6 +808,8 @@
LOG.warn(msg)
continue
+ parseFn, _ = self.CODING_FNS.get(parseType,(None,None))
+
# Parse and validate the value of this entry.
if parseFn is not None:
try:
@@ -741,7 +837,7 @@
# Check for missing entries, setting defaults and detecting
# missing requirements as we go.
- for k, (rule, parseFn, default) in secConfig.items():
+ for k, (rule, parseType, default) in secConfig.items():
if k == '__SECTION__':
continue
elif not section.has_key(k):
@@ -749,6 +845,7 @@
raise ConfigError("Missing entry %s from section %s"
% (k, secName))
else:
+ parseFn, _ = self.CODING_FNS.get(parseType,(None,None))
if parseFn is None or default is None:
if rule == 'ALLOW*':
section[k] = []
@@ -792,40 +889,16 @@
"""
return contents
- def resolveFeatureName(self, name):
- """DOCDOC"""
- #XXXX006 this should be case insensitive.
- syn = self._syntax
- if self._features.has_key(name):
- return "-", name
- elif ':' in name:
- idx = name.index(':')
- sec, ent = name[:idx], name[idx+1:]
- if not syn.has_key(sec) or not syn[sec].has_key[ent]:
- raise UIError("Section %s has no entry %s"%(sec,ent))
- return sec,ent
- elif syn.has_key(name):
- raise UIError("No key given for section %s"%name)
- else:
- secs = []
- for secname, secitems in syn.items():
- if secitems.has_key(name):
- secs.append(name)
- if len(secs) == 0:
- raise UIError("No key named %s found"%name)
- elif len(secs) > 1:
- secs = [ "%s/%s"%(name, sec) for sec in secs ]
- raise UIError("%s is ambiguous. Did you mean %s?",
- name, englishSequence(secs,compound="or"))
- else:
- return secs[0],name
-
def getFeature(self,sec,name):
"""DOCDOC"""
- if sec == "-":
- return "XXXX" #XXXX006 insert magic.
- else:
- return self[sec].get(name,"<none>")
+ assert sec not in ("+","-")
+ parseType = self._syntax[sec].get(name)[1]
+ _, unparseFn = self.CODING_FNS[parseType]
+ try:
+ v = self[sec][name]
+ except KeyError:
+ return "<none>"
+ return unparseFn(v)
def validate(self, entryLines, fileContents):
"""Check additional semantic properties of a set of configuration
@@ -872,25 +945,25 @@
_restrictKeys = _restrictSections = 1
_syntax = {
'Host' : { '__SECTION__' : ('ALLOW', None, None),
- 'ShredCommand': ('ALLOW', _parseCommand, None),
- 'EntropySource': ('ALLOW', _parseFilename, "/dev/urandom"),
- 'TrustedUser': ('ALLOW*', _parseUser, None),
- 'FileParanoia': ('ALLOW', _parseBoolean, "yes"),
+ 'ShredCommand': ('ALLOW', "command", None),
+ 'EntropySource': ('ALLOW', "filename", "/dev/urandom"),
+ 'TrustedUser': ('ALLOW*', "user", None),
+ 'FileParanoia': ('ALLOW', "boolean", "yes"),
},
'DirectoryServers' :
{ '__SECTION__' : ('REQUIRE', None, None),
'ServerURL' : ('ALLOW*', None, None),
- 'MaxSkew' : ('ALLOW', _parseInterval, "10 minutes") },
- 'User' : { 'UserDir' : ('ALLOW', _parseFilename, "~/.mixminion" ) },
- 'Security' : { 'PathLength' : ('ALLOW', _parseInt, "8"),
+ 'MaxSkew' : ('ALLOW', "interval", "10 minutes") },
+ 'User' : { 'UserDir' : ('ALLOW', "filename", "~/.mixminion" ) },
+ 'Security' : { 'PathLength' : ('ALLOW', "int", "8"),
'SURBAddress' : ('ALLOW', None, None),
- 'SURBPathLength' : ('ALLOW', _parseInt, "4"),
- 'SURBLifetime' : ('ALLOW', _parseInterval, "7 days"),
+ 'SURBPathLength' : ('ALLOW', "int", "4"),
+ 'SURBLifetime' : ('ALLOW', "interval", "7 days"),
'ForwardPath' : ('ALLOW', None, "*"),
'ReplyPath' : ('ALLOW', None, "*"),
'SURBPath' : ('ALLOW', None, "*"),
},
- 'Network' : { 'ConnectionTimeout' : ('ALLOW', _parseInterval, None) }
+ 'Network' : { 'ConnectionTimeout' : ('ALLOW', "interval", None) }
}
def __init__(self, fname=None, string=None):
_ConfigFile.__init__(self, fname, string)
Index: MMTPClient.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/MMTPClient.py,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- MMTPClient.py 20 Oct 2003 18:19:56 -0000 1.40
+++ MMTPClient.py 7 Nov 2003 07:03:28 -0000 1.41
@@ -246,7 +246,7 @@
elif t == "RENEGOTIATE":
con.renegotiate()
else:
- con.sendPacket(p)
+ con.sendPacket(str(p))
if callback is not None:
callback(idx)
finally:
Index: ServerInfo.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ServerInfo.py,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -d -r1.59 -r1.60
--- ServerInfo.py 19 Oct 2003 03:12:02 -0000 1.59
+++ ServerInfo.py 7 Nov 2003 07:03:28 -0000 1.60
@@ -53,56 +53,56 @@
_syntax = {
"Server" : { "__SECTION__": ("REQUIRE", None, None),
"Descriptor-Version": ("REQUIRE", None, None),
- "Nickname": ("REQUIRE", C._parseNickname, None),
- "Identity": ("REQUIRE", C._parsePublicKey, None),
- "Digest": ("REQUIRE", C._parseBase64, None),
- "Signature": ("REQUIRE", C._parseBase64, None),
- "Published": ("REQUIRE", C._parseTime, None),
- "Valid-After": ("REQUIRE", C._parseDate, None),
- "Valid-Until": ("REQUIRE", C._parseDate, None),
+ "Nickname": ("REQUIRE", "nickname", None),
+ "Identity": ("REQUIRE", "publicKey", None),
+ "Digest": ("REQUIRE", "base64", None),
+ "Signature": ("REQUIRE", "base64", None),
+ "Published": ("REQUIRE", "time", None),
+ "Valid-After": ("REQUIRE", "date", None),
+ "Valid-Until": ("REQUIRE", "date", None),
"Contact": ("ALLOW", None, None),
"Comments": ("ALLOW", None, None),
- "Packet-Key": ("REQUIRE", C._parsePublicKey, None),
+ "Packet-Key": ("REQUIRE", "publicKey", None),
"Contact-Fingerprint": ("ALLOW", None, None),
# XXXX010 change these next few to "REQUIRE".
"Packet-Formats": ("ALLOW", None, None),#XXXX007 remove
"Packet-Versions": ("ALLOW", None, None),
"Software": ("ALLOW", None, None),
- "Secure-Configuration": ("ALLOW", C._parseBoolean, None),
+ "Secure-Configuration": ("ALLOW", "boolean", None),
"Why-Insecure": ("ALLOW", None, None),
},
"Incoming/MMTP" : {
"Version": ("REQUIRE", None, None),
- "IP": ("ALLOW", C._parseIP, None),#XXXX007 remove
- "Hostname": ("ALLOW", C._parseHost, None),#XXXX008 require
- "Port": ("REQUIRE", C._parseInt, None),
- "Key-Digest": ("ALLOW", C._parseBase64, None),#XXXX007 rmv
+ "IP": ("ALLOW", "IP", None),#XXXX007 remove
+ "Hostname": ("ALLOW", "host", None),#XXXX008 require
+ "Port": ("REQUIRE", "int", None),
+ "Key-Digest": ("ALLOW", "base64", None),#XXXX007 rmv
"Protocols": ("REQUIRE", None, None),
- "Allow": ("ALLOW*", C._parseAddressSet_allow, None),
- "Deny": ("ALLOW*", C._parseAddressSet_deny, None),
+ "Allow": ("ALLOW*", "addressSet_allow", None),
+ "Deny": ("ALLOW*", "addressSet_deny", None),
},
"Outgoing/MMTP" : {
"Version": ("REQUIRE", None, None),
"Protocols": ("REQUIRE", None, None),
- "Allow": ("ALLOW*", C._parseAddressSet_allow, None),
- "Deny": ("ALLOW*", C._parseAddressSet_deny, None),
+ "Allow": ("ALLOW*", "addressSet_allow", None),
+ "Deny": ("ALLOW*", "addressSet_deny", None),
},
"Delivery/MBOX" : {
"Version": ("REQUIRE", None, None),
# XXXX006 change to 'REQUIRE'
- "Maximum-Size": ("ALLOW", C._parseInt, "32"),
+ "Maximum-Size": ("ALLOW", "int", "32"),
# XXXX006 change to 'REQUIRE'
- "Allow-From": ("ALLOW", C._parseBoolean, "yes"),
+ "Allow-From": ("ALLOW", "boolean", "yes"),
},
"Delivery/SMTP" : {
"Version": ("REQUIRE", None, None),
# XXXX006 change to 'REQUIRE'
- "Maximum-Size": ("ALLOW", C._parseInt, "32"),
- "Allow-From": ("ALLOW", C._parseBoolean, "yes"),
+ "Maximum-Size": ("ALLOW", "int", "32"),
+ "Allow-From": ("ALLOW", "boolean", "yes"),
},
"Delivery/Fragmented" : {
"Version": ("REQUIRE", None, None),
- "Maximum-Fragments": ("REQUIRE", C._parseInt, None),
+ "Maximum-Fragments": ("REQUIRE", "int", None),
},
# We never read these values, except to see whether we should
# regenerate them. Depending on these options would violate
@@ -112,6 +112,7 @@
"Configuration": ("ALLOW", None, None),
},
}
+ _features = { "capabilities" : 1, "caps" : 1 }
expected_versions = {
"Server" : ( "Descriptor-Version", "0.2"),
"Incoming/MMTP" : ("Version", "0.1"),
@@ -417,6 +418,15 @@
valid -= o.getIntervalSet()
return valid.isEmpty()
+ def getFeature(self,sec,name):
+ """DOCDOC"""
+ if sec == '-':
+ if name in ("caps", "capabilities"):
+ return " ".join(self.getCaps())
+ assert 0
+ else:
+ return mixminion.Config._ConfigFile.getFeature(self,sec,name)
+
#----------------------------------------------------------------------
# Server Directories
@@ -501,15 +511,15 @@
_syntax = {
'Directory': { "__SECTION__": ("REQUIRE", None, None),
"Version": ("REQUIRE", None, None),
- "Published": ("REQUIRE", C._parseTime, None),
- "Valid-After": ("REQUIRE", C._parseDate, None),
- "Valid-Until": ("REQUIRE", C._parseDate, None),
+ "Published": ("REQUIRE", "time", None),
+ "Valid-After": ("REQUIRE", "date", None),
+ "Valid-Until": ("REQUIRE", "date", None),
"Recommended-Servers": ("REQUIRE", None, None),
},
'Signature': {"__SECTION__": ("REQUIRE", None, None),
- "DirectoryIdentity": ("REQUIRE", C._parsePublicKey, None),
- "DirectoryDigest": ("REQUIRE", C._parseBase64, None),
- "DirectorySignature": ("REQUIRE", C._parseBase64, None),
+ "DirectoryIdentity": ("REQUIRE", "publicKey", None),
+ "DirectoryDigest": ("REQUIRE", "base64", None),
+ "DirectorySignature": ("REQUIRE", "base64", None),
},
'Recommended-Software': {"__SECTION__": ("ALLOW", None, None),
"MixminionClient": ("ALLOW", None, None),
Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.159
retrieving revision 1.160
diff -u -d -r1.159 -r1.160
--- test.py 7 Nov 2003 05:44:40 -0000 1.159
+++ test.py 7 Nov 2003 07:03:28 -0000 1.160
@@ -3888,14 +3888,14 @@
'Sec2' : {'Fob': ('ALLOW*', None, None),
'Bap': ('REQUIRE', None, None),
'Quz': ('REQUIRE*', None, None), },
- 'Sec3' : {'IntAS': ('ALLOW', _parseInt, None),
- 'IntAS2': ('ALLOW', _parseInt, None),
- 'IntASD': ('ALLOW', _parseInt, "5"),
- 'IntASD2': ('ALLOW', _parseInt, "5"),
- 'IntAM': ('ALLOW*', _parseInt, None),
- 'IntAMD': ('ALLOW*', _parseInt, ["5", "2"]),
- 'IntAMD2': ('ALLOW*', _parseInt, ["5", "2"]),
- 'IntRS': ('REQUIRE', _parseInt, None),
+ 'Sec3' : {'IntAS': ('ALLOW', "int", None),
+ 'IntAS2': ('ALLOW', "int", None),
+ 'IntASD': ('ALLOW', "int", "5"),
+ 'IntASD2': ('ALLOW', "int", "5"),
+ 'IntAM': ('ALLOW*', "int", None),
+ 'IntAMD': ('ALLOW*', "int", ["5", "2"]),
+ 'IntAMD2': ('ALLOW*', "int", ["5", "2"]),
+ 'IntRS': ('REQUIRE', "int", None),
'Quz' : ('ALLOW', None, None) }
}
def __init__(self, fname=None, string=None, restrict=0):
@@ -4878,8 +4878,7 @@
def getName(self):
return "TestModule"
def getConfigSyntax(self):
- return { "Example" : { "Foo" : ("REQUIRE",
- mixminion.Config._parseInt, None) } }
+ return { "Example" : { "Foo" : ("REQUIRE", "int", None) } }
def validateConfig(self, cfg, lines, contents):
if cfg['Example'] is not None:
if cfg['Example'].get('Foo',1) % 2 == 0:
Index: testSupport.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/testSupport.py,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- testSupport.py 2 Oct 2003 21:46:23 -0000 1.21
+++ testSupport.py 7 Nov 2003 07:03:28 -0000 1.22
@@ -46,8 +46,8 @@
def getConfigSyntax(self):
return { 'Testing/DirectoryDump':
{ 'Location' : ('REQUIRE', None, None),
- 'UseQueue': ('REQUIRE', _parseBoolean, None),
- 'Retry' : ('ALLOW', _parseIntervalList,
+ 'UseQueue': ('REQUIRE', "boolean", None),
+ 'Retry' : ('ALLOW', "intervalList",
"every 1 min for 10 min") } }
def validateConfig(self, config, lines, contents):