def resolveFeatureName(name, klass): """Given a feature name and a subclass of _ConfigFile, check whether the feature exists, and return a sec/name tuple that, when passed to _ConfigFile.getFeature, gives the value of the appropriate feature. Raises a UIError if the feature name is invalid. A feature is either: a special string handled by the class (like 'caps' for ServerInfo), a special string handled outside the class (like 'status' for ClientDirectory), a Section:Entry string, or an Entry string. (If the Entry string is not unique within a section, raises UIError.) All features are case-insensitive. Example features are: 'caps', 'status', 'Incoming/MMTP:Version', 'hostname'. """ syn = klass._syntax name = name.lower() if name in klass._features: 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" % (goodSection, 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]
def resolveFeatureName(name, klass): """Given a feature name and a subclass of _ConfigFile, check whether the feature exists, and return a sec/name tuple that, when passed to _ConfigFile.getFeature, gives the value of the appropriate feature. Raises a UIError if the feature name is invalid. A feature is either: a special string handled by the class (like 'caps' for ServerInfo), a special string handled outside the class (like 'status' for ClientDirectory), a Section:Entry string, or an Entry string. (If the Entry string is not unique within a section, raises UIError.) All features are case-insensitive. Example features are: 'caps', 'status', 'Incoming/MMTP:Version', 'hostname'. """ 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"%(goodSection,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]
# If we don't know our Hostname, try to guess if fields['Hostname'] is None: fields['Hostname'] = socket.getfqdn() LOG.warn("No Hostname configured; guessing %s", fields['Hostname']) try: _checkHostnameIsLocal(fields['Hostname']) dnsResults = mixminion.NetUtils.getIPs(fields['Hostname']) except socket.error, e: LOG.warn("Can't resolve configured hostname %r: %s", fields['Hostname'], str(e)) else: found = [ip for _, ip, _ in dnsResults] if fields['IP'] not in found: LOG.warn( "Configured hostname %r resolves to %s, but we're publishing the IP %s", fields['Hostname'], englishSequence(found), fields['IP']) # Fill in a stock server descriptor. Note the empty Digest: and # Signature: lines. info = """\ [Server] Descriptor-Version: 0.2 Nickname: %(Nickname)s Identity: %(Identity)s Digest: Signature: Published: %(Published)s Valid-After: %(ValidAfter)s Valid-Until: %(ValidUntil)s Packet-Key: %(PacketKey)s Packet-Versions: %(PacketVersion)s
def __load(self, fileContents): """As in .reload(), but takes an open file object _or_ a string.""" fileContents = _abnormal_line_ending_re.sub("\n", fileContents) if self._restrictFormat: sections = _readRestrictedConfigFile(fileContents) else: sections = _readConfigFile(fileContents) sections = self.prevalidate(sections) self._sections = {} self._sectionEntries = {} self._sectionNames = [] sectionEntryLines = {} for secName, secEntries in sections: self._sectionNames.append(secName) if secName in self._sections: raise ConfigError("Duplicate section [%s]" % secName) section = {} sectionEntries = [] entryLines = [] self._sections[secName] = section self._sectionEntries[secName] = sectionEntries sectionEntryLines[secName] = entryLines secConfig = self._syntax.get(secName) if not secConfig: if self._restrictSections: raise ConfigError("Skipping unrecognized section %s" % secName) else: LOG.warn("Skipping unrecognized section %s", secName) continue # Set entries from the section, searching for bad entries # as we go. for k, v, line in secEntries: try: 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() if k in sc ] acceptedIn.sort() if acceptedIn: msg += (". This key belongs in %s, " % englishSequence(acceptedIn, compound="or")) msg += "but appears in %s." % secName if self._restrictKeys: raise ConfigError(msg) else: 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: v = parseFn(v) except ConfigError, e: e.args = ("%s at line %s" % (e.args[0], line)) raise e sectionEntries.append((k, v)) entryLines.append(line) # Insert the entry, checking for impermissible duplicates. if rule in ('REQUIRE', 'ALLOW'): if k in section: raise ConfigError("Duplicate entry for %s at line %s" % (k, line)) else: section[k] = v elif rule in ('REQUIRE*', 'ALLOW*'): try: section[k].append(v) except KeyError: section[k] = [v] else: assert rule == 'IGNORE' pass # Check for missing entries, setting defaults and detecting # missing requirements as we go. for k, (rule, parseType, default) in secConfig.items(): if k == '__SECTION__' or rule == 'IGNORE': continue elif k not in section: if rule in ('REQUIRE', 'REQUIRE*'): 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] = [] else: section[k] = default elif rule == 'ALLOW': section[k] = parseFn(default) else: assert rule == 'ALLOW*' section[k] = map(parseFn, default) cb = self._callbacks.get(secName) if cb: cb(section, sectionEntries)
def __load(self, fileContents): """As in .reload(), but takes an open file object _or_ a string.""" fileContents = _abnormal_line_ending_re.sub("\n", fileContents) if self._restrictFormat: sections = _readRestrictedConfigFile(fileContents) else: sections = _readConfigFile(fileContents) sections = self.prevalidate(sections) self._sections = {} self._sectionEntries = {} self._sectionNames = [] sectionEntryLines = {} for secName, secEntries in sections: self._sectionNames.append(secName) if self._sections.has_key(secName): raise ConfigError("Duplicate section [%s]" %secName) section = {} sectionEntries = [] entryLines = [] self._sections[secName] = section self._sectionEntries[secName] = sectionEntries sectionEntryLines[secName] = entryLines secConfig = self._syntax.get(secName) if not secConfig: if self._restrictSections: raise ConfigError("Skipping unrecognized section %s" %secName) else: LOG.warn("Skipping unrecognized section %s", secName) continue # Set entries from the section, searching for bad entries # as we go. for k,v,line in secEntries: try: 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() if sc.has_key(k) ] acceptedIn.sort() if acceptedIn: msg += ". This key belongs in %s, but appears in %s."%( englishSequence(acceptedIn, compound="or"), secName) if self._restrictKeys: raise ConfigError(msg) else: 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: v = parseFn(v) except ConfigError, e: e.args = ("%s at line %s" %(e.args[0],line)) raise e sectionEntries.append( (k,v) ) entryLines.append(line) # Insert the entry, checking for impermissible duplicates. if rule in ('REQUIRE', 'ALLOW'): if section.has_key(k): raise ConfigError("Duplicate entry for %s at line %s" % (k, line)) else: section[k] = v elif rule in ('REQUIRE*','ALLOW*'): try: section[k].append(v) except KeyError: section[k] = [v] else: assert rule == 'IGNORE' pass # Check for missing entries, setting defaults and detecting # missing requirements as we go. for k, (rule, parseType, default) in secConfig.items(): if k == '__SECTION__' or rule == 'IGNORE': continue elif not section.has_key(k): if rule in ('REQUIRE', 'REQUIRE*'): 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] = [] else: section[k] = default elif rule == 'ALLOW': section[k] = parseFn(default) else: assert rule == 'ALLOW*' section[k] = map(parseFn,default) cb = self._callbacks.get(secName) if cb: cb(section, sectionEntries)
raise UIError("Can't guess IP: %s" % str(e)) # If we don't know our Hostname, try to guess if fields['Hostname'] is None: fields['Hostname'] = socket.getfqdn() LOG.warn("No Hostname configured; guessing %s",fields['Hostname']) try: _checkHostnameIsLocal(fields['Hostname']) dnsResults = mixminion.NetUtils.getIPs(fields['Hostname']) except socket.error, e: LOG.warn("Can't resolve configured hostname %r: %s", fields['Hostname'],str(e)) else: found = [ ip for _,ip,_ in dnsResults ] if fields['IP'] not in found: LOG.warn("Configured hostname %r resolves to %s, but we're publishing the IP %s", fields['Hostname'], englishSequence(found), fields['IP']) # Fill in a stock server descriptor. Note the empty Digest: and # Signature: lines. info = """\ [Server] Descriptor-Version: 0.2 Nickname: %(Nickname)s Identity: %(Identity)s Digest: Signature: Published: %(Published)s Valid-After: %(ValidAfter)s Valid-Until: %(ValidUntil)s Packet-Key: %(PacketKey)s Packet-Versions: %(PacketVersion)s