def read_kv_conf(filepath): """Reads a flat Cuckoo key/value configuration file.""" ret = {} for line in open(filepath, "rb"): line = line.strip() if not line or line.startswith("#"): continue if "=" not in line: raise CuckooConfigurationError( "Invalid flat configuration line: %s (missing '=' character)" % line) key, raw_value = line.split("=", 1) key, raw_value = key.replace(".", ":").strip(), raw_value.strip() try: value = cast(key, raw_value) except (CuckooConfigurationError, RuntimeError) as e: raise CuckooConfigurationError( "Invalid flat configuration line: %s (error %s)" % (line, e)) if raw_value and value is None: raise CuckooConfigurationError( "Invalid flat configuration entry: %s is None" % key) a, b, c = key.split(":") ret[a] = ret.get(a, {}) ret[a][b] = ret[a].get(b, {}) ret[a][b][c] = value return ret
def config(s, cfg=None, strict=False, raw=False, loose=False, check=False): """Fetch a configuration value, denoted as file:section:key.""" if s.count(":") != 2: raise RuntimeError("Invalid configuration entry: %s" % s) file_name, section, key = s.split(":") if check: strict = raw = loose = True type_ = Config.configuration.get(file_name, {}).get(section, {}).get(key) if strict and type_ is None: raise CuckooConfigurationError( "No such configuration value exists: %s" % s ) required = type_ is not None and type_.required index = file_name, cfg, cwd(), strict, raw, loose if index not in _cache: _cache[index] = Config( file_name, cfg=cfg, strict=strict, raw=raw, loose=loose ) config = _cache[index] if strict and required and section not in config.sections: raise CuckooConfigurationError( "Configuration value %s not present! This may indicate that " "you've incorrectly filled out the Cuckoo configuration, " "please double check it." % s ) section = config.sections.get(section, {}) if strict and required and key not in section: raise CuckooConfigurationError( "Configuration value %s not present! This may indicate that " "you've incorrectly filled out the Cuckoo configuration, " "please double check it." % s ) value = section.get(key, type_.default if type_ else None) if check and not type_.check(value): raise CuckooConfigurationError( "The configuration value %r found for %s is invalid. Please " "update your configuration!" % (value, s) ) return value
def get_section_types(self, file_name, section, strict=False, loose=False): """Get types for a section entry.""" section_types = get_section_types(file_name, section) if not section_types and not loose: log.error("Config section %s:%s not found!", file_name, section) if strict: raise CuckooConfigurationError( "Config section %s:%s not found!", file_name, section) return return section_types
def get(self, section): """Get option. @param section: section to fetch. @raise CuckooConfigurationError: if section not found. @return: option value. """ if section not in self.sections: raise CuckooConfigurationError( "Option %s is not found in configuration" % section) return self.sections[section]
def cast(s, value): """Cast a configuration value as per its type.""" if s.count(":") != 2: raise RuntimeError("Invalid configuration entry: %s" % s) file_name, section, key = s.split(":") type_ = get_section_types(file_name, section).get(key) if type_ is None: raise CuckooConfigurationError( "No such configuration value exists: %s" % s) return type_.parse(value)
def config2(file_name, section): keys = get_section_types(file_name, section, strict=True) if not keys: raise CuckooConfigurationError( "No such configuration section exists: %s:%s" % (file_name, section)) ret = Dictionary() for key in keys: if key == "__star__" or key == "*": continue ret[key] = config("%s:%s:%s" % (file_name, section, key)) return ret
def __init__(self, file_name="cuckoo", cfg=None, strict=False, loose=False, raw=False): """ @param file_name: file name without extension. @param cfg: configuration file path. """ env = {} for key, value in os.environ.items(): if key.startswith("CUCKOO_"): env[key] = value env["CUCKOO_CWD"] = cwd() env["CUCKOO_APP"] = os.environ.get("CUCKOO_APP", "") config = ConfigParser.ConfigParser(env) self.env_keys = [] for key in env.keys(): self.env_keys.append(key.lower()) self.sections = {} try: config.read(cfg or cwd("conf", "%s.conf" % file_name)) except ConfigParser.ParsingError as e: raise CuckooConfigurationError( "There was an error reading in the $CWD/conf/%s.conf " "configuration file. Most likely there are leading " "whitespaces in front of one of the key=value lines defined. " "More information from the original exception: %s" % (file_name, e)) if file_name not in self.configuration and not loose: log.error("Unknown config file %s.conf", file_name) return for section in config.sections(): types = self.get_section_types(file_name, section, strict, loose) if types is None: continue self.sections[section] = Dictionary() setattr(self, section, self.sections[section]) try: items = config.items(section) except ConfigParser.InterpolationMissingOptionError as e: log.error("Missing environment variable(s): %s", e) raise CuckooConfigurationError( "Missing environment variable: %s" % e) except ValueError as e: if e.message == "incomplete format key": raise CuckooConfigurationError( "One of the fields that you've filled out in " "$CWD/conf/%s contains the sequence '%(' which is " "interpreted as environment variable sequence, e.g., " "'%(PGPASSWORD)s' would locate a PostgreSQL " "password. Please update the field to correctly " "state the environment variable or change it in a " "way that '%(' is no longer in the variable.") raise for name, raw_value in items: if name in self.env_keys: continue if "\n" in raw_value: wrong_key = "???" try: wrong_key = raw_value.split("\n", 1)[1].split()[0] except: pass raise CuckooConfigurationError( "There was an error reading in the $CWD/conf/%s.conf " "configuration file. Namely, there are one or more " "leading whitespaces before the definition of the " "'%s' key/value pair in the '%s' section. Please " "remove those leading whitespaces as Python's default " "configuration parser is unable to handle those " "properly." % (file_name, wrong_key, section)) if not raw and name in types: # TODO Is this the area where we should be checking the # configuration values? # if not types[name].check(raw_value): # print file_name, section, name, raw_value # raise value = types[name].parse(raw_value) else: if not loose: log.error( "Type of config parameter %s:%s:%s not found! " "This may indicate that you've incorrectly filled " "out the Cuckoo configuration, please double " "check it.", file_name, section, name) value = raw_value self.sections[section][name] = value
def write_cuckoo_conf(cfg=None): if cfg is None: cfg = {} # Merge any provided configuration with the defaults and emit their values. raw = {} for filename, sections in Config.configuration.items(): cfg[filename] = cfg.get(filename, {}) raw[filename] = {} for section, entries in sections.items(): if section == "__star__": continue # Process each entry. if not isinstance(entries, (tuple, list)): entries = entries, for entry in entries: real_section = entry.get("__section__", section) entries = cfg[filename].get(section, {}) entries.update(cfg[filename].get(real_section, {})) cfg[filename][real_section] = entries raw[filename][real_section] = {} for key, value in entry.items(): if key == "__section__": continue raw_value = cfg[filename][real_section].get(key, value.default) cfg[filename][real_section][key] = raw_value raw[filename][real_section][key] = value.emit(raw_value) if "__star__" in sections: section, key = sections["__star__"] for entry in cfg[filename][section][key]: if entry not in cfg[filename]: raise CuckooConfigurationError( "A section was defined that has not been found: " "%s:%s" % (section, entry) ) if isinstance(sections["*"], (tuple, list)): section_types = sections["*"][0] else: section_types = sections["*"] raw[filename][entry] = {} for key, value in section_types.items(): if key == "__section__": continue if key not in cfg[filename][entry]: raw_value = cfg[filename][entry][key] = None else: raw_value = cfg[filename][entry][key] raw[filename][entry][key] = value.emit(raw_value) def _config(s): filename, section, key = s.split(":") return cfg[filename][section][key] raw["config"] = _config for filename in os.listdir(cwd("cwd", "conf", private=True)): template = jinja2.Template( open(cwd("cwd", "conf", filename, private=True), "rb").read() ) open(cwd("conf", filename), "wb").write( template.render(raw).rstrip() + "\n" )