summaryrefslogtreecommitdiffstats
path: root/src/python/openlmi/common/JobManager.py
diff options
context:
space:
mode:
authorJan Safranek <jsafrane@redhat.com>2013-04-12 10:24:27 +0200
committerJan Safranek <jsafrane@redhat.com>2013-04-12 10:24:27 +0200
commitb04d75b0200b2af845f993e3d5d861b0f91118c0 (patch)
treebc1c367903befdd44c0d7c76f7fa7bdc363022de /src/python/openlmi/common/JobManager.py
parentd65c216cb9d8bcce65f19d4e0b1a06b298c8d654 (diff)
downloadopenlmi-providers-b04d75b0200b2af845f993e3d5d861b0f91118c0.tar.gz
openlmi-providers-b04d75b0200b2af845f993e3d5d861b0f91118c0.tar.xz
openlmi-providers-b04d75b0200b2af845f993e3d5d861b0f91118c0.zip
Synchronize JobManager with storage.
JobManager here is older version of the one in openlmi-storage. Let's sync it with the storage so I can use it from there. The patch includes: Fixed job expiration under SFCB. Added LMI_StorageJob.JobInParameters and .JobOutParameters properties. Allow python to exit the provider even if there are threads running. Fixed job returning an error Added possibility to set AffectedElements when a job finishes. Added workaround for rhbz#920763
Diffstat (limited to 'src/python/openlmi/common/JobManager.py')
-rw-r--r--src/python/openlmi/common/JobManager.py115
1 files changed, 80 insertions, 35 deletions
diff --git a/src/python/openlmi/common/JobManager.py b/src/python/openlmi/common/JobManager.py
index a923f29..122fc7c 100644
--- a/src/python/openlmi/common/JobManager.py
+++ b/src/python/openlmi/common/JobManager.py
@@ -49,6 +49,7 @@ import pywbem
import openlmi.common.cmpi_logging as cmpi_logging
from pywbem.cim_provider2 import CIMProvider2
import socket
+import traceback
# Too many instance attributes
# pylint: disable-msg=R0902
@@ -208,7 +209,7 @@ class Job(object):
@cmpi_logging.trace_method
def finish_method(self, new_state, return_value=None, return_type=None,
- output_arguments=None, error=None):
+ output_arguments=None, error=None, affected_elements=None):
"""
Mark the job as finished, with given return value, output parameters and
error.
@@ -224,12 +225,18 @@ class Job(object):
any output parameters.
:param error: (``CIMError``) Error raised by the job. Can be None,
when the job finished successfully.
+ :param affected_elements: (``array of CIMInstanceName``) New list of
+ affected elements to generate LMI_<name>JobAffectedElement
+ association. If None, the old list, passed to constructor, remains
+ untouched.
"""
self.lock()
self.return_value = return_value
self.return_value_type = return_type
self.output_arguments = output_arguments
self.error = error
+ if affected_elements is not None:
+ self.affected_elements = affected_elements
self.change_state(new_state, 100)
self.unlock()
@@ -310,14 +317,13 @@ class Job(object):
self._restart_timer()
self.unlock()
- @cmpi_logging.trace_method
def _expire(self):
"""
Callback when a Job completes and time_before_removal second passed.
The job gets removed from its JobManager.
"""
- cmpi_logging.logger.debug("Got timeout for job %s: '%s', removing"
- " the job" % (self.the_id, self.job_name))
+ # We cannot log here, this method is executed in job's Timer thread,
+ # which is not registered at the cimom.
self.job_manager.remove_job(self)
@cmpi_logging.trace_method
@@ -370,8 +376,16 @@ class Job(object):
try:
self._execute(*(self._execargs), **(self._execkwargs))
except pywbem.CIMError, error:
+ cmpi_logging.logger.trace_warn("Job.execute caught an CIMError %s",
+ str(error))
+ cmpi_logging.logger.trace_verbose("traceback: %s",
+ traceback.format_exc())
self.finish_method(Job.STATE_FAILED, error=error)
except Exception, ex:
+ cmpi_logging.logger.trace_warn("Job.execute caught an Exception %s",
+ str(ex))
+ cmpi_logging.logger.trace_verbose("traceback: %s",
+ traceback.format_exc())
error = pywbem.CIMError(pywbem.CIM_ERR_FAILED, str(ex))
self.finish_method(Job.STATE_FAILED, error=error)
@@ -455,18 +469,14 @@ class Job(object):
namespace=self.job_manager.namespace)
inst = pywbem.CIMInstance(
classname="CIM_InstMethodCall",
- path=path,
- properties={
- 'MethodName' : self.method_name,
- 'MethodParameters' : pywbem.CIMProperty(
- name="MethodParameters",
- type='instance',
- value=self._get_method_params(False)),
- 'PreCall' : True,
- })
+ path=path)
src_instance = self._get_cim_instance()
inst['SourceInstance'] = src_instance
inst['SourceInstanceModelPath'] = str(src_instance.path)
+ inst['MethodName'] = self.method_name
+ inst['MethodParameters'] = self.get_method_params(
+ '__MethodParameters', True, False)
+ inst['PreCall'] = True
return inst
@cmpi_logging.trace_method
@@ -484,22 +494,31 @@ class Job(object):
namespace=self.job_manager.namespace)
inst = pywbem.CIMInstance(
classname="CIM_InstMethodCall",
- path=path,
- properties={
- 'MethodName' : self.method_name,
- 'MethodParameters' : self._get_method_params(True),
- 'PreCall' : False
- })
+ path=path)
+
src_instance = self._get_cim_instance()
inst['SourceInstance'] = src_instance
inst['SourceInstanceModelPath'] = str(src_instance.path)
+ inst['MethodName'] = self.method_name
+ inst['MethodParameters'] = self.get_method_params(
+ '__MethodParameters', True, True)
+ inst['PreCall'] = False
if self.return_value_type is not None:
inst['ReturnValueType'] = self.return_value_type
if self.return_value is not None:
- inst['ReturnValue'] = self.return_value
+ inst['ReturnValue'] = str(self.return_value)
if self.error is not None:
- inst['Error'] = self.error
+ path = pywbem.CIMInstanceName(
+ classname="CIM_Error",
+ host=socket.gethostname(),
+ namespace=self.job_manager.namespace)
+ err = pywbem.CIMInstance(
+ classname="CIM_Error",
+ path=path)
+ err['CIMStatusCode'] = pywbem.Uint32(self.error[0])
+ err['Message'] = self.error[1]
+ inst['Error'] = [err, ]
return inst
@cmpi_logging.trace_method
@@ -512,20 +531,31 @@ class Job(object):
return self.job_manager.get_job_instance(self)
@cmpi_logging.trace_method
- def _get_method_params(self, output=True):
+ def get_method_params(self, class_name, include_input, include_output):
"""
- Assemble __MethodParameters for CIM_InstMethodCall indication.
-
- :rtype: CIMInstance of __MethodParameters.
+ Create a class of given name with all input or output parameters
+ of the asynchronous method. Typically used to assemble
+ CIM_ConcreteJob.JobInParameters or CIM_InstMethodCall.MethodParameters
+ values.
+
+ :param class_name: (``string``) Name of the class to create.
+ :param input: (``boolean``) Whether input parameters should be
+ included in the returned class
+ :param output: (``boolean``) Whether output parameters should be
+ included in the returned class
+ :rtype: CIMInstance of the created class.
"""
+ # TODO: this is workaround for bug #920763, use class_name
+ # when it's fixed
+ clsname = "CIM_ManagedElement"
path = pywbem.CIMInstanceName(
- classname="__MethodParameters",
+ classname=clsname,
namespace=self.job_manager.namespace,
- keybindings={})
- inst = pywbem.CIMInstance(classname="__MethodParameters", path=path)
- for (name, value) in self.input_arguments.iteritems():
- inst[name] = value
- if output:
+ inst = pywbem.CIMInstance(classname=clsname, path=path)
+ if include_input and self.input_arguments:
+ for (name, value) in self.input_arguments.iteritems():
+ inst[name] = value
+ if include_output and self.output_arguments:
# overwrite any input parameter
for (name, value) in self.output_arguments.iteritems():
inst[name] = value
@@ -633,7 +663,7 @@ class JobManager(object):
# Start the worker thread (don't forget to register it at CIMOM)
self.worker = threading.Thread(target=self._worker_main)
- self.worker.daemon=True
+ self.worker.daemon = True
self.worker.start()
# Various classnames for job-related classes, with correct infixes.
@@ -765,7 +795,6 @@ class JobManager(object):
self.indication_manager.send_instmodification(prev_instance,
current_instance, _id)
- @cmpi_logging.trace_method
def remove_job(self, job):
"""
Remove existing job. Note that jobs are removed automatically after a
@@ -773,8 +802,8 @@ class JobManager(object):
:param job: (``Job``) Job to remove.
"""
- cmpi_logging.logger.debug("Removing job %s: '%s'"
- % (job.the_id, job.job_name))
+ # We cannot log here, this method is executed in job's Timer thread,
+ # which is not registered at the cimom.
del self.jobs[job.the_id]
# The job may still be in the queue!
# There is no way, how to remove it, it will be skipped by the
@@ -964,6 +993,17 @@ class LMI_ConcreteJob(CIMProvider2):
value=None,
type='datetime')
+ if job.input_arguments:
+ model['JobInParameters'] = job.get_method_params(
+ "__JobInParameters", True, False)
+
+ if job.job_state in Job.FINAL_STATES:
+ # assemble output parameters with return value
+ outparams = job.get_method_params("__JobOutParameters", False, True)
+ if job.return_value is not None:
+ outparams['__ReturnValue'] = job.return_value
+ model['JobOutParameters'] = outparams
+
model['TimeSubmitted'] = pywbem.CIMDateTime(job.time_submitted)
# set correct state
jobstate, opstate = self.get_job_states(job)
@@ -1383,6 +1423,9 @@ class LMI_AffectedJobElement(CIMProvider2):
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"AffectingElement not found.")
+ if job.affected_elements is None:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "The AffectingElement has no AffectedElement.")
if model['AffectedElement'] not in job.affected_elements:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"AffectedElement is not associated to AffectingElement.")
@@ -1394,6 +1437,8 @@ class LMI_AffectedJobElement(CIMProvider2):
"""Enumerate instances."""
model.path.update({'AffectingElement': None, 'AffectedElement': None})
for job in self.job_manager.jobs.values():
+ if job.affected_elements is None:
+ continue
for element in job.affected_elements:
model['AffectingElement'] = job.get_name()
model['AffectedElement'] = element