summaryrefslogtreecommitdiffstats
path: root/src/software/lmi/software/core/AffectedSoftwareJobElement.py
blob: 0bbc7c7f0c3b2320701bc3cde0e606ec6dc3de3e (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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# -*- encoding: utf-8 -*-
# Software Management Providers
#
# Copyright (C) 2012-2014 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

"""
Just a common functionality related to AffectedSoftwareJobElement provider.
"""

import pywbem

from lmi.providers import cmpi_logging
from lmi.providers import ComputerSystem
from lmi.software import util
from lmi.software.core import Identity
from lmi.software.core import IdentityFileCheck
from lmi.software.core import Job
from lmi.software.core import SystemCollection
from lmi.software.yumdb import jobs
from lmi.software.yumdb import PackageInfo

LOG = cmpi_logging.get_logger(__name__)

class Values(object):
    class ElementEffects(object):
        Unknown = pywbem.Uint16(0)
        Other = pywbem.Uint16(1)
        Exclusive_Use = pywbem.Uint16(2)
        Performance_Impact = pywbem.Uint16(3)
        Element_Integrity = pywbem.Uint16(4)
        Create = pywbem.Uint16(5)
        _reverse_map = {
                0: 'Unknown',
                1: 'Other',
                2: 'Exclusive Use',
                3: 'Performance Impact',
                4: 'Element Integrity',
                5: 'Create'
        }

@cmpi_logging.trace_function
def check_path(env, op):
    """
    Checks, whether object path is valid.

    Return internal object representing job and object path of affected element
    as a pair: ``(job, affected)``.
    """
    if not isinstance(op, pywbem.CIMInstanceName):
        raise TypeError("op must be a CIMInstanceName")
    ch = env.get_cimom_handle()

    job = op['AffectingElement'] = Job.object_path2job(op['AffectingElement'])
    affected = op['AffectedElement']
    if ch.is_subclass(affected.namespace, sub=affected.classname,
            super='LMI_SoftwareIdentity'):
        pkg_info = Identity.object_path2pkg(affected, kind='all')
        if isinstance(job, jobs.YumSpecificPackageJob):
            if isinstance(job.pkg, PackageInfo):
                if pkg_info != job.pkg:
                    raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                            "AffectedElement does not match job's package:"
                            " \"%s\" != \"%s\"." % (pkg_info, job.pkg))
            else:
                flt = pkg_info.key_props
                flt.pop('repoid', None)
                if util.nevra2filter(job.pkg) != flt:
                    raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                            "AffectedElement does not match job's package:"
                            " \"%s\" != \"%s\"." % (pkg_info, job.pkg))
            affected = Identity.pkg2model(pkg_info)
        elif isinstance(job, jobs.YumInstallPackageFromURI):
            if job.state == job.COMPLETED:
                affected = Identity.pkg2model(job.result_data)
            else:
                # TODO: this should be somehow obtained from downloaded
                # package before installation
                raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                        "No SoftwareIdentity is associated to given job.")
        else:
            LOG().error("Unsupported async job: %s", job)
            raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                    "No associated SoftwareIdentity.")
    elif ch.is_subclass(affected.namespace, sub=affected.classname,
            super='LMI_SystemSoftwareCollection'):
        SystemCollection.check_path(env, affected, "AffectedElement")
        affected = SystemCollection.get_path()
    elif ch.is_subclass(affected.namespace, sub=affected.classname,
            super="CIM_ComputerSystem"):
        ComputerSystem.check_path(env, affected, "AffectedElement")
        affected = ComputerSystem.get_path(env)
    elif ch.is_subclass(affected.namespace, sub=affected.classname,
            super='LMI_SoftwareIdentityFileCheck'):
        if not isinstance(job, jobs.YumCheckPackage):
            raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                    "Job must point to verification job, not to: \"%s\"" % job)
        if job.state != job.COMPLETED:
            raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                    "Associations to failed file checks for verification job"
                    " \"%s\" are not yet known, since job has not completed"
                    " yet." % op["AffectingElement"]["InstanceID"])
        pkg_info, _ = job.result_data
        file_check = IdentityFileCheck.object_path2file_check(affected)
        if file_check.pkg_info.nevra != pkg_info.nevra:
            raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                    "Affected element associated to job for another package:"
                    " \"%s\" != \"%s\"." % (file_check.pkg_info, pkg_info))
        if IdentityFileCheck.file_check_passed(file_check):
            raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                    "Given file check reference passed the verification.")
    else:
        raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
                "Expected an instance of LMI_SoftwareIdentity,"
                " LMI_SystemSoftwareCollection or CIM_ComputerSystem.")
    return (job, affected)

@cmpi_logging.trace_function
def job2affected_software_identity(job):
    """
    @return (path of SoftwareIdentity, ElementEffects array,
        OtherElementEffectsDescriptions array)
    """
    effects = [Values.ElementEffects.Other]
    descriptions = []
    if isinstance(job, jobs.YumSpecificPackageJob):
        if job.state == job.COMPLETED and job.result_data:
            if isinstance(job, jobs.YumCheckPackage):
                # get the first item out of (pkg_info, pkg_check)
                affected = Identity.pkg2model(job.result_data[0])
            else:
                affected = Identity.pkg2model(job.result_data)
        else:
            affected = Identity.pkg2model(job.pkg)
        if isinstance(job, jobs.YumInstallPackage):
            descriptions.append("Installing")
        elif isinstance(job, jobs.YumRemovePackage):
            descriptions.append("Removing")
        elif isinstance(job,
                (jobs.YumUpdatePackage, jobs.YumUpdateToPackage)):
            descriptions.append("Updating")
        elif isinstance(job, jobs.YumCheckPackage):
            descriptions.append("Verifying")
        else:
            descriptions.append("Modifying")
            LOG().error("Unhandled job: %s", job)
    elif isinstance(job, jobs.YumInstallPackageFromURI):
        if job.state == job.COMPLETED:
            affected = Identity.pkg2model(job.result_data)
            descriptions.append("Installing")
        else:
            # TODO: this should be somehow obtained from from downloaded
            # package before installation
            raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                    "No SoftwareIdentity is associated to given job.")
    else:
        LOG().error("Unsupported async job: %s", job)
        raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
                "No associated SoftwareIdentity.")
    return (affected, effects, descriptions)

@cmpi_logging.trace_function
def fill_model_computer_system(env, model, job, keys_only=True):
    """
    Fills model's AffectedElement and all non-key properties.
    """
    model["AffectedElement"] = ComputerSystem.get_path(env)
    if not keys_only:
        model["ElementEffects"] = [Values.ElementEffects.Other]
        description = "Modifying software collection."
        if isinstance(job, (jobs.YumInstallPackage,
                jobs.YumInstallPackageFromURI)):
            description = "Installing software package to collection."
        elif isinstance(job, jobs.YumRemovePackage):
            description = "Removing package from software collection."
        elif isinstance(job, (jobs.YumUpdatePackage, jobs.YumUpdateToPackage)):
            description = "Updating software package."
        model["OtherElementEffectsDescriptions"] = [description]
    return model

@cmpi_logging.trace_function
def fill_model_system_collection(model, keys_only=True):
    """
    Fills model's AffectedElement and all non-key properties.
    """
    model["AffectedElement"] = SystemCollection.get_path()
    if not keys_only:
        model["ElementEffects"] = [Values.ElementEffects.Exclusive_Use]
        model["OtherElementEffectsDescriptions"] = [
                "Package database is locked."
        ]
    return model

@cmpi_logging.trace_function
def fill_model_failed_check(model, failed_check, keys_only=True):
    """
    Fills model's AffectedElement and all non-key properties.

    :param failed_check: (``CIMInstanceName``) Is on object path of failed
        file check.
    """
    if not isinstance(failed_check, pywbem.CIMInstanceName):
        raise TypeError("failed_check must be a CIMInstanceName")
    model["AffectedElement"] = failed_check
    if not keys_only:
        model["ElementEffects"] = [Values.ElementEffects.Other]
        model["OtherElementEffectsDescriptions"] = [
                "File did not pass the verification."
        ]
    return model

@cmpi_logging.trace_function
def generate_failed_checks(model, job, keys_only=True):
    """
    Generates associations between LMI_SoftwareVerificationJob and
    LMI_SoftwareIdentityFileCheck for files that did not pass the check.
    """
    out_params = Job.get_verification_out_params(job)
    if not "Failed" in out_params:
        return
    for failed in out_params["Failed"].value:
        yield fill_model_failed_check(model, failed, keys_only)

@cmpi_logging.trace_function
def generate_models_from_job(env, job, keys_only=True, model=None):
    """
    Generates all associations between job and affected elements.
    """
    if not isinstance(job, jobs.YumJob):
        raise TypeError("pkg must be an instance of PackageInfo or nevra")
    if model is None:
        model = util.new_instance_name("LMI_AffectedSoftwareJobElement")
        if not keys_only:
            model = pywbem.CIMInstance("LMI_AffectedSoftwareJobElement",
                    path=model)
    model["AffectingElement"] = Job.job2model(job)
    (si, element_effects, element_effects_descriptions) = \
            job2affected_software_identity(job)
    model["AffectedElement"] = si
    if not keys_only:
        model["ElementEffects"] = element_effects
        model["OtherElementEffectsDescriptions"] = \
                element_effects_descriptions
    yield model
    if not isinstance(job, jobs.YumCheckPackage):
        fill_model_system_collection(model, keys_only=keys_only)
        yield model
    else:   # package verification - associate to failed file checks
        for model in generate_failed_checks(model, job, keys_only=keys_only):
            yield model
    fill_model_computer_system(env, model, job, keys_only=keys_only)
    yield model