summaryrefslogtreecommitdiffstats
path: root/build/lib/Bcfg2/Server/Plugins/Packages.py
diff options
context:
space:
mode:
Diffstat (limited to 'build/lib/Bcfg2/Server/Plugins/Packages.py')
-rw-r--r--build/lib/Bcfg2/Server/Plugins/Packages.py869
1 files changed, 0 insertions, 869 deletions
diff --git a/build/lib/Bcfg2/Server/Plugins/Packages.py b/build/lib/Bcfg2/Server/Plugins/Packages.py
deleted file mode 100644
index 194330723..000000000
--- a/build/lib/Bcfg2/Server/Plugins/Packages.py
+++ /dev/null
@@ -1,869 +0,0 @@
-import cPickle
-import copy
-import gzip
-import tarfile
-import glob
-import logging
-import lxml.etree
-import os
-import re
-import sys
-import urllib2
-
-# FIXME: Remove when server python dep is 2.5 or greater
-if sys.version_info >= (2, 5):
- from hashlib import md5
-else:
- from md5 import md5
-
-import Bcfg2.Logger
-import Bcfg2.Server.Plugin
-
-# build sources.list?
-# caching for yum
-
-class NoData(Exception):
- pass
-
-class SomeData(Exception):
- pass
-
-logger = logging.getLogger('Packages')
-
-def source_from_xml(xsource):
- ret = dict([('rawurl', False), ('url', False)])
- for key, tag in [('groups', 'Group'), ('components', 'Component'),
- ('arches', 'Arch'), ('blacklist', 'Blacklist'),
- ('whitelist', 'Whitelist')]:
- ret[key] = [item.text for item in xsource.findall(tag)]
- # version and component need to both contain data for sources to work
- try:
- ret['version'] = xsource.find('Version').text
- except:
- ret['version'] = 'placeholder'
- if ret['components'] == []:
- ret['components'] = ['placeholder']
- try:
- if xsource.find('Recommended').text in ['True', 'true']:
- ret['recommended'] = True
- else:
- ret['recommended'] = False
- except:
- ret['recommended'] = False
- if xsource.find('RawURL') is not None:
- ret['rawurl'] = xsource.find('RawURL').text
- if not ret['rawurl'].endswith('/'):
- ret['rawurl'] += '/'
- else:
- ret['url'] = xsource.find('URL').text
- if not ret['url'].endswith('/'):
- ret['url'] += '/'
- return ret
-
-def _fetch_url(url):
- if '@' in url:
- mobj = re.match('(\w+://)([^:]+):([^@]+)@(.*)$', url)
- if not mobj:
- raise ValueError
- user = mobj.group(2)
- passwd = mobj.group(3)
- url = mobj.group(1) + mobj.group(4)
- auth = urllib2.HTTPBasicAuthHandler(urllib2.HTTPPasswordMgrWithDefaultRealm())
- auth.add_password(None, url, user, passwd)
- urllib2.install_opener(urllib2.build_opener(auth))
- return urllib2.urlopen(url).read()
-
-class Source(object):
- basegroups = []
-
- def __init__(self, basepath, url, version, arches, components, groups, rawurl,
- blacklist, whitelist, recommended):
- self.basepath = basepath
- self.version = version
- self.components = components
- self.url = url
- self.rawurl = rawurl
- self.groups = groups
- self.arches = arches
- self.deps = dict()
- self.provides = dict()
- self.blacklist = set(blacklist)
- self.whitelist = set(whitelist)
- self.cachefile = '%s/cache-%s' % (self.basepath, md5(cPickle.dumps( \
- [self.version, self.components, self.url, \
- self.rawurl, self.groups, self.arches])).hexdigest())
- self.recommended = recommended
- self.url_map = []
-
- def load_state(self):
- pass
-
- def setup_data(self, force_update=False):
- should_read = True
- should_download = False
- if os.path.exists(self.cachefile):
- try:
- self.load_state()
- should_read = False
- except:
- logger.error("Cachefile %s load failed; falling back to file read"\
- % (self.cachefile))
- if should_read:
- try:
- self.read_files()
- except:
- logger.error("Packages: File read failed; falling back to file download")
- should_download = True
-
- if should_download or force_update:
- try:
- self.update()
- self.read_files()
- except:
- logger.error("Failed to update source", exc_info=1)
-
- def get_urls(self):
- return []
- urls = property(get_urls)
-
- def get_files(self):
- return [self.escape_url(url) for url in self.urls]
- files = property(get_files)
-
- def get_vpkgs(self, meta):
- agroups = ['global'] + [a for a in self.arches if a in meta.groups]
- vdict = dict()
- for agrp in agroups:
- for key, value in self.provides[agrp].iteritems():
- if key not in vdict:
- vdict[key] = set(value)
- else:
- vdict[key].update(value)
- return vdict
-
- def escape_url(self, url):
- return "%s/%s" % (self.basepath, url.replace('/', '@'))
-
- def file_init(self):
- pass
-
- def read_files(self):
- pass
-
- def update(self):
- for url in self.urls:
- logger.info("Packages: Updating %s" % url)
- fname = self.escape_url(url)
- try:
- data = _fetch_url(url)
- except ValueError:
- logger.error("Packages: Bad url string %s" % url)
- continue
- except urllib2.HTTPError, h:
- logger.error("Packages: Failed to fetch url %s. code=%s" \
- % (url, h.code))
- continue
- file(fname, 'w').write(data)
-
- def applies(self, metadata):
- return len([g for g in self.basegroups if g in metadata.groups]) != 0 and \
- len([g for g in metadata.groups if g in self.groups]) \
- == len(self.groups)
-
- def get_arches(self, metadata):
- return ['global'] + [a for a in self.arches if a in metadata.groups]
-
- def get_deps(self, metadata, pkgname):
- for arch in self.get_arches(metadata):
- if pkgname in self.deps[arch]:
- return self.deps[arch][pkgname]
- raise NoData
-
- def get_provides(self, metadata, required):
- for arch in self.get_arches(metadata):
- if required in self.provides[arch]:
- return self.provides[arch][required]
- raise NoData
-
- def is_package(self, metadata, _):
- return False
-
- def get_url_info(self):
- return {'groups': copy.copy(self.groups), \
- 'urls': [copy.deepcopy(url) for url in self.url_map]}
-
-class YUMSource(Source):
- xp = '{http://linux.duke.edu/metadata/common}'
- rp = '{http://linux.duke.edu/metadata/rpm}'
- rpo = '{http://linux.duke.edu/metadata/repo}'
- fl = '{http://linux.duke.edu/metadata/filelists}'
- basegroups = ['yum', 'redhat', 'centos', 'fedora']
- ptype = 'yum'
-
- def __init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended):
- Source.__init__(self, basepath, url, version, arches, components,
- groups, rawurl, blacklist, whitelist, recommended)
- if not self.rawurl:
- self.baseurl = self.url + '%(version)s/%(component)s/%(arch)s/'
- else:
- self.baseurl = self.rawurl
- self.packages = dict()
- self.deps = dict([('global', dict())])
- self.provides = dict([('global', dict())])
- self.filemap = dict([(x, dict()) for x in ['global'] + self.arches])
- self.needed_paths = set()
- self.file_to_arch = dict()
-
- def save_state(self):
- cache = file(self.cachefile, 'wb')
- cPickle.dump((self.packages, self.deps, self.provides,
- self.filemap, self.url_map), cache, 2)
- cache.close()
-
- def load_state(self):
- data = file(self.cachefile)
- (self.packages, self.deps, self.provides, \
- self.filemap, self.url_map) = cPickle.load(data)
-
- def get_urls(self):
- surls = list()
- self.url_map = []
- for arch in self.arches:
- usettings = [{'version': self.version, 'component':comp,
- 'arch':arch} for comp in self.components]
- for setting in usettings:
- setting['groups'] = self.groups
- setting['url'] = self.baseurl % setting
- self.url_map.append(copy.deepcopy(setting))
- surls.append((arch, [setting['url'] for setting in usettings]))
- urls = []
- for (sarch, surl_list) in surls:
- for surl in surl_list:
- if not surl.endswith('/'):
- surl += '/'
- rmdurl = surl + 'repodata/repomd.xml'
- try:
- repomd = _fetch_url(rmdurl)
- xdata = lxml.etree.XML(repomd)
- except ValueError:
- logger.error("Packages: Bad url string %s" % rmdurl)
- continue
- except urllib2.HTTPError, h:
- logger.error("Packages: Failed to fetch url %s. code=%s" \
- % (rmdurl, h.code))
- continue
- except:
- logger.error("Failed to process url %s" % rmdurl)
- continue
- for elt in xdata.findall(self.rpo + 'data'):
- if elt.get('type') not in ['filelists', 'primary']:
- continue
- floc = elt.find(self.rpo + 'location')
- fullurl = surl + floc.get('href')
- urls.append(fullurl)
- self.file_to_arch[self.escape_url(fullurl)] = sarch
- return urls
- urls = property(get_urls)
-
- def read_files(self):
- for fname in [f for f in self.files if f.endswith('primary.xml.gz')]:
- farch = self.file_to_arch[fname]
- fdata = lxml.etree.parse(fname).getroot()
- self.parse_primary(fdata, farch)
- for fname in [f for f in self.files if f.endswith('filelists.xml.gz')]:
- farch = self.file_to_arch[fname]
- fdata = lxml.etree.parse(fname).getroot()
- self.parse_filelist(fdata, farch)
- # merge data
- sdata = self.packages.values()
- self.packages['global'] = copy.deepcopy(sdata.pop())
- while sdata:
- self.packages['global'].intersection(sdata.pop())
-
- for key in self.packages:
- if key == 'global':
- continue
- self.packages[key] = self.packages['global'].difference(self.packages[key])
- self.save_state()
-
- def parse_filelist(self, data, arch):
- if arch not in self.filemap:
- self.filemap[arch] = dict()
- for pkg in data.findall(self.fl + 'package'):
- for fentry in [fe for fe in pkg.findall(self.fl + 'file') \
- if fe.text in self.needed_paths]:
- if fentry.text in self.filemap[arch]:
- self.filemap[arch][fentry.text].add(pkg.get('name'))
- else:
- self.filemap[arch][fentry.text] = set([pkg.get('name')])
-
- def parse_primary(self, data, arch):
- if arch not in self.packages:
- self.packages[arch] = set()
- if arch not in self.deps:
- self.deps[arch] = dict()
- if arch not in self.provides:
- self.provides[arch] = dict()
- for pkg in data.getchildren():
- if not pkg.tag.endswith('package'):
- continue
- pkgname = pkg.find(self.xp + 'name').text
- self.packages[arch].add(pkgname)
-
- pdata = pkg.find(self.xp + 'format')
- pre = pdata.find(self.rp + 'requires')
- self.deps[arch][pkgname] = set()
- for entry in pre.getchildren():
- self.deps[arch][pkgname].add(entry.get('name'))
- if entry.get('name').startswith('/'):
- self.needed_paths.add(entry.get('name'))
- pro = pdata.find(self.rp + 'provides')
- if pro != None:
- for entry in pro.getchildren():
- prov = entry.get('name')
- if prov not in self.provides[arch]:
- self.provides[arch][prov] = list()
- self.provides[arch][prov].append(pkgname)
-
- def is_package(self, metadata, item):
- arch = [a for a in self.arches if a in metadata.groups]
- if not arch:
- return False
- return (item in self.packages['global'] or item in self.packages[arch[0]]) and \
- item not in self.blacklist and \
- ((len(self.whitelist) == 0) or item in self.whitelist)
-
- def get_vpkgs(self, metadata):
- rv = Source.get_vpkgs(self, metadata)
- for arch, fmdata in self.filemap.iteritems():
- if arch not in metadata.groups and arch != 'global':
- continue
- for filename, pkgs in fmdata.iteritems():
- rv[filename] = pkgs
- return rv
-
- def filter_unknown(self, unknown):
- filtered = set([u for u in unknown if u.startswith('rpmlib')])
- unknown.difference_update(filtered)
-
-class APTSource(Source):
- basegroups = ['apt', 'debian', 'ubuntu', 'nexenta']
- ptype = 'deb'
-
- def __init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended):
- Source.__init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended)
- self.pkgnames = set()
-
- self.url_map = [{'rawurl': self.rawurl, 'url': self.url, 'version': self.version, \
- 'components': self.components, 'arches': self.arches, 'groups': self.groups}]
-
- def save_state(self):
- cache = file(self.cachefile, 'wb')
- cPickle.dump((self.pkgnames, self.deps, self.provides),
- cache, 2)
- cache.close()
-
- def load_state(self):
- data = file(self.cachefile)
- self.pkgnames, self.deps, self.provides = cPickle.load(data)
-
- def filter_unknown(self, unknown):
- filtered = set([u for u in unknown if u.startswith('choice')])
- unknown.difference_update(filtered)
-
- def get_urls(self):
- if not self.rawurl:
- return ["%sdists/%s/%s/binary-%s/Packages.gz" % \
- (self.url, self.version, part, arch) for part in self.components \
- for arch in self.arches]
- else:
- return ["%sPackages.gz" % (self.rawurl)]
- urls = property(get_urls)
-
- def read_files(self):
- bdeps = dict()
- bprov = dict()
- if self.recommended:
- depfnames = ['Depends', 'Pre-Depends', 'Recommends']
- else:
- depfnames = ['Depends', 'Pre-Depends']
- for fname in self.files:
- if not self.rawurl:
- barch = [x for x in fname.split('@') if x.startswith('binary-')][0][7:]
- else:
- # RawURL entries assume that they only have one <Arch></Arch>
- # element and that it is the architecture of the source.
- barch = self.arches[0]
- if barch not in bdeps:
- bdeps[barch] = dict()
- bprov[barch] = dict()
- try:
- reader = gzip.GzipFile(fname)
- except:
- print("Failed to read file %s" % fname)
- raise
- for line in reader.readlines():
- words = line.strip().split(':', 1)
- if words[0] == 'Package':
- pkgname = words[1].strip().rstrip()
- self.pkgnames.add(pkgname)
- bdeps[barch][pkgname] = []
- elif words[0] in depfnames:
- vindex = 0
- for dep in words[1].split(','):
- if '|' in dep:
- cdeps = [re.sub('\s+', '', re.sub('\(.*\)', '', cdep)) for cdep in dep.split('|')]
- dyn_dname = "choice-%s-%s-%s" % (pkgname, barch, vindex)
- vindex += 1
- bdeps[barch][pkgname].append(dyn_dname)
- bprov[barch][dyn_dname] = set(cdeps)
- else:
- raw_dep = re.sub('\(.*\)', '', dep)
- raw_dep = raw_dep.rstrip().strip()
- bdeps[barch][pkgname].append(raw_dep)
- elif words[0] == 'Provides':
- for pkg in words[1].split(','):
- dname = pkg.rstrip().strip()
- if dname not in bprov[barch]:
- bprov[barch][dname] = set()
- bprov[barch][dname].add(pkgname)
-
- self.deps['global'] = dict()
- self.provides['global'] = dict()
- for barch in bdeps:
- self.deps[barch] = dict()
- self.provides[barch] = dict()
- for pkgname in self.pkgnames:
- pset = set()
- for barch in bdeps:
- if pkgname not in bdeps[barch]:
- bdeps[barch][pkgname] = []
- pset.add(tuple(bdeps[barch][pkgname]))
- if len(pset) == 1:
- self.deps['global'][pkgname] = pset.pop()
- else:
- for barch in bdeps:
- self.deps[barch][pkgname] = bdeps[barch][pkgname]
- provided = set()
- for bprovided in bprov.values():
- provided.update(set(bprovided))
- for prov in provided:
- prset = set()
- for barch in bprov:
- if prov not in bprov[barch]:
- continue
- prset.add(tuple(bprov[barch].get(prov, ())))
- if len(prset) == 1:
- self.provides['global'][prov] = prset.pop()
- else:
- for barch in bprov:
- self.provides[barch][prov] = bprov[barch].get(prov, ())
- self.save_state()
-
- def is_package(self, _, pkg):
- return pkg in self.pkgnames and \
- pkg not in self.blacklist and \
- (len(self.whitelist) == 0 or pkg in self.whitelist)
-
-class PACSource(Source):
- basegroups = ['arch', 'parabola']
- ptype = 'pacman'
-
- def __init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended):
- Source.__init__(self, basepath, url, version, arches, components, groups,
- rawurl, blacklist, whitelist, recommended)
- self.pkgnames = set()
-
- self.url_map = [{'rawurl': self.rawurl, 'url': self.url, 'version': self.version, \
- 'components': self.components, 'arches': self.arches, 'groups': self.groups}]
-
- def save_state(self):
- cache = file(self.cachefile, 'wb')
- cPickle.dump((self.pkgnames, self.deps, self.provides),
- cache, 2)
- cache.close()
-
- def load_state(self):
- data = file(self.cachefile)
- self.pkgnames, self.deps, self.provides = cPickle.load(data)
-
- def filter_unknown(self, unknown):
- filtered = set([u for u in unknown if u.startswith('choice')])
- unknown.difference_update(filtered)
-
- def get_urls(self):
- if not self.rawurl:
- return ["%s/%s/os/%s/%s.db.tar.gz" % \
- (self.url, part, arch, part) for part in self.components \
- for arch in self.arches]
- else:
- raise Exception("PACSource : RAWUrl not supported (yet)")
- urls = property(get_urls)
-
-
- def read_files(self):
- bdeps = dict()
- bprov = dict()
-
- if self.recommended:
- depfnames = ['Depends', 'Pre-Depends', 'Recommends']
- else:
- depfnames = ['Depends', 'Pre-Depends']
-
- for fname in self.files:
- if not self.rawurl:
- barch = [x for x in fname.split('@') if x in self.arches][0]
- else:
- # RawURL entries assume that they only have one <Arch></Arch>
- # element and that it is the architecture of the source.
- barch = self.arches[0]
-
- if barch not in bdeps:
- bdeps[barch] = dict()
- bprov[barch] = dict()
- try:
- print "try to read : " + fname
- tar = tarfile.open(fname, "r")
- reader = gzip.GzipFile(fname)
- except:
- print("Failed to read file %s" % fname)
- raise
-
- for tarinfo in tar:
- if tarinfo.isdir():
- self.pkgnames.add(tarinfo.name.rsplit("-",2)[0])
- print "added : " + tarinfo.name.rsplit("-",2)[0]
- tar.close()
-
- self.deps['global'] = dict()
- self.provides['global'] = dict()
- for barch in bdeps:
- self.deps[barch] = dict()
- self.provides[barch] = dict()
- for pkgname in self.pkgnames:
- pset = set()
- for barch in bdeps:
- if pkgname not in bdeps[barch]:
- bdeps[barch][pkgname] = []
- pset.add(tuple(bdeps[barch][pkgname]))
- if len(pset) == 1:
- self.deps['global'][pkgname] = pset.pop()
- else:
- for barch in bdeps:
- self.deps[barch][pkgname] = bdeps[barch][pkgname]
- provided = set()
- for bprovided in bprov.values():
- provided.update(set(bprovided))
- for prov in provided:
- prset = set()
- for barch in bprov:
- if prov not in bprov[barch]:
- continue
- prset.add(tuple(bprov[barch].get(prov, ())))
- if len(prset) == 1:
- self.provides['global'][prov] = prset.pop()
- else:
- for barch in bprov:
- self.provides[barch][prov] = bprov[barch].get(prov, ())
- self.save_state()
-
- def is_package(self, _, pkg):
- return pkg in self.pkgnames and \
- pkg not in self.blacklist and \
- (len(self.whitelist) == 0 or pkg in self.whitelist)
-
-class Packages(Bcfg2.Server.Plugin.Plugin,
- Bcfg2.Server.Plugin.StructureValidator,
- Bcfg2.Server.Plugin.Generator,
- Bcfg2.Server.Plugin.Connector):
- name = 'Packages'
- conflicts = ['Pkgmgr']
- experimental = True
- __rmi__ = Bcfg2.Server.Plugin.Plugin.__rmi__ + ['Refresh', 'Reload']
-
- def __init__(self, core, datastore):
- Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
- Bcfg2.Server.Plugin.StructureValidator.__init__(self)
- Bcfg2.Server.Plugin.Generator.__init__(self)
- Bcfg2.Server.Plugin.Connector.__init__(self)
- self.cachepath = self.data + '/cache'
- self.sentinels = set()
- self.sources = []
- self.disableResolver = False
- self.disableMetaData = False
- self.virt_pkgs = dict()
-
- if not os.path.exists(self.cachepath):
- # create cache directory if needed
- os.makedirs(self.cachepath)
- self._load_config()
-
- def get_relevant_groups(self, meta):
- mgrps = list(set([g for g in meta.groups for s in self.get_matching_sources(meta) \
- if g in s.basegroups or g in s.groups or g in s.arches]))
- mgrps.sort()
- return tuple(mgrps)
-
- def build_vpkgs_entry(self, meta):
- # build single entry for all matching sources
- mgrps = self.get_relevant_groups(meta)
- vpkgs = dict()
- for source in self.get_matching_sources(meta):
- s_vpkgs = source.get_vpkgs(meta)
- for name, prov_set in s_vpkgs.iteritems():
- if name not in vpkgs:
- vpkgs[name] = set(prov_set)
- else:
- vpkgs[name].update(prov_set)
- return vpkgs
-
- def get_matching_sources(self, meta):
- return [s for s in self.sources if s.applies(meta)]
-
- def HandlesEntry(self, entry, metadata):
- if [x for x in metadata.groups if x in self.sentinels] \
- and entry.tag == 'Package':
- return True
- return False
-
- def HandleEntry(self, entry, metadata):
- entry.set('version', 'auto')
- for source in self.sources:
- if [x for x in metadata.groups if x in source.basegroups]:
- entry.set('type', source.ptype)
-
- def complete(self, meta, input_requirements, debug=False):
- '''Build the transitive closure of all package dependencies
-
- Arguments:
- meta - client metadata instance
- packages - set of package names
- debug - print out debug information for the decision making process
- returns => (set(packages), set(unsatisfied requirements), package type)
- '''
- sources = self.get_matching_sources(meta)
- # reverse list so that priorities correspond to file order
- sources.reverse()
- if len(sources) == 0:
- self.logger.error("Packages: No matching sources for client %s; improper group memberships?" % (meta.hostname))
- return set(), set(), 'failed'
- ptype = set([s.ptype for s in sources])
- if len(ptype) < 1:
- return set(), set(), 'failed'
-
- # setup vpkg cache
- pgrps = self.get_relevant_groups(meta)
- if pgrps not in self.virt_pkgs:
- self.virt_pkgs[pgrps] = self.build_vpkgs_entry(meta)
- vpkg_cache = self.virt_pkgs[pgrps]
-
- # unclassified is set of unsatisfied requirements (may be pkg for vpkg)
- unclassified = set(input_requirements)
- vpkgs = set()
- both = set()
- pkgs = set(input_requirements)
-
- packages = set()
- examined = set()
- unknown = set()
-
- final_pass = False
- really_done = False
- # do while unclassified or vpkgs or both or pkgs
- while unclassified or pkgs or both or final_pass:
- #print len(unclassified), len(pkgs), len(both), len(vpkgs), final_pass
- if really_done:
- break
- if len(unclassified) + len(pkgs) + len(both) == 0:
- # one more pass then exit
- really_done = True
-
- while unclassified:
- current = unclassified.pop()
- examined.add(current)
- is_pkg = True in [source.is_package(meta, current) for source in sources]
- is_vpkg = current in vpkg_cache
-
- if is_pkg and is_vpkg:
- both.add(current)
- elif is_pkg and not is_vpkg:
- pkgs.add(current)
- elif is_vpkg and not is_pkg:
- vpkgs.add(current)
- elif not is_vpkg and not is_pkg:
- unknown.add(current)
-
- while pkgs:
- # direct packages; current can be added, and all deps should be resolved
- current = pkgs.pop()
- if debug:
- self.logger.debug("Packages: handling package requirement %s" % (current))
- deps = ()
- for source in sources:
- if source.is_package(meta, current):
- try:
- deps = source.get_deps(meta, current)
- break
- except:
- continue
- packages.add(current)
- newdeps = set(deps).difference(examined)
- if debug and newdeps:
- self.logger.debug("Packages: Package %s added requirements %s" % (current, newdeps))
- unclassified.update(newdeps)
-
- satisfied_vpkgs = set()
- for current in vpkgs:
- # virtual dependencies, satisfied if one of N in the config, or can be forced if only one provider
- if len(vpkg_cache[current]) == 1:
- if debug:
- self.logger.debug("Packages: requirement %s satisfied by %s" % (current, vpkg_cache[current]))
- unclassified.update(vpkg_cache[current].difference(examined))
- satisfied_vpkgs.add(current)
- elif [item for item in vpkg_cache[current] if item in packages]:
- if debug:
- self.logger.debug("Packages: requirement %s satisfied by %s" % (current, [item for item in vpkg_cache[current] if item in packages]))
- satisfied_vpkgs.add(current)
- vpkgs.difference_update(satisfied_vpkgs)
-
- satisfied_both = set()
- for current in both:
- # packages that are both have virtual providers as well as a package with that name
- # allow use of virt through explicit specification, then fall back to forcing current on last pass
- if [item for item in vpkg_cache[current] if item in packages]:
- if debug:
- self.logger.debug("Packages: requirement %s satisfied by %s" % (current, [item for item in vpkg_cache[current] if item in packages]))
- satisfied_both.add(current)
- elif current in input_requirements or final_pass:
- pkgs.add(current)
- satisfied_both.add(current)
- both.difference_update(satisfied_both)
-
- if len(unclassified) + len(pkgs) == 0:
- final_pass = True
- else:
- final_pass = False
-
- for source in sources:
- source.filter_unknown(unknown)
-
- return packages, unknown, ptype.pop()
-
- def validate_structures(self, meta, structures):
- '''Ensure client configurations include all needed prerequisites
-
- Arguments:
- meta - client metadata instance
- structures - a list of structure-stage entry combinations
- '''
- if self.disableResolver: return # Config requests no resolver
-
- initial = set([pkg.get('name') for struct in structures \
- for pkg in struct.findall('Package') +
- struct.findall('BoundPackage')])
- news = lxml.etree.Element('Independent')
- packages, unknown, ptype = self.complete(meta, initial,
- debug=self.debug_flag)
- if unknown:
- self.logger.info("Got unknown entries")
- self.logger.info(list(unknown))
- newpkgs = list(packages.difference(initial))
- newpkgs.sort()
- for pkg in newpkgs:
- lxml.etree.SubElement(news, 'BoundPackage', name=pkg,
- type=ptype, version='auto', origin='Packages')
- structures.append(news)
-
- def make_non_redundant(self, meta, plname=None, plist=None):
- '''build a non-redundant version of a list of packages
-
- Arguments:
- meta - client metadata instance
- plname - name of file containing a list of packages
- '''
- if plname is not None:
- pkgnames = set([x.strip() for x in open(plname).readlines()])
- elif plist is not None:
- pkgnames = set(plist)
- redundant = set()
- sources = self.get_matching_sources(meta)
- for source in sources:
- for pkgname in pkgnames:
- if source.is_pkg(meta, current):
- try:
- deps = source.get_deps(meta, pkgname)
- except:
- continue
- for rpkg in deps:
- if rpkg in pkgnames:
- redundant.add(rpkg)
- return pkgnames.difference(redundant), redundant
-
- def Refresh(self):
- '''Packages.Refresh() => True|False\nReload configuration specification and download sources\n'''
- self._load_config(force_update=True)
- return True
-
- def Reload(self):
- '''Packages.Refresh() => True|False\nReload configuration specification and sources\n'''
- self._load_config()
- return True
-
- def _load_config(self, force_update=False):
- '''
- Load the configuration data and setup sources
-
- Keyword args:
- force_update Force downloading repo data
- '''
- self.virt_pkgs = dict()
- try:
- xdata = lxml.etree.parse(self.data + '/config.xml')
- xdata.xinclude()
- xdata = xdata.getroot()
- except (lxml.etree.XIncludeError, \
- lxml.etree.XMLSyntaxError), xmlerr:
- self.logger.error("Package: Error processing xml: %s" % xmlerr)
- raise Bcfg2.Server.Plugin.PluginInitError
- except IOError:
- self.logger.error("Failed to read Packages configuration. Have" +
- " you created your config.xml file?")
- raise Bcfg2.Server.Plugin.PluginInitError
-
- # Load Packages config
- config = xdata.xpath('//Sources/Config')
- if config:
- if config[0].get("resolver", "enabled").lower() == "disabled":
- self.logger.info("Packages: Resolver disabled")
- self.disableResolver = True
- if config[0].get("metadata", "enabled").lower() == "disabled":
- self.logger.info("Packages: Metadata disabled")
- self.disableResolver = True
- self.disableMetaData = True
-
- self.sentinels = set()
- self.sources = []
- for s in xdata.findall('.//APTSource'):
- self.sources.append(APTSource(self.cachepath, **source_from_xml(s)))
- for s in xdata.findall('.//YUMSource'):
- self.sources.append(YUMSource(self.cachepath, **source_from_xml(s)))
- for s in xdata.findall('.//PACSource'):
- self.sources.append(PACSource(self.cachepath, **source_from_xml(s)))
-
- cachefiles = []
- for source in self.sources:
- cachefiles.append(source.cachefile)
- if not self.disableMetaData: source.setup_data(force_update)
- self.sentinels.update(source.basegroups)
- for cfile in glob.glob("%s/cache-*" % self.cachepath):
- if cfile not in cachefiles:
- os.unlink(cfile)
-
- def get_additional_data(self, meta):
- sdata = []
- [sdata.extend(copy.deepcopy(src.url_map)) for src in self.get_matching_sources(meta)]
- return dict(sources=sdata)