summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Minar <miminar@redhat.com>2013-07-03 13:04:08 +0200
committerMichal Minar <miminar@redhat.com>2013-07-03 13:04:08 +0200
commitd5ac71ea513deffe78fb48e4f29ef69102f74cdb (patch)
tree8609f6002c6ad14ea89180a5c8a4d84a23de8700
parent2cf31bd8735ac61d762cc77f3234e566b465a928 (diff)
downloadopenlmi-providers-d5ac71ea513deffe78fb48e4f29ef69102f74cdb.tar.gz
openlmi-providers-d5ac71ea513deffe78fb48e4f29ef69102f74cdb.tar.xz
openlmi-providers-d5ac71ea513deffe78fb48e4f29ef69102f74cdb.zip
clean up YumDB instance only if it's instantiated
using global variable to signal, whether running under broker process
-rw-r--r--src/software/openlmi/software/core/InstallationJob.py154
-rw-r--r--src/software/openlmi/software/yumdb/__init__.py10
-rw-r--r--src/software/openlmi/software/yumdb/process.py9
3 files changed, 139 insertions, 34 deletions
diff --git a/src/software/openlmi/software/core/InstallationJob.py b/src/software/openlmi/software/core/InstallationJob.py
index e90ad1b..0a3d44a 100644
--- a/src/software/openlmi/software/core/InstallationJob.py
+++ b/src/software/openlmi/software/core/InstallationJob.py
@@ -17,7 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-Just a common functionality related to SoftwareInstallationJob.
+Just a common functionality related to SoftwareInstallationJob
+and SoftwareVerificationJob.
"""
from datetime import datetime, timedelta
@@ -25,10 +26,16 @@ import pywbem
import time
from openlmi.common import cmpi_logging
+from openlmi.software import util
from openlmi.software.core import Error
from openlmi.software.yumdb import errors, jobs
from openlmi.software.yumdb import YumDB
+JOB_CLASS_NAMES = (
+ "LMI_SoftwareInstallationJob",
+ "LMI_SoftwareVerificationJob"
+)
+
JOB_DESCRIPTIONS = {
jobs.YumInstallPackage :
'Software package installation job %(jobid)d for "%(pkg)s".',
@@ -38,23 +45,27 @@ JOB_DESCRIPTIONS = {
'Software package update job %(jobid)d for "%(pkg)s".',
jobs.YumUpdatePackage :
'Software package update job %(jobid)d for "%(pkg)s".',
- jobs.YumCheckPackage :
- 'Software package check job %(jobid)d for "%(pkg)s".',
jobs.YumInstallPackageFromURI :
'Software package installation job %(jobid)d from uri: "%(uri)s".',
+ jobs.YumCheckPackage :
+ 'Software package check job %(jobid)d for "%(pkg)s".',
+ jobs.YumCheckPackageFile :
+ 'File verification job %(jobid)d for package "%(pkg)s".',
}
# identificators of InstallationService method, which may trigger
# creation of asynchronous job
( JOB_METHOD_INSTALL_FROM_SOFTWARE_IDENTITY
, JOB_METHOD_INSTALL_FROM_URI
-, JOB_METHOD_INSTALL_FROM_BYTE_STREAM) = range(3)
+, JOB_METHOD_INSTALL_FROM_BYTE_STREAM
+, JOB_METHOD_VERIFY_INSTALLED_IDENTITY) = range(4)
# above identificators point to this array to their description
JOB_METHOD_NAMES = (
"InstallFromSoftwareIdentity",
"InstallFromURI",
- "InstallFromByteStream")
+ "InstallFromByteStream",
+ "VerifyInstalledIdentity")
class Values(object):
class DetailedStatus(object):
@@ -398,6 +409,46 @@ class Values(object):
}
@cmpi_logging.trace_function
+def get_verification_out_params(job):
+ """
+ Get the output parameters for verification job. They may not be computed
+ yet. In that case compute them a update the job in YumWorker process.
+
+ :param job: (``jobs.YumCheckPackage``)
+ :rtype: (``dict``) Dictionary of output parameters with pywbem values.
+ """
+ if not isinstance(job, jobs.YumCheckPackage):
+ raise TypeError("job must be a YumCheckPackage instance")
+ if ( not job.metadata.get("output_params", [])
+ and job.state == job.COMPLETED):
+ from openlmi.software.core import IdentityFileCheck
+ failed = []
+ pkg_info, pkg_check = job.result_data
+ for file_name in pkg_check:
+ pkg_file = pkg_check[file_name]
+ file_check = IdentityFileCheck.test_file(pkg_info,
+ pkg_check.file_checksum_type, pkg_file)
+ if not IdentityFileCheck.file_check_passed(file_check):
+ failed.append(IdentityFileCheck.file_check2model(
+ file_check, job=job))
+ metadata = {
+ 'output_params' : {
+ 'Failed' : pywbem.CIMProperty("Failed",
+ type="reference", is_array=True, value=failed)
+ }
+ }
+ # update local instance
+ job.update(metadata=metadata)
+ if YumDB.RUNNING_UNDER_CIMOM_PROCESS:
+ # update instance on server
+ YumDB.get_instance().update_job(job.jobid, metadata=metadata)
+ # else: we are called from YumWorker process;
+ # (update on server already occured)
+ # moreover YumWorker blocks on us - we can not wait for another job
+ # to finish
+ return job.metadata.get('output_params', [])
+
+@cmpi_logging.trace_function
def make_method_params(job, class_name, include_input, include_output):
"""
Create a class of given name with all input or output parameters
@@ -422,12 +473,32 @@ def make_method_params(job, class_name, include_input, include_output):
if include_input and "input_params" in job.metadata:
for (name, value) in job.metadata["input_params"].items():
inst[name] = value
- if include_output and "output_params" in job.metadata:
- # overwrite any input parameter
- for (name, value) in job.metadata["output_params"].iteritems():
- inst[name] = value
+ if include_output:
+ if isinstance(job, jobs.YumCheckPackage):
+ # make sure, that output parameters are computed
+ get_verification_out_params(job)
+ if "output_params" in job.metadata:
+ # overwrite any input parameter
+ for (name, value) in job.metadata["output_params"].iteritems():
+ inst[name] = value
return inst
+def job_class2cim_class_name(jobcls):
+ """
+ Here we map classes of job objects to their corresponding CIM class
+ name.
+
+ :param jobcls: (``type``) Subclass of jobs.YumJob.
+ """
+ if not issubclass(jobcls, (
+ jobs.YumInstallPackageFromURI,
+ jobs.YumSpecificPackageJob)):
+ raise ValueError("Job class \"%s\" does not have any associated"
+ " CIM class." % jobcls.__name__)
+ if issubclass(jobcls, (jobs.YumCheckPackage, jobs.YumCheckPackageFile)):
+ return "LMI_SoftwareVerificationJob"
+ return "LMI_SoftwareInstallationJob"
+
@cmpi_logging.trace_function
def _fill_nonkeys(job, model):
"""
@@ -506,11 +577,22 @@ def _fill_nonkeys(job, model):
job.created))
@cmpi_logging.trace_function
-def job2model(job, keys_only=True, model=None):
+def job2model(job, class_name=None, keys_only=True, model=None):
"""
- @param job can either be jobs.YumAsyncJob or integer
- @param model if not None, will be filled with data, otherwise
- a new instance of CIMInstance or CIMObjectPath is created
+ Makes LMI_SoftwareJob out of job object or job id.
+
+ :param job: (``int`` | ``YumAsyncJob``) Job identifier.
+ In case of integer, caller should also provide class_name of resulting
+ CIM instance. Otherwise generic LMI_SoftwareJob will be returned.
+ :param class_name: (``str``) Determines CIM class name of resulting
+ instance. This should be given when ``job`` is an integer.
+ :param model: (``CIMInstance`` | ``CIMInstanceName``) If not None,
+ will be filled with properties, otherwise
+ a new instance of CIMInstance or CIMObjectPath is created.
+ :param keys_only: (``bool``) Says whether to fill only key properties.
+ Also if ``model`` is not given, it determines, whether to make
+ ``CIMInstanceName`` or ``CIMInstance``.
+ :rtype: (``CIMInstance`` | ``CIMInstanceName``)
"""
if not isinstance(job, (int, long, jobs.YumAsyncJob)):
raise TypeError("job must be an instance of YumAsyncJob")
@@ -520,15 +602,23 @@ def job2model(job, keys_only=True, model=None):
raise TypeError("job must be an instance of YumAsyncJob"
" filling non-key properties")
+ if class_name is None:
+ if model is not None:
+ class_name = model.classname
+ elif isinstance(job, jobs.YumJob):
+ class_name = job_class2cim_class_name(job.__class__)
+ else:
+ class_name = "LMI_SoftwareJob"
+ cmpi_logging.logger.warn(
+ "class_name not supplied for jobid=%d, using general"
+ " LMI_SoftwareJob as CIM class name")
if model is None:
- model = pywbem.CIMInstanceName("LMI_SoftwareInstallationJob",
- namespace="root/cimv2")
+ model = pywbem.CIMInstanceName(class_name, namespace="root/cimv2")
if not keys_only:
- model = pywbem.CIMInstance("LMI_SoftwareInstallationJob",
- path=model)
+ model = pywbem.CIMInstance(class_name, path=model)
jobid = job.jobid if isinstance(job, jobs.YumAsyncJob) else job
- model['InstanceID'] = 'LMI:LMI_SoftwareInstallationJob:%d' % jobid
+ model['InstanceID'] = 'LMI:%s:%d' % (class_name, jobid)
if isinstance(model, pywbem.CIMInstance):
model.path['InstanceID'] = model['InstanceID'] #pylint: disable=E1103
if not keys_only:
@@ -545,19 +635,27 @@ def object_path2job(op):
"op must be an instance of CIMInstanceName")
if (not "InstanceID" in op or not op['InstanceID']):
- raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "Wrong keys.")
- instid = op['InstanceID']
- if not instid.lower().startswith("lmi:lmi_softwareinstallationjob:"):
raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
- "InstanceID must start with LMI:LMI_SoftwareInstallationJob:"
- " prefix.")
- try:
- instid = int(instid[len("LMI:LMI_SoftwareInstallationJob:"):])
- except ValueError:
+ "Missing InstanceID key property.")
+ instid = op['InstanceID']
+ match = util.RE_INSTANCE_ID.match(instid)
+ if not match or match.group('clsname').lower() not in {
+ c.lower() for c in JOB_CLASS_NAMES}:
raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
- 'Invalid InstanceID "%s"' % instid)
+ "InstanceID must start with one of {%s} prefixes."
+ " And end with positive integer." % (
+ ", ".join(("LMI:%s:" % cn) for cn in JOB_CLASS_NAMES)))
+
+ instid = int(match.group('id'))
try:
- return YumDB.get_instance().get_job(instid)
+ job = YumDB.get_instance().get_job(instid)
+ clsname = job_class2cim_class_name(job.__class__)
+ if ( clsname.lower() != op.classname.lower()
+ and op.classname.lower() != 'LMI_SoftwareJob'.lower()):
+ raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
+ "Classname \"%s\" does not belong to job with given id."
+ " \"%s\" is the correct one." % (op.classname, clsname))
+ return job
except errors.JobNotFound:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
'No such job "%s".' % op['InstanceID'])
diff --git a/src/software/openlmi/software/yumdb/__init__.py b/src/software/openlmi/software/yumdb/__init__.py
index b913bfa..71fc1c5 100644
--- a/src/software/openlmi/software/yumdb/__init__.py
+++ b/src/software/openlmi/software/yumdb/__init__.py
@@ -205,6 +205,16 @@ class YumDB(singletonmixin.Singleton):
# this is to inform Singleton, that __init__ should be called only once
ignoreSubsequent = True
+ # This serves to all code base as a global variable used to check,
+ # whether YumDB instance is running under cimom broker or under worker
+ # process. This is important for code used in callback functions passed
+ # to worker responsible for creating instances of ConcreteJob. This code
+ # must avoid using calls to YumDB while running under worker. This
+ #
+ # Worker process must set this to False before starting its event handling
+ # loop.
+ RUNNING_UNDER_CIMOM_PROCESS = True
+
@cmpi_logging.trace_method
def __init__(self, **kwargs): #pylint: disable=W0231
"""
diff --git a/src/software/openlmi/software/yumdb/process.py b/src/software/openlmi/software/yumdb/process.py
index c4171ec..56227f3 100644
--- a/src/software/openlmi/software/yumdb/process.py
+++ b/src/software/openlmi/software/yumdb/process.py
@@ -898,13 +898,10 @@ class YumWorker(Process):
self._jobmgr.name, self._jobmgr.ident)
self._pkg_cache = weakref.WeakValueDictionary()
- # We've been started by YumDB, but in this process we don't need
- # the instance object - let's delete it.
- # This allows the code, that can be run both from broker and YumWorker
- # process, to check it. When run under broker, the
- # YumDB.isInstantiated() returns True.
+ # This allows the code, that can be run both from broker and
+ # YumWorker, to check, whether it's called by this process.
from openlmi.software.yumdb import YumDB
- YumDB._forget_class_instance_reference_for_testing()
+ YumDB.RUNNING_UNDER_CIMOM_PROCESS = False
self._main_loop()
LOG.info("terminating")