RPKI Engine
1.0
|
00001 """ 00002 Configuration file parsing utilities, layered on top of stock Python 00003 ConfigParser module. 00004 00005 $Id: config.py 4014 2011-10-05 16:30:24Z sra $ 00006 00007 Copyright (C) 2009--2011 Internet Systems Consortium ("ISC") 00008 00009 Permission to use, copy, modify, and distribute this software for any 00010 purpose with or without fee is hereby granted, provided that the above 00011 copyright notice and this permission notice appear in all copies. 00012 00013 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 00014 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00015 AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 00016 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00017 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00018 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00019 PERFORMANCE OF THIS SOFTWARE. 00020 00021 Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") 00022 00023 Permission to use, copy, modify, and distribute this software for any 00024 purpose with or without fee is hereby granted, provided that the above 00025 copyright notice and this permission notice appear in all copies. 00026 00027 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH 00028 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00029 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, 00030 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00031 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00032 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00033 PERFORMANCE OF THIS SOFTWARE. 00034 """ 00035 00036 import ConfigParser, os, re 00037 00038 ## @var default_filename 00039 # Default name of config file if caller doesn't specify one explictly. 00040 00041 default_filename = "rpki.conf" 00042 00043 ## @var default_dirname 00044 # Default name of directory to check for global config file, or None 00045 # if no global config file. Autoconf-generated code may set this to a 00046 # non-None value during script startup. 00047 00048 default_dirname = None 00049 00050 ## @var default_envname 00051 # Name of environment variable containing config file name. 00052 00053 default_envname = "RPKI_CONF" 00054 00055 class parser(object): 00056 """ 00057 Extensions to stock Python ConfigParser: 00058 00059 Read config file and set default section while initializing parser object. 00060 00061 Support for OpenSSL-style subscripted options and a limited form of 00062 OpenSSL-style indirect variable references (${section::option}). 00063 00064 get-methods with default values and default section name. 00065 00066 If no filename is given to the constructor (filename = None), we 00067 check for an environment variable naming the config file, then we 00068 check for a default filename in the current directory, then finally 00069 we check for a global config file if autoconf provided a directory 00070 name to check. 00071 """ 00072 00073 def __init__(self, filename = None, section = None, allow_missing = False): 00074 00075 self.cfg = ConfigParser.RawConfigParser() 00076 self.default_section = section 00077 00078 filenames = [] 00079 if filename is not None: 00080 filenames.append(filename) 00081 else: 00082 if default_envname in os.environ: 00083 filenames.append(os.environ[default_envname]) 00084 filenames.append(default_filename) 00085 if default_dirname is not None: 00086 filenames.append("%s/%s" % (default_dirname, default_filename)) 00087 00088 for fn in filenames: 00089 try: 00090 f = open(fn) 00091 break 00092 except IOError: 00093 f = None 00094 00095 if f is not None: 00096 self.filename = fn 00097 self.cfg.readfp(f, fn) 00098 elif allow_missing: 00099 self.filename = None 00100 else: 00101 raise 00102 00103 def has_section(self, section): 00104 """ 00105 Test whether a section exists. 00106 """ 00107 00108 return self.cfg.has_section(section) 00109 00110 def has_option(self, option, section = None): 00111 """ 00112 Test whether an option exists. 00113 """ 00114 00115 if section is None: 00116 section = self.default_section 00117 return self.cfg.has_option(section, option) 00118 00119 def multiget(self, option, section = None): 00120 """ 00121 Parse OpenSSL-style foo.0, foo.1, ... subscripted options. 00122 00123 Returns a list of values matching the specified option name. 00124 """ 00125 00126 matches = [] 00127 if section is None: 00128 section = self.default_section 00129 if self.cfg.has_option(section, option): 00130 matches.append((-1, self.get(option, section = section))) 00131 for key, value in self.cfg.items(section): 00132 s = key.rsplit(".", 1) 00133 if len(s) == 2 and s[0] == option and s[1].isdigit(): 00134 matches.append((int(s[1]), self.get(option, section = section))) 00135 matches.sort() 00136 return [match[1] for match in matches] 00137 00138 _regexp = re.compile("\\${(.*?)::(.*?)}") 00139 00140 def _repl(self, m): 00141 """ 00142 Replacement function for indirect variable substitution. 00143 This is intended for use with re.subn(). 00144 """ 00145 section, option = m.group(1, 2) 00146 if section == "ENV": 00147 return os.getenv(option, "") 00148 else: 00149 return self.cfg.get(section, option) 00150 00151 def get(self, option, default = None, section = None): 00152 """ 00153 Get an option, perhaps with a default value. 00154 """ 00155 if section is None: 00156 section = self.default_section 00157 if default is not None and not self.cfg.has_option(section, option): 00158 return default 00159 val = self.cfg.get(section, option) 00160 while True: 00161 val, modified = self._regexp.subn(self._repl, val, 1) 00162 if not modified: 00163 return val 00164 00165 def getboolean(self, option, default = None, section = None): 00166 """ 00167 Get a boolean option, perhaps with a default value. 00168 """ 00169 v = self.get(option, default, section) 00170 if isinstance(v, str): 00171 v = v.lower() 00172 if v not in self.cfg._boolean_states: 00173 raise ValueError, "Not a boolean: %s" % v 00174 v = self.cfg._boolean_states[v] 00175 return v 00176 00177 def getint(self, option, default = None, section = None): 00178 """ 00179 Get an integer option, perhaps with a default value. 00180 """ 00181 return int(self.get(option, default, section)) 00182 00183 def getlong(self, option, default = None, section = None): 00184 """ 00185 Get a long integer option, perhaps with a default value. 00186 """ 00187 return long(self.get(option, default, section)) 00188 00189 def set_global_flags(self): 00190 """ 00191 Consolidated control for all the little global control flags 00192 scattered through the libraries. This isn't a particularly good 00193 place for this function to live, but it has to live somewhere and 00194 making it a method of the config parser from which it gets all of 00195 its data is less silly than the available alternatives. 00196 """ 00197 00198 import rpki.http, rpki.x509, rpki.sql, rpki.async, rpki.log 00199 00200 try: 00201 rpki.http.debug_http = self.getboolean("debug_http") 00202 except ConfigParser.NoOptionError: 00203 pass 00204 00205 try: 00206 rpki.http.want_persistent_client = self.getboolean("want_persistent_client") 00207 except ConfigParser.NoOptionError: 00208 pass 00209 00210 try: 00211 rpki.http.want_persistent_server = self.getboolean("want_persistent_server") 00212 except ConfigParser.NoOptionError: 00213 pass 00214 00215 try: 00216 rpki.http.use_adns = self.getboolean("use_adns") 00217 except ConfigParser.NoOptionError: 00218 pass 00219 00220 try: 00221 rpki.http.enable_ipv6_clients = self.getboolean("enable_ipv6_clients") 00222 except ConfigParser.NoOptionError: 00223 pass 00224 00225 try: 00226 rpki.http.enable_ipv6_servers = self.getboolean("enable_ipv6_servers") 00227 except ConfigParser.NoOptionError: 00228 pass 00229 00230 try: 00231 rpki.x509.CMS_object.debug_cms_certs = self.getboolean("debug_cms_certs") 00232 except ConfigParser.NoOptionError: 00233 pass 00234 00235 try: 00236 rpki.sql.sql_persistent.sql_debug = self.getboolean("sql_debug") 00237 except ConfigParser.NoOptionError: 00238 pass 00239 00240 try: 00241 rpki.async.timer.gc_debug = self.getboolean("gc_debug") 00242 except ConfigParser.NoOptionError: 00243 pass 00244 00245 try: 00246 rpki.async.timer.run_debug = self.getboolean("timer_debug") 00247 except ConfigParser.NoOptionError: 00248 pass 00249 00250 try: 00251 rpki.x509.XML_CMS_object.dump_outbound_cms = rpki.x509.DeadDrop(self.get("dump_outbound_cms")) 00252 except ConfigParser.NoOptionError: 00253 pass 00254 00255 try: 00256 rpki.x509.XML_CMS_object.dump_inbound_cms = rpki.x509.DeadDrop(self.get("dump_inbound_cms")) 00257 except ConfigParser.NoOptionError: 00258 pass 00259 00260 try: 00261 rpki.async.gc_summary(self.getint("gc_summary"), self.getint("gc_summary_threshold", 0)) 00262 except ConfigParser.NoOptionError: 00263 pass 00264 00265 try: 00266 rpki.log.enable_tracebacks = self.getboolean("enable_tracebacks") 00267 except ConfigParser.NoOptionError: 00268 pass