From d5b267825e357d8d538fcc813f2ddde58f47785a Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 12 Mar 2013 03:30:04 +0100 Subject: Plugins/Packages/Layman: add support for layman overlays In combination with the PortageCollection the Packages plugin could now handle layman overlays. The Portage collection evaluates the dependencies with respect to the configured overlays. --- schemas/packages.xsd | 1 + src/lib/Bcfg2/Server/Plugins/Packages/Layman.py | 142 ++++++++++++++++++++++ src/lib/Bcfg2/Server/Plugins/Packages/Portage.py | 8 ++ src/lib/Bcfg2/Server/Plugins/Packages/__init__.py | 2 +- 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/lib/Bcfg2/Server/Plugins/Packages/Layman.py diff --git a/schemas/packages.xsd b/schemas/packages.xsd index aede2f815..08c51a1d1 100644 --- a/schemas/packages.xsd +++ b/schemas/packages.xsd @@ -19,6 +19,7 @@ + diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Layman.py b/src/lib/Bcfg2/Server/Plugins/Packages/Layman.py new file mode 100644 index 000000000..19877d32b --- /dev/null +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Layman.py @@ -0,0 +1,142 @@ +import os +import layman +import Bcfg2.Server.Plugin + +class LaymanSource(Bcfg2.Server.Plugin.Debuggable): + basegroups = ['portage', 'gentoo', 'emerge'] + ptype = 'layman' + cclass = 'Portage' + + def __init__(self, basepath, xsource): + Bcfg2.Server.Plugin.Debuggable.__init__(self) + self.basepath = basepath + self.xsource = xsource + + self.url = xsource.get('url', 'http://www.gentoo.org/proj/en/overlays/repositories.xml') + self.name = xsource.get('name', '') + self.priority = xsource.get('priority', 0) + self.cachefile = None + self.gpgkeys = [] + self.recommended = False + self.essentialpkgs = set() + self.arches = [item.text for item in xsource.findall('Arch')] + + self.url_map = [dict(version=None, component=None, arch=arch, + url=self.url, baseurl=self.url) for arch in self.arches] + + #: A list of the the names of packages that are blacklisted + #: from this source + self.blacklist = [item.text for item in xsource.findall('Blacklist')] + + #: A list of the the names of packages that are whitelisted in + #: this source + self.whitelist = [item.text for item in xsource.findall('Whitelist')] + + + # configure layman + base = os.path.join(basepath, 'layman') + storage = os.path.join(base, 'overlays') + config = layman.config.OptionConfig(options = { + 'storage': os.path.join(base, 'overlays'), + 'cache': os.path.join(base, 'cache'), + 'installed': os.path.join(base, 'installed.xml'), + 'local_list': os.path.join(base, 'overlays.xml'), + 'overlays': [self.url] + }) + self.api = layman.LaymanAPI(config) + + # path + self.dir = os.path.join(storage, self.name) + + # build the set of conditions to see if this source applies to + # a given set of metadata + self.conditions = [] + self.groups = [] # provided for some limited backwards compat + for el in xsource.iterancestors(): + if el.tag == "Group": + if el.get("negate", "false").lower() == "true": + self.conditions.append(lambda m, el=el: + el.get("name") not in m.groups) + else: + self.groups.append(el.get("name")) + self.conditions.append(lambda m, el=el: + el.get("name") in m.groups) + elif el.tag == "Client": + if el.get("negate", "false").lower() == "true": + self.conditions.append(lambda m, el=el: + el.get("name") != m.hostname) + else: + self.conditions.append(lambda m, el=el: + el.get("name") == m.hostname) + + def get_repo_name(self, url_map): + return self.name + + def save_state(self): + pass + + def load_state(self): + pass + + def filter_unknown(self, unknown): + filtered = set([u for u in unknown if u.startswith('choice')]) + unknown.difference_update(filtered) + + def get_urls(self): + return self.url + urls = property(get_urls) + + def setup_data(self, force_update=False): + self.api.fetch_remote_list() + if not self.api.is_repo(self.name): + self.logger.error("Packages: Layman overlay '%s' not" + " found" % self.name) + return False + + if not self.api.is_installed(self.name): + self.logger.info("Packages: Adding layman overlay '%s'" % + self.name) + if not self.api.add_repos(self.name): + self.logger.error("Packages: Failed adding layman" + " overlay '%s'" % self.name) + return False + + if force_update: + if not self.api.sync(self.name): + self.logger.error("Packages: Failed syncing layman" + " overlay '%s'" % self.name) + return False + + return True + + + def applies(self, metadata): + """ Return true if this source applies to the given client, + i.e., the client is in all necessary groups. + + :param metadata: The client metadata to check to see if this + source applies + :type metadata: Bcfg2.Server.Plugins.Metadata.ClientMetadata + :returns: bool + """ + # check arch groups + if not self.arch_groups_match(metadata): + return False + + # check Group/Client tags from sources.xml + for condition in self.conditions: + if not condition(metadata): + return False + + return True + + def arch_groups_match(self, metadata): + """ Returns True if the client is in an arch group that + matches the arch of this source. + + :returns: bool + """ + for arch in self.arches: + if arch in metadata.groups: + return True + return False diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py b/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py index a74bf5e4a..4ddadb701 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Portage.py @@ -6,6 +6,7 @@ import lxml.etree import Bcfg2.Options import Bcfg2.Server.Plugin from Bcfg2.Server.Plugins.Packages.Collection import Collection +from Bcfg2.Server.Plugins.Packages.Layman import LaymanSource _portage_python = '/usr/lib/portage/pym/' @@ -146,6 +147,13 @@ class PortageCollection(Collection): env = portage.settings.configdict['backupenv'] + # add layman overlays + env['PORTDIR_OVERLAY'] = '' + for overlay in self: + if isinstance(overlay, LaymanSource): + env['PORTDIR_OVERLAY'] += ' ' + env['PORTDIR_OVERLAY'] += overlay.dir + portage.settings = portage.package.ebuild.config.config( config_root=portage.settings['PORTAGE_CONFIGROOT'], target_root=portage.settings['ROOT'], diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py index 570b020f6..8ddc050f7 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/__init__.py @@ -103,7 +103,7 @@ class Packages(Bcfg2.Server.Plugin.Plugin, help="Packages backends to load", type=Bcfg2.Options.Types.comma_list, action=PackagesBackendAction, - default=['Yum', 'Apt', 'Pac', 'Pkgng', 'Portage']), + default=['Yum', 'Apt', 'Pac', 'Pkgng', 'Portage', 'Layman']), Bcfg2.Options.PathOption( cf=("packages", "cache"), dest="packages_cache", help="Path to the Packages cache", -- cgit v1.2.3-1-g7c22