summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Packages/Yum.py13
-rwxr-xr-xsrc/sbin/bcfg2-yum-helper32
2 files changed, 45 insertions, 0 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
index 7c950a435..7a90f4f2e 100644
--- a/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
+++ b/src/lib/Bcfg2/Server/Plugins/Packages/Yum.py
@@ -53,11 +53,13 @@ The Yum Backend
import os
import re
import sys
+import time
import copy
import errno
import socket
import logging
import lxml.etree
+from lockfile import FileLock
from subprocess import Popen, PIPE
import Bcfg2.Server.Plugin
# pylint: disable=W0622
@@ -864,6 +866,17 @@ class YumCollection(Collection):
if not self.use_yum:
return Collection.complete(self, packagelist)
+ lock = FileLock(os.path.join(self.cachefile, "lock"))
+ slept = 0
+ while lock.is_locked():
+ if slept > 30:
+ self.logger.warning("Packages: Timeout waiting for yum cache "
+ "to release its lock")
+ return set(), set()
+ self.logger.debug("Packages: Yum cache is locked, waiting...")
+ time.sleep(3)
+ slept += 3
+
if packagelist:
try:
result = self.call_helper(
diff --git a/src/sbin/bcfg2-yum-helper b/src/sbin/bcfg2-yum-helper
index 414606abb..1f22c0ff9 100755
--- a/src/sbin/bcfg2-yum-helper
+++ b/src/sbin/bcfg2-yum-helper
@@ -10,6 +10,8 @@ import sys
import yum
import logging
import Bcfg2.Logger
+from Bcfg2.Compat import wraps
+from lockfile import FileLock, LockTimeout
from optparse import OptionParser
try:
import json
@@ -192,6 +194,27 @@ class DepSolver(YumHelper):
return list(packages), list(unknown)
+def acquire_lock(func):
+ """ decorator for CacheManager methods that gets and release a
+ lock while the method runs """
+ @wraps(func)
+ def inner(self, *args, **kwargs):
+ self.logger.debug("Acquiring lock at %s" % self.lockfile)
+ while not self.lock.i_am_locking():
+ try:
+ self.lock.acquire(timeout=60) # wait up to 60 seconds
+ except LockTimeout:
+ self.lock.break_lock()
+ self.lock.acquire()
+ try:
+ func(self, *args, **kwargs)
+ finally:
+ self.lock.release()
+ self.logger.debug("Released lock at %s" % self.lockfile)
+
+ return inner
+
+
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
@@ -199,6 +222,14 @@ class CacheManager(YumHelper):
either DepSolver or CacheManager, but for consistency I've put it
here.) """
+ def __init__(self, cfgfile, verbose=1):
+ YumHelper.__init__(self, cfgfile, verbose=verbose)
+ self.lockfile = \
+ os.path.join(os.path.dirname(self.yumbase.conf.config_file_path),
+ "lock")
+ self.lock = FileLock(self.lockfile)
+
+ @acquire_lock
def clean_cache(self):
""" clean the yum cache """
for mdtype in ["Headers", "Packages", "Sqlite", "Metadata",
@@ -211,6 +242,7 @@ class CacheManager(YumHelper):
if not msg.startswith("0 "):
self.logger.info(msg)
+ @acquire_lock
def populate_cache(self):
""" populate the yum cache """
for repo in self.yumbase.repos.findRepos('*'):