summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2013-03-12 03:30:04 +0100
committerAlexander Sulfrian <alexander@sulfrian.net>2015-05-10 16:25:27 +0200
commit0d241e55c4cd60e534571fd8e19b69ebadc58a12 (patch)
treed5ca5dca6797a6926febc8b2f04d1eaf4ef4d77b
parent6db515b7110aa7a4248eab3e2e341c08ad9221f5 (diff)
downloadbcfg2-0d241e55c4cd60e534571fd8e19b69ebadc58a12.tar.gz
bcfg2-0d241e55c4cd60e534571fd8e19b69ebadc58a12.tar.bz2
bcfg2-0d241e55c4cd60e534571fd8e19b69ebadc58a12.zip
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.
-rw-r--r--schemas/packages.xsd1
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Layman.py142
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Portage.py8
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/__init__.py2
4 files changed, 152 insertions, 1 deletions
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 @@
<xsd:enumeration value="pac"/>
<xsd:enumeration value="pkgng"/>
<xsd:enumeration value="portage"/>
+ <xsd:enumeration value="layman"/>
</xsd:restriction>
</xsd:simpleType>
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 92ad64c13..7cde453ff 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",