summaryrefslogtreecommitdiffstats
path: root/src/software/openlmi/software/yumdb/jobs.py
blob: 1fdfbe303b6547c5da403fc0a451e67d8f988e74 (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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# -*- encoding: utf-8 -*-
# Software Management Providers
#
# Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
#
# Authors: Michal Minar <miminar@redhat.com>
#
"""
Define job classes representing kinds of jobs of worker process.
"""

import threading

from openlmi.software import util
from openlmi.software.yumdb.packageinfo import PackageInfo

class YumJob(object):  #pylint: disable=R0903
    """
    Base class for any job, that is processable by YumWorker process.
    It contains at least a jobid attribute, that must be unique for
    each job, it's counted from zero a incremented after each creation.
    """
    __slots__ = ('jobid', )

    # jobs can be created concurrently from multiple threads, that's
    # why we need to make its creation thread safe
    _JOB_ID_LOCK = threading.Lock()
    _JOB_ID = 0

    @staticmethod
    def _get_job_id():
        """
        Generates new job ids. It should be called only from constructor
        of YumJob. Ensures, that each job has a unique number.
        @return number of jobs created since program start -1
        """
        with YumJob._JOB_ID_LOCK:
            val = YumJob._JOB_ID
            YumJob._JOB_ID += 1
        return val

    def __init__(self):
        self.jobid = self._get_job_id()

    @property
    def job_kwargs(self):
        """
        Jobs are in worker represented be methods with arguments.
        Those can be obtained from job by calling this property.
        @return dictionary of keyword arguments of job
        """
        kwargs = {}
        cls = self.__class__
        while not cls in (YumJob, object):
            for slot in cls.__slots__:
                if not slot in kwargs:
                    kwargs[slot] = getattr(self, slot)
            cls = cls.__bases__[0]
        kwargs.pop('jobid', None)
        return kwargs

    def __getstate__(self):
        ret = self.job_kwargs
        ret.update(jobid=self.jobid)
        return ret

    def __setstate__(self, state):
        for k, value in state.items():
            setattr(self, k, value)

class YumBeginSession(YumJob):    #pylint: disable=R0903
    """
    Begin session on YumWorker which ensures that yum database is locked
    during its lifetime. Sessions can be nested, but the number of
    YumEndSession jobs must be processed to make the database unlocked.
    """
    pass
class YumEndSession(YumJob):      #pylint: disable=R0903
    """
    End the session started with YumBeginSession. If the last active session
    is ended, database will be unlocked.
    """
    pass

class YumGetPackageList(YumJob):  #pylint: disable=R0903
    """
    Job requesing a list of packages.
    Arguments:
      kind             - supported values are in SUPPORTED_KINDS tuple
      allow_duplicates - whether multiple packages can be present
        in result for single (name, arch) of package differing
        in their version

    Worker replies with [pkg1, pkg2, ...].
    """
    __slots__ = ('kind', 'allow_duplicates', 'sort')

    SUPPORTED_KINDS = ('installed', 'available', 'all')

    def __init__(self, kind, allow_duplicates, sort=False):
        YumJob.__init__(self)
        if not isinstance(kind, basestring):
            raise TypeError("kind must be a string")
        if not kind in self.SUPPORTED_KINDS:
            raise ValueError("kind must be one of {%s}" %
                    ", ".join(self.SUPPORTED_KINDS))
        self.kind = kind
        self.allow_duplicates = bool(allow_duplicates)
        self.sort = bool(sort)

class YumFilterPackages(YumGetPackageList):   #pylint: disable=R0903
    """
    Job similar to YumGetPackageList, but allowing to specify
    filter on packages.
    Arguments (plus those in YumGetPackageList):
      name, epoch, version, release, arch, nevra, envra, evra
      
    Some of those are redundant, but filtering is optimized for
    speed, so supplying all of them won't affect performance.

    Worker replies with [pkg1, pkg2, ...].
    """
    __slots__ = (
        'name', 'epoch', 'version', 'release', 'arch',
        'nevra', 'envra', 'evra')

    def __init__(self, kind, allow_duplicates,
            sort=False,
            name=None, epoch=None, version=None,
            release=None, arch=None,
            nevra=None, evra=None,
            envra=None):
        if nevra is not None and not util.RE_NEVRA.match(nevra):
            raise ValueError("Invalid nevra: %s" % nevra)
        if evra is not None and not util.RE_EVRA.match(evra):
            raise ValueError("Invalid evra: %s" % evra)
        if envra is not None and not util.RE_ENVRA.match(evra):
            raise ValueError("Invalid envra: %s" % envra)
        YumGetPackageList.__init__(self, kind, allow_duplicates, sort)
        self.name = name
        self.epoch = None if epoch is None else str(epoch)
        self.version = version
        self.release = release
        self.arch = arch
        self.nevra = nevra
        self.evra = evra
        self.envra = envra

class YumSpecificPackageJob(YumJob):  #pylint: disable=R0903
    """
    Abstract job taking instance of yumdb.PackageInfo as argument.
    Arguments:
      pkg - plays different role depending on job subclass
    """
    __slots__ = ('pkg', )
    def __init__(self, pkg):
        if not isinstance(pkg, PackageInfo):
            raise TypeError("pkg must be instance of PackageInfo")
        YumJob.__init__(self)
        self.pkg = pkg

class YumInstallPackage(YumSpecificPackageJob):   #pylint: disable=R0903
    """
    Job requesting installation of specific package.
    pkg argument should be available.

    Worker replies with new instance of package.
    """
    pass

class YumRemovePackage(YumSpecificPackageJob):    #pylint: disable=R0903
    """
    Job requesting removal of specific package.
    pkg argument should be installed.
    """
    pass

class YumUpdateToPackage(YumSpecificPackageJob):  #pylint: disable=R0903
    """
    Job requesting update to provided specific package.
    Package is updated to epoch, version and release of this
    provided available package.

    Worker replies with new instance of package.
    """
    pass

class YumUpdatePackage(YumSpecificPackageJob):    #pylint: disable=R0903
    """
    Job requesting update of package, optionally reducing possible
    candidate packages to ones with specific evr.
    Arguments:
      to_epoch, to_version, to_release

    The arguments more given, the more complete filter of candidates.

    Worker replies with new instance of package.
    """
    __slots__ = ('to_epoch', 'to_version', 'to_release')

    def __init__(self, pkg,
            to_epoch=None, to_version=None, to_release=None):
        if not isinstance(pkg, PackageInfo):
            raise TypeError("pkg must be instance of yumdb.PackageInfo")
        YumSpecificPackageJob.__init__(self, pkg)
        self.to_epoch = to_epoch
        self.to_version = to_version
        self.to_release = to_release

class YumCheckPackage(YumSpecificPackageJob):       #pylint: disable=R0903
    """
    Request verification information for instaled package and its files.
    
    Worker replies with new instance of yumdb.PackageCheck.
    """
    def __init__(self, pkg):
        YumSpecificPackageJob.__init__(self, pkg)
        if not pkg.installed:
            raise ValueError("package must be installed to check it")