From 2cfbdf19d62880eed3e80f526bf12f6f98ff6633 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Thu, 18 Jul 2013 08:56:32 -0400 Subject: Packages: fixed read-only yum cache Replaced incredibly stupid (mea culpa!) and race-condition-prone system that toggled filesystem permissions (what was I thinking?!?) with judicious application of the yum cacheonly option. --- src/lib/Bcfg2/Server/Plugins/Packages/Yum.py | 33 ++++------------------------ src/sbin/bcfg2-yum-helper | 31 +++++++++++++++++++++----- 2 files changed, 30 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py index 9b08c4e88..9060af150 100644 --- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py +++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py @@ -928,28 +928,6 @@ class YumCollection(Collection): "output: %s" % err) raise - def _set_cache_writeable(self, writeable): - """ Set the writeability of the yum cache. - - :param writeable: If True, the cache will be made writeable. - If False, the cache will be made read-only. - :type writeable: bool - """ - fmode = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH - if writeable: - self.debug_log("Packages: Making cache %s writeable" % - self.cachefile) - fmode |= stat.S_IWUSR - else: - self.debug_log("Packages: Making cache %s read-only" % - self.cachefile) - dmode = fmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH - for root, dirs, files in os.walk(self.cachefile): - for dname in dirs: - os.chmod(os.path.join(root, dname), dmode) - for fname in files: - os.chmod(os.path.join(root, fname), fmode) - def setup_data(self, force_update=False): """ Do any collection-level data setup tasks. This is called when sources are loaded or reloaded by @@ -957,11 +935,10 @@ class YumCollection(Collection): If the builtin yum parsers are in use, this defers to :func:`Bcfg2.Server.Plugins.Packages.Collection.Collection.setup_data`. - If using the yum Python libraries, this makes the cache - writeable, cleans up cached yum metadata, regenerates the - server-side yum config (in order to catch any new sources that - have been added to this server), regenerates the yum cache, - and then sets the cache back to read-only. + If using the yum Python libraries, this cleans up cached yum + metadata, regenerates the server-side yum config (in order to + catch any new sources that have been added to this server), + then regenerates the yum cache. :param force_update: Ignore all local cache and setup data from its original upstream sources (i.e., @@ -971,7 +948,6 @@ class YumCollection(Collection): if not self.use_yum: return Collection.setup_data(self, force_update) - self._set_cache_writeable(True) if force_update: # clean up data from the old config try: @@ -989,7 +965,6 @@ class YumCollection(Collection): except ValueError: # error reported by call_helper pass - self._set_cache_writeable(False) class YumSource(Source): diff --git a/src/sbin/bcfg2-yum-helper b/src/sbin/bcfg2-yum-helper index 473214d89..414606abb 100755 --- a/src/sbin/bcfg2-yum-helper +++ b/src/sbin/bcfg2-yum-helper @@ -42,8 +42,8 @@ def pkgtup_to_string(package): return ''.join(str(e) for e in rv) -class DepSolver(object): - """ Yum dependency solver """ +class YumHelper(object): + """ Yum helper base object """ def __init__(self, cfgfile, verbose=1): self.cfgfile = cfgfile @@ -57,6 +57,16 @@ class DepSolver(object): self.yumbase._getConfig(cfgfile, debuglevel=verbose) # pylint: enable=E1121,W0212 self.logger = logging.getLogger(self.__class__.__name__) + + +class DepSolver(YumHelper): + """ Yum dependency solver. This is used for operations that only + read from the yum cache, and thus operates in cacheonly mode. """ + + def __init__(self, cfgfile, verbose=1): + YumHelper.__init__(self, cfgfile, verbose=verbose) + # internally, yum uses an integer, not a boolean, for conf.cache + self.yumbase.conf.cache = 1 self._groups = None def get_groups(self): @@ -181,6 +191,14 @@ class DepSolver(object): packages.add(txmbr.pkgtup) return list(packages), list(unknown) + +class CacheManager(YumHelper): + """ Yum cache manager. Unlike :class:`DepSolver`, this can write + to the yum cache, and so is used for operations that muck with the + cache. (Technically, :func:`CacheManager.clean_cache` could be in + either DepSolver or CacheManager, but for consistency I've put it + here.) """ + def clean_cache(self): """ clean the yum cache """ for mdtype in ["Headers", "Packages", "Sqlite", "Metadata", @@ -237,10 +255,10 @@ def main(): # pylint: disable=W0702 rv = 0 - depsolver = DepSolver(options.config, options.verbose) if cmd == "clean": + cachemgr = CacheManager(options.config, options.verbose) try: - depsolver.clean_cache() + cachemgr.clean_cache() print(json.dumps(True)) except: logger.error("Unexpected error cleaning cache: %s" % @@ -248,15 +266,17 @@ def main(): print(json.dumps(False)) rv = 2 elif cmd == "makecache": + cachemgr = CacheManager(options.config, options.verbose) try: # this code copied from yumcommands.py - depsolver.populate_cache() + cachemgr.populate_cache() print json.dumps(True) except yum.Errors.YumBaseError: logger.error("Unexpected error creating cache: %s" % sys.exc_info()[1], exc_info=1) print json.dumps(False) elif cmd == "complete": + depsolver = DepSolver(options.config, options.verbose) try: data = json.loads(sys.stdin.read()) except: @@ -275,6 +295,7 @@ def main(): print(json.dumps(dict(packages=[], unknown=data['packages']))) rv = 2 elif cmd == "get_groups": + depsolver = DepSolver(options.config, options.verbose) try: data = json.loads(sys.stdin.read()) rv = dict() -- cgit v1.2.3-1-g7c22