# This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Copyright 2005 Dan Williams and Red Hat, Inc. import os import fnmatch from ConfigParser import ConfigParser from plague import BaseConfig import Builder def make_target_string(distro, target, repo): return "%s-%s-%s" % (distro, target, repo) class InvalidTargetException(Exception): pass class InvalidUserAliasException(Exception): pass class ServerConfig(BaseConfig.BaseConfig): def __init__(self, filename): BaseConfig.BaseConfig.__init__(self, filename) try: self.open() except BaseConfig.ConfigError: print "Config file did not exist. Writing %s with default values." % filename self.save_default_config() self._targets = [] self._target_strings = {} self._target_aliases = {} self._builders = self._load_builders() def targets(self): return self._targets def builders(self): return self._builders def resolve_target_user_alias(self, user_alias): try: cfg = self._target_aliases[user_alias.lower()] except KeyError: raise InvalidUserAliasException("Invalid user alias.") return cfg def resolve_target_string(self, target_str): try: cfg = self._target_strings[target_str] except KeyError: raise InvalidTargetException("Invalid target string.") return cfg def _add_target(self, target_cfg): """ Return True if the target name is OK, False otherwise """ target_str = target_cfg.target_string() if self._target_strings.has_key(target_str): raise InvalidTargetException("Target name '%s' already exists." % target_str) aliases = target_cfg.get_list("Aliases", "user_aliases") for alias in aliases: alias = alias.lower() if self._target_aliases.has_key(alias): target_str = self._target_aliases[alias].target_string() raise InvalidTargetException("Target alias '%s' already exists in target %s." % (alias, target_str)) # We're OK, add it to our list self._targets.append(target_cfg) self._target_strings[target_cfg.target_string()] = target_cfg for alias in aliases: self._target_aliases[alias.lower()] = target_cfg def load_target_configs(self): cfg_dir = self.get_str("Directories", "target_configs_dir") if not os.path.exists(cfg_dir) or not os.access(cfg_dir, os.R_OK): return # Don't ever load targets twice if len(self._targets) > 0: return files = os.listdir(cfg_dir) for f in files: if not f.endswith(".cfg"): continue cfg_file = os.path.join(cfg_dir, f) target_cfg = TargetConfig(self, cfg_file) try: self._add_target(target_cfg) except InvalidTargetException, e: print "Error: could not add target %s because: %s" % (f, e) def _get_builders_of_type(self, btype): if btype == Builder.TYPE_PASSIVE: section = "Passive Builders" elif btype == Builder.TYPE_ACTIVE: section = "Active Builders" else: raise Exception("Unknown builder type %d" % btype) if not self._config.has_section(section): return {} prefix = "http://" if self.get_bool("Builders", "use_ssl") == True: prefix = "https://" items = self._config.items(section) list = {} for (tag, builder) in items: if not tag.startswith("builder"): continue weight = 0 weight_str = "0" addr = None try: (weight_str, addr) = builder.split() except ValueError: pass try: weight = int(weight_str) except ValueError: weight = 0 # Rewrite addresses to match current builder connection method new_addr = addr if addr.startswith("http://"): new_addr = addr[7:] elif addr.startswith("https://"): new_addr = addr[8:] if new_addr: list[prefix + new_addr] = (weight, btype) return list def _load_builders(self): passive_builders = self._get_builders_of_type(Builder.TYPE_PASSIVE) active_builders = self._get_builders_of_type(Builder.TYPE_ACTIVE) builders = {} for key in active_builders.keys(): builders[key] = active_builders[key] for key in passive_builders.keys(): builders[key] = passive_builders[key] return builders def save_default_config(self, filename=None): self.add_section("General") self.set_option("General", "hostname", "localhost") self.set_option("General", "traceback_server", "no") self.set_option("General", "depsolve_jobs", "yes") self.add_section("Directories") self.set_option("Directories", "server_work_dir", "/rpmbuild",) self.set_option("Directories", "repo_dir", "/repodir") self.set_option("Directories", "tmpdir", "/tmp") self.set_option("Directories", "target_configs_dir", "/etc/plague/server/targets") self.set_option("Directories", "mock_configs_dir", "/etc/mock") self.add_section("Email") self.set_option("Email", "email_from", "buildsys@foo.com") self.set_option("Email", "admin_emails", "") self.set_option("Email", "success_emails", "") self.add_section("Builders") self.set_option("Builders", "use_ssl", "yes") self.add_section("Active Builders") self.set_option("Active Builders", "xmlrpc_server_port", "8889") self.set_option("Active Builders", "file_server_port", "8890") self.set_option("Active Builders", "builder1", "20 127.0.0.1") self.set_option("Active Builders", "builder2", "0 127.0.0.2") self.add_section("Passive Builders") self.set_option("Passive Builders", "builder1", "20 127.0.0.1:8888") self.add_section("SSL") self.set_option("SSL", "server_key_and_cert", "/etc/plague/server/certs/server_key_and_cert.pem") self.set_option("SSL", "ca_cert", "/etc/plague/server/certs/ca_cert.pem") self.add_section("CVS") self.set_option("CVS", "use_cvs", "no") self.add_section("UI") self.set_option("UI", "use_ssl", "yes") self.set_option("UI", "client_ca_cert", "/etc/plague/server/certs/ui_ca_cert.pem") self.set_option("UI", "port", "8887") self.set_option("UI", "guest_allowed", "yes") self.set_option("UI", "log_url", "http://www.foo.com/logs/") self.add_section("Database") self.set_option("Database", "engine", "sqlite") self.add_section("sqlite Engine") self.set_option("sqlite Engine", "database", "/etc/plague/server/jobdb") self.set_option("sqlite Engine", "timeout", "3") self.add_section("pgdb Engine") self.set_option("pgdb Engine", "host", "localhost") self.set_option("pgdb Engine", "database", "plague") self.set_option("pgdb Engine", "user", "plague") self.set_option("pgdb Engine", "password", "") self.add_section("mysql Engine") self.set_option("mysql Engine", "host", "localhost") self.set_option("mysql Engine", "database", "plague") self.set_option("mysql Engine", "user", "plague") self.set_option("mysql Engine", "password", "") self.save() class TargetConfig(BaseConfig.BaseConfig): def __init__(self, cfg, filename): BaseConfig.BaseConfig.__init__(self, filename) try: self.open() except BaseConfig.ConfigError: print "Config file did not exist. Writing %s with default values." % filename self.save_default_config() self._parent_cfg = cfg self._distro = self.get_str("General", "distro") self._target = self.get_str("General", "target") self._base_arches = self.get_list("Arches", "base_arches") self._opt_arches = self.get_list("Arches", "optional_arches") self._repo = self.get_str("General", "repo") self._testing = self.get_bool("General", "testing") self._mock_configs = self._find_mock_configs() self._addl_pkg_arches = self._get_addl_pkg_arches() def _find_mock_configs(self): mock_configs = {} mock_config_dir = self._parent_cfg.get_str("Directories", "mock_configs_dir") for arch in self._base_arches: mock_config_file = "%s-%s-%s-%s.cfg" % (self._distro, self._target, arch, self._repo) f = os.path.join(mock_config_dir, mock_config_file) if not os.path.exists(f) or not os.access(f, os.R_OK): print """%s: Could not find mock config file for %s. Each base_archs arch must have a matching mock config in mock_configs_dir for this target.""" % (self._filename, mock_config_file) os._exit(0) mock_configs[arch] = f return mock_configs def parent_cfg(self): return self._parent_cfg def mock_config_for_arch(self, arch): return self._mock_configs[arch] def target_dict(self, arch=None): target_dict = {} target_dict['distro'] = self._distro target_dict['target'] = self._target target_dict['arch'] = arch target_dict['repo'] = self._repo return target_dict def target_string(self): return make_target_string(self._distro, self._target, self._repo) def distro(self): return self._distro def target(self): return self._target def basearches(self): return self._base_arches def optarches(self): return self._opt_arches def repo(self): return self._repo def testing(self): return self._testing def _get_addl_pkg_arches(self): if not self._config.has_section("Additional Package Arches"): return {} items = self._config.items("Additional Package Arches") addl_arches = {} for (pkg, arches) in items: if type(arches) != type("") or not len(arches): continue try: l = arches.split() except Exception, e: continue addl_arches[pkg] = l return addl_arches def addl_arches_for_pkg(self, name): # Match package name against Additional Package Arches # entries, taking wildcards into account for item in self._addl_pkg_arches.keys(): if fnmatch.fnmatchcase(name, item): return self._addl_pkg_arches[item] return [] def save_default_config(self, filename=None): self.add_section("General") self.set_option("General", "distro", "fedora") self.set_option("General", "target", "development") self.set_option("General", "repo", "core") self.set_option("General", "testing", "no") self.set_option("General", "repo_script", "") self.add_section("Arches") self.set_option("Arches", "base_arches", "i386") self.set_option("Arches", "optional_arches", "") self.add_section("Aliases") self.set_option("Aliases", "cvs_alias", "devel") self.set_option("Aliases", "user_aliases", "devel") self.add_section("Additional Package Arches") self.set_option("Additional Package Arches", "kernel", "i686") self.add_section("CVS") self.set_option("CVS", "cvs_root", "") self.set_option("CVS", "cvs_rsh", "") self.save()