summaryrefslogtreecommitdiffstats
path: root/py/mock/plugins/yum_cache.py
blob: c43b7e1a6930fbb2ac5aba3859824e34643cb79a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=python:textwidth=0:
# License: GPL2 or later see COPYING
# Written by Michael Brown
# Copyright (C) 2007 Michael E Brown <mebrown@michaels-house.net>

# python library imports
import fcntl
import time
import os

# our imports
from mock.trace_decorator import decorate, traceLog, getLog
import mock.util

# set up logging, module options
requires_api_version = "1.0"

# plugin entry point
decorate(traceLog())
def init(rootObj, conf):
    YumCache(rootObj, conf)

# classes
class YumCache(object):
    """caches root environment in a tarball"""
    decorate(traceLog())
    def __init__(self, rootObj, conf):
        self.rootObj = rootObj
        self.yum_cache_opts = conf
        self.yumSharedCachePath = self.yum_cache_opts['dir'] % self.yum_cache_opts
        self.state = rootObj.state
        self.online = rootObj.online
        rootObj.yum_cacheObj = self
        rootObj.addHook("preyum", self._yumCachePreYumHook)
        rootObj.addHook("postyum", self._yumCachePostYumHook)
        rootObj.addHook("preinit", self._yumCachePreInitHook)
        rootObj.umountCmds.append('umount -n %s' % rootObj.makeChrootPath('/var/cache/yum'))
        rootObj.mountCmds.append('mount -n --bind %s  %s' % (self.yumSharedCachePath, rootObj.makeChrootPath('/var/cache/yum')))
        mock.util.mkdirIfAbsent(self.yumSharedCachePath)
        self.yumCacheLock = open(os.path.join(self.yumSharedCachePath, "yumcache.lock"), "a+")

    # =============
    # 'Private' API
    # =============
    # lock the shared yum cache (when enabled) before any access
    # by yum, and prior to cleaning it. This prevents simultaneous access from
    # screwing things up. This can possibly happen, eg. when running multiple
    # mock instances with --uniqueext=
    decorate(traceLog())
    def _yumCachePreYumHook(self):
        try:
            fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError, e:
            oldState = self.state()
            self.state("Waiting for yumcache lock")
            fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_EX)
            self.state(oldState)

    decorate(traceLog())
    def _yumCachePostYumHook(self):
        fcntl.lockf(self.yumCacheLock.fileno(), fcntl.LOCK_UN)

    decorate(traceLog())
    def _yumCachePreInitHook(self):
        getLog().info("enabled yum cache")
        mock.util.mkdirIfAbsent(self.rootObj.makeChrootPath('/var/cache/yum'))

        # lock so others dont accidentally use yum cache while we operate on it.
        self._yumCachePreYumHook()

        if self.online:
            self.state("cleaning yum metadata")
            for (dirpath, dirnames, filenames) in os.walk(self.yumSharedCachePath):
                for filename in filenames:
                    fullPath = os.path.join(dirpath, filename)
                    statinfo = os.stat(fullPath)
                    file_age_days = (time.time() - statinfo.st_ctime) / (60 * 60 * 24)
                    # prune repodata so yum redownloads.
                    # prevents certain errors where yum gets stuck due to bad metadata
                    for ext in (".sqllite", ".xml", ".bz2", ".gz"):
                        if filename.endswith(ext) and file_age_days > self.yum_cache_opts['max_metadata_age_days']:
                            os.unlink(fullPath)
                            fullPath = None
                            break

                    if fullPath is None: continue
                    if file_age_days > self.yum_cache_opts['max_age_days']:
                        os.unlink(fullPath)
                        continue

        self._yumCachePostYumHook()