summaryrefslogtreecommitdiffstats
path: root/src/software/openlmi/software/core/Job.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/software/openlmi/software/core/Job.py')
-rw-r--r--src/software/openlmi/software/core/Job.py754
1 files changed, 754 insertions, 0 deletions
diff --git a/src/software/openlmi/software/core/Job.py b/src/software/openlmi/software/core/Job.py
new file mode 100644
index 0000000..0a3d44a
--- /dev/null
+++ b/src/software/openlmi/software/core/Job.py
@@ -0,0 +1,754 @@
+# -*- encoding: utf-8 -*-
+# Software Management Providers
+#
+# Copyright (C) 2012-2013 Red Hat, Inc. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Just a common functionality related to SoftwareInstallationJob
+and SoftwareVerificationJob.
+"""
+
+from datetime import datetime, timedelta
+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".',
+ jobs.YumRemovePackage :
+ 'Software package removal job %(jobid)d for "%(pkg)s".',
+ jobs.YumUpdateToPackage :
+ 'Software package update job %(jobid)d for "%(pkg)s".',
+ jobs.YumUpdatePackage :
+ 'Software package update 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
+, JOB_METHOD_VERIFY_INSTALLED_IDENTITY) = range(4)
+
+# above identificators point to this array to their description
+JOB_METHOD_NAMES = (
+ "InstallFromSoftwareIdentity",
+ "InstallFromURI",
+ "InstallFromByteStream",
+ "VerifyInstalledIdentity")
+
+class Values(object):
+ class DetailedStatus(object):
+ Not_Available = pywbem.Uint16(0)
+ No_Additional_Information = pywbem.Uint16(1)
+ Stressed = pywbem.Uint16(2)
+ Predictive_Failure = pywbem.Uint16(3)
+ Non_Recoverable_Error = pywbem.Uint16(4)
+ Supporting_Entity_in_Error = pywbem.Uint16(5)
+ # DMTF_Reserved = ..
+ # Vendor_Reserved = 0x8000..
+ _reverse_map = {
+ 0: 'Not Available',
+ 1: 'No Additional Information',
+ 2: 'Stressed',
+ 3: 'Predictive Failure',
+ 4: 'Non-Recoverable Error',
+ 5: 'Supporting Entity in Error'
+ }
+
+ class Status(object):
+ OK = 'OK'
+ Error = 'Error'
+ Degraded = 'Degraded'
+ Unknown = 'Unknown'
+ Pred_Fail = 'Pred Fail'
+ Starting = 'Starting'
+ Stopping = 'Stopping'
+ Service = 'Service'
+ Stressed = 'Stressed'
+ NonRecover = 'NonRecover'
+ No_Contact = 'No Contact'
+ Lost_Comm = 'Lost Comm'
+ Stopped = 'Stopped'
+
+ class HealthState(object):
+ Unknown = pywbem.Uint16(0)
+ OK = pywbem.Uint16(5)
+ Degraded_Warning = pywbem.Uint16(10)
+ Minor_failure = pywbem.Uint16(15)
+ Major_failure = pywbem.Uint16(20)
+ Critical_failure = pywbem.Uint16(25)
+ Non_recoverable_error = pywbem.Uint16(30)
+ # DMTF_Reserved = ..
+ # Vendor_Specific = 32768..65535
+ _reverse_map = {
+ 0: 'Unknown',
+ 5: 'OK',
+ 10: 'Degraded/Warning',
+ 15: 'Minor failure',
+ 20: 'Major failure',
+ 25: 'Critical failure',
+ 30: 'Non-recoverable error'
+ }
+
+ class JobState(object):
+ New = pywbem.Uint16(2)
+ Starting = pywbem.Uint16(3)
+ Running = pywbem.Uint16(4)
+ Suspended = pywbem.Uint16(5)
+ Shutting_Down = pywbem.Uint16(6)
+ Completed = pywbem.Uint16(7)
+ Terminated = pywbem.Uint16(8)
+ Killed = pywbem.Uint16(9)
+ Exception = pywbem.Uint16(10)
+ Service = pywbem.Uint16(11)
+ Query_Pending = pywbem.Uint16(12)
+ # DMTF_Reserved = 13..32767
+ # Vendor_Reserved = 32768..65535
+ _reverse_map = {
+ 2: 'New',
+ 3: 'Starting',
+ 4: 'Running',
+ 5: 'Suspended',
+ 6: 'Shutting Down',
+ 7: 'Completed',
+ 8: 'Terminated',
+ 9: 'Killed',
+ 10: 'Exception',
+ 11: 'Service',
+ 12: 'Query Pending'
+ }
+
+ class GetError(object):
+ Success = pywbem.Uint32(0)
+ Not_Supported = pywbem.Uint32(1)
+ Unspecified_Error = pywbem.Uint32(2)
+ Timeout = pywbem.Uint32(3)
+ Failed = pywbem.Uint32(4)
+ Invalid_Parameter = pywbem.Uint32(5)
+ Access_Denied = pywbem.Uint32(6)
+ # DMTF_Reserved = ..
+ # Vendor_Specific = 32768..65535
+
+ class KillJob(object):
+ Success = pywbem.Uint32(0)
+ Not_Supported = pywbem.Uint32(1)
+ Unknown = pywbem.Uint32(2)
+ Timeout = pywbem.Uint32(3)
+ Failed = pywbem.Uint32(4)
+ Access_Denied = pywbem.Uint32(6)
+ Not_Found = pywbem.Uint32(7)
+ # DMTF_Reserved = ..
+ # Vendor_Specific = 32768..65535
+
+ class RecoveryAction(object):
+ Unknown = pywbem.Uint16(0)
+ Other = pywbem.Uint16(1)
+ Do_Not_Continue = pywbem.Uint16(2)
+ Continue_With_Next_Job = pywbem.Uint16(3)
+ Re_run_Job = pywbem.Uint16(4)
+ Run_Recovery_Job = pywbem.Uint16(5)
+ _reverse_map = {
+ 0: 'Unknown',
+ 1: 'Other',
+ 2: 'Do Not Continue',
+ 3: 'Continue With Next Job',
+ 4: 'Re-run Job',
+ 5: 'Run Recovery Job'
+ }
+
+ class RunDayOfWeek(object):
+ _Saturday = pywbem.Sint8(-7)
+ _Friday = pywbem.Sint8(-6)
+ _Thursday = pywbem.Sint8(-5)
+ _Wednesday = pywbem.Sint8(-4)
+ _Tuesday = pywbem.Sint8(-3)
+ _Monday = pywbem.Sint8(-2)
+ _Sunday = pywbem.Sint8(-1)
+ ExactDayOfMonth = pywbem.Sint8(0)
+ Sunday = pywbem.Sint8(1)
+ Monday = pywbem.Sint8(2)
+ Tuesday = pywbem.Sint8(3)
+ Wednesday = pywbem.Sint8(4)
+ Thursday = pywbem.Sint8(5)
+ Friday = pywbem.Sint8(6)
+ Saturday = pywbem.Sint8(7)
+ _reverse_map = {
+ 0: 'ExactDayOfMonth',
+ 1: 'Sunday',
+ 2: 'Monday',
+ 3: 'Tuesday',
+ 4: 'Wednesday',
+ 5: 'Thursday',
+ 6: 'Friday',
+ 7: 'Saturday',
+ -1: '-Sunday',
+ -7: '-Saturday',
+ -6: '-Friday',
+ -5: '-Thursday',
+ -4: '-Wednesday',
+ -3: '-Tuesday',
+ -2: '-Monday'
+ }
+
+ class RunMonth(object):
+ January = pywbem.Uint8(0)
+ February = pywbem.Uint8(1)
+ March = pywbem.Uint8(2)
+ April = pywbem.Uint8(3)
+ May = pywbem.Uint8(4)
+ June = pywbem.Uint8(5)
+ July = pywbem.Uint8(6)
+ August = pywbem.Uint8(7)
+ September = pywbem.Uint8(8)
+ October = pywbem.Uint8(9)
+ November = pywbem.Uint8(10)
+ December = pywbem.Uint8(11)
+ _reverse_map = {
+ 0: 'January',
+ 1: 'February',
+ 2: 'March',
+ 3: 'April',
+ 4: 'May',
+ 5: 'June',
+ 6: 'July',
+ 7: 'August',
+ 8: 'September',
+ 9: 'October',
+ 10: 'November',
+ 11: 'December'
+ }
+
+ class GetErrors(object):
+ Success = pywbem.Uint32(0)
+ Not_Supported = pywbem.Uint32(1)
+ Unspecified_Error = pywbem.Uint32(2)
+ Timeout = pywbem.Uint32(3)
+ Failed = pywbem.Uint32(4)
+ Invalid_Parameter = pywbem.Uint32(5)
+ Access_Denied = pywbem.Uint32(6)
+ # DMTF_Reserved = ..
+ # Vendor_Specific = 32768..65535
+
+ class CommunicationStatus(object):
+ Unknown = pywbem.Uint16(0)
+ Not_Available = pywbem.Uint16(1)
+ Communication_OK = pywbem.Uint16(2)
+ Lost_Communication = pywbem.Uint16(3)
+ No_Contact = pywbem.Uint16(4)
+ # DMTF_Reserved = ..
+ # Vendor_Reserved = 0x8000..
+ _reverse_map = {
+ 0: 'Unknown',
+ 1: 'Not Available',
+ 2: 'Communication OK',
+ 3: 'Lost Communication',
+ 4: 'No Contact'
+ }
+
+ class OperationalStatus(object):
+ Unknown = pywbem.Uint16(0)
+ Other = pywbem.Uint16(1)
+ OK = pywbem.Uint16(2)
+ Degraded = pywbem.Uint16(3)
+ Stressed = pywbem.Uint16(4)
+ Predictive_Failure = pywbem.Uint16(5)
+ Error = pywbem.Uint16(6)
+ Non_Recoverable_Error = pywbem.Uint16(7)
+ Starting = pywbem.Uint16(8)
+ Stopping = pywbem.Uint16(9)
+ Stopped = pywbem.Uint16(10)
+ In_Service = pywbem.Uint16(11)
+ No_Contact = pywbem.Uint16(12)
+ Lost_Communication = pywbem.Uint16(13)
+ Aborted = pywbem.Uint16(14)
+ Dormant = pywbem.Uint16(15)
+ Supporting_Entity_in_Error = pywbem.Uint16(16)
+ Completed = pywbem.Uint16(17)
+ Power_Mode = pywbem.Uint16(18)
+ Relocating = pywbem.Uint16(19)
+ # DMTF_Reserved = ..
+ # Vendor_Reserved = 0x8000..
+ _reverse_map = {
+ 0: 'Unknown',
+ 1: 'Other',
+ 2: 'OK',
+ 3: 'Degraded',
+ 4: 'Stressed',
+ 5: 'Predictive Failure',
+ 6: 'Error',
+ 7: 'Non-Recoverable Error',
+ 8: 'Starting',
+ 9: 'Stopping',
+ 10: 'Stopped',
+ 11: 'In Service',
+ 12: 'No Contact',
+ 13: 'Lost Communication',
+ 14: 'Aborted',
+ 15: 'Dormant',
+ 16: 'Supporting Entity in Error',
+ 17: 'Completed',
+ 18: 'Power Mode',
+ 19: 'Relocating'
+ }
+
+ class OperatingStatus(object):
+ Unknown = pywbem.Uint16(0)
+ Not_Available = pywbem.Uint16(1)
+ Servicing = pywbem.Uint16(2)
+ Starting = pywbem.Uint16(3)
+ Stopping = pywbem.Uint16(4)
+ Stopped = pywbem.Uint16(5)
+ Aborted = pywbem.Uint16(6)
+ Dormant = pywbem.Uint16(7)
+ Completed = pywbem.Uint16(8)
+ Migrating = pywbem.Uint16(9)
+ Emigrating = pywbem.Uint16(10)
+ Immigrating = pywbem.Uint16(11)
+ Snapshotting = pywbem.Uint16(12)
+ Shutting_Down = pywbem.Uint16(13)
+ In_Test = pywbem.Uint16(14)
+ Transitioning = pywbem.Uint16(15)
+ In_Service = pywbem.Uint16(16)
+ # DMTF_Reserved = ..
+ # Vendor_Reserved = 0x8000..
+ _reverse_map = {
+ 0: 'Unknown',
+ 1: 'Not Available',
+ 2: 'Servicing',
+ 3: 'Starting',
+ 4: 'Stopping',
+ 5: 'Stopped',
+ 6: 'Aborted',
+ 7: 'Dormant',
+ 8: 'Completed',
+ 9: 'Migrating',
+ 10: 'Emigrating',
+ 11: 'Immigrating',
+ 12: 'Snapshotting',
+ 13: 'Shutting Down',
+ 14: 'In Test',
+ 15: 'Transitioning',
+ 16: 'In Service'
+ }
+
+ class LocalOrUtcTime(object):
+ Local_Time = pywbem.Uint16(1)
+ UTC_Time = pywbem.Uint16(2)
+ _reverse_map = {
+ 1: 'Local Time',
+ 2: 'UTC Time'
+ }
+
+ class RequestStateChange(object):
+ Completed_with_No_Error = pywbem.Uint32(0)
+ Not_Supported = pywbem.Uint32(1)
+ Unknown_Unspecified_Error = pywbem.Uint32(2)
+ Can_NOT_complete_within_Timeout_Period = pywbem.Uint32(3)
+ Failed = pywbem.Uint32(4)
+ Invalid_Parameter = pywbem.Uint32(5)
+ In_Use = pywbem.Uint32(6)
+ # DMTF_Reserved = ..
+ Method_Parameters_Checked___Transition_Started = pywbem.Uint32(4096)
+ Invalid_State_Transition = pywbem.Uint32(4097)
+ Use_of_Timeout_Parameter_Not_Supported = pywbem.Uint32(4098)
+ Busy = pywbem.Uint32(4099)
+ # Method_Reserved = 4100..32767
+ # Vendor_Specific = 32768..65535
+ class RequestedState(object):
+ Start = pywbem.Uint16(2)
+ Suspend = pywbem.Uint16(3)
+ Terminate = pywbem.Uint16(4)
+ Kill = pywbem.Uint16(5)
+ Service = pywbem.Uint16(6)
+ # DMTF_Reserved = 7..32767
+ # Vendor_Reserved = 32768..65535
+
+ class PrimaryStatus(object):
+ Unknown = pywbem.Uint16(0)
+ OK = pywbem.Uint16(1)
+ Degraded = pywbem.Uint16(2)
+ Error = pywbem.Uint16(3)
+ # DMTF_Reserved = ..
+ # Vendor_Reserved = 0x8000..
+ _reverse_map = {
+ 0: 'Unknown',
+ 1: 'OK',
+ 2: 'Degraded',
+ 3: 'Error'
+ }
+
+@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
+ of the asynchronous method. Typically used to assemble
+ CIM_ConcreteJob.JobInParameters or CIM_InstMethodCall.MethodParameters
+ values.
+
+ :param job: (``YumJob``) Instance of job created as a result of method
+ invocation. It carries method parameters.
+ :param class_name: (``str``) Name of the class to create.
+ :param include_input: (``bool``) Whether input parameters should be
+ included in the returned class.
+ :param include_output: (``bool``) 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=clsname, namespace="root/cimv2")
+ inst = pywbem.CIMInstance(classname=clsname, path=path)
+ if include_input and "input_params" in job.metadata:
+ for (name, value) in job.metadata["input_params"].items():
+ 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):
+ """
+ Fills into the model of instance all non-key properties.
+ """
+ model['Caption'] = 'Software installation job with id=%d' % job.jobid
+ model['CommunicationStatus'] = Values.CommunicationStatus.Not_Available
+ model['DeleteOnCompletion'] = job.delete_on_completion
+ try:
+ description = JOB_DESCRIPTIONS[job.__class__]
+ kwargs = job.job_kwargs
+ kwargs['jobid'] = job.jobid
+ model['Description'] = description % kwargs
+ except KeyError:
+ cmpi_logging.logger.error(
+ 'no description string found for job class %s' %
+ job.__class__.__name__)
+ model['Description'] = pywbem.CIMProperty('Description',
+ type='string', value=None)
+ if job.started:
+ if job.finished:
+ elapsed = job.finished - job.started
+ else:
+ elapsed = time.time() - job.started
+ model['ElapsedTime'] = pywbem.CIMDateTime(timedelta(seconds=elapsed))
+ else:
+ model["ElapsedTime"] = pywbem.CIMProperty('ElapsedTime',
+ type='datetime', value=None)
+ model['ErrorCode'] = pywbem.Uint16(0 if job.state != job.EXCEPTION else 1)
+ try:
+ model['JobState'], model['OperationalStatus'], model['JobStatus'] = {
+ jobs.YumJob.NEW : (Values.JobState.New,
+ [Values.OperationalStatus.Dormant], 'Enqueued'),
+ jobs.YumJob.RUNNING : (Values.JobState.Running,
+ [Values.OperationalStatus.OK], 'Running'),
+ jobs.YumJob.TERMINATED : (Values.JobState.Terminated,
+ [Values.OperationalStatus.Stopped], 'Terminated'),
+ jobs.YumJob.EXCEPTION : (Values.JobState.Exception
+ , [Values.OperationalStatus.Error]
+ , 'Failed'),
+ jobs.YumJob.COMPLETED : (Values.JobState.Completed
+ , [ Values.OperationalStatus.OK
+ , Values.OperationalStatus.Completed]
+ , 'Finished successfully')
+ }[job.state]
+ except KeyError:
+ cmpi_logging.logger.error('unknown job state: %s' % job.state)
+ model['JobState'] = pywbem.CIMProperty('JobState',
+ type='uint16', value=None)
+ model['OperationalStatus'] = [Values.OperationalStatus.Unknown]
+ model['JobStatus'] = 'Unknown'
+ model["JobInParameters"] = make_method_params(
+ job, "__JobInParameters", True, False)
+ model["JobOutParameters"] = make_method_params(
+ job, "__JobOutParameters", False, True)
+ if 'method' in job.metadata:
+ model['MethodName'] = JOB_METHOD_NAMES[job.metadata["method"]]
+ else:
+ model["MethodName"] = pywbem.CIMProperty('MethodName',
+ type='string', value=None)
+ model['Name'] = job.metadata['name']
+ model['LocalOrUtcTime'] = Values.LocalOrUtcTime.UTC_Time
+ model['PercentComplete'] = pywbem.Uint16(
+ 100 if job.state == job.COMPLETED else (
+ 50 if job.state == job.RUNNING else
+ 0))
+ model['Priority'] = pywbem.Uint32(job.priority)
+ if job.started:
+ model['StartTime'] = pywbem.CIMDateTime(datetime.fromtimestamp(
+ job.started))
+ model['TimeBeforeRemoval'] = pywbem.CIMDateTime(timedelta(
+ seconds=job.time_before_removal))
+ model['TimeOfLastStateChange'] = pywbem.CIMDateTime(datetime.fromtimestamp(
+ job.last_change))
+ model['TimeSubmitted'] = pywbem.CIMDateTime(datetime.fromtimestamp(
+ job.created))
+
+@cmpi_logging.trace_function
+def job2model(job, class_name=None, keys_only=True, model=None):
+ """
+ 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")
+ if isinstance(job, jobs.YumAsyncJob) and not job.async:
+ raise ValueError("job must be asynchronous")
+ if not keys_only and isinstance(job, (int, long)):
+ 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(class_name, namespace="root/cimv2")
+ if not keys_only:
+ model = pywbem.CIMInstance(class_name, path=model)
+
+ jobid = job.jobid if isinstance(job, jobs.YumAsyncJob) else job
+ 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:
+ _fill_nonkeys(job, model)
+ return model
+
+@cmpi_logging.trace_function
+def object_path2job(op):
+ """
+ @param op must contain precise InstanceID of job
+ """
+ if not isinstance(op, pywbem.CIMInstanceName):
+ raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
+ "op must be an instance of CIMInstanceName")
+
+ if (not "InstanceID" in op or not op['InstanceID']):
+ raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
+ "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,
+ "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:
+ 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'])
+
+@cmpi_logging.trace_function
+def modify_instance(instance):
+ """
+ This call modifies the job's parameters according to given instance.
+ """
+ job = object_path2job(instance.path)
+ ydb = YumDB.get_instance()
+ update_kwargs = {}
+ reschedule_kwargs = {}
+ # all modifiable properties
+ prop_name_map = {
+ "name" : "name",
+ "priority" : "priority",
+ "deleteoncompletion" : "delete_on_completion",
+ "timebeforeremoval" : "time_before_removal"
+ }
+ metadata_props = {"name"}
+ reschedule_props = {"delete_on_completion", "time_before_removal"}
+ for name, prop in instance.properties.items():
+ if prop is None:
+ cmpi_logging.logger.warn('property "%s" is None')
+ continue
+ name = name.lower()
+ try:
+ pname = prop_name_map[name]
+ if pname == "priority" and job.priority != prop.value:
+ cmpi_logging.logger.info(
+ 'changing priority of job %s to %d', job, prop.value)
+ job = ydb.set_job_priority(job.jobid, prop.value)
+ elif pname in reschedule_props:
+ if getattr(job, pname) == prop.value:
+ continue
+ if pname == "time_before_removal":
+ value = prop.value.timedelta.total_seconds()
+ else:
+ value = prop.value
+ reschedule_kwargs[pname] = value
+ else:
+ if pname in metadata_props:
+ if not 'metadata' in update_kwargs:
+ update_kwargs['metadata'] = {}
+ update_kwargs['metadata'][pname] = prop.value
+ else:
+ update_kwargs[pname] = prop.value
+ except KeyError:
+ if name == 'instanceid':
+ continue
+ cmpi_logging.logger.warn("skipping property %s: %s", name, prop)
+
+ if reschedule_kwargs:
+ for prop in ('delete_on_completion', 'time_before_removal'):
+ if prop not in reschedule_kwargs:
+ reschedule_kwargs[prop] = getattr(job, prop)
+ cmpi_logging.logger.info('rescheduling job %s to: %s',
+ job, ", ".join("%s=%s"%(k, v) for k, v in
+ reschedule_kwargs.items()))
+ job = ydb.reschedule_job(job.jobid, **reschedule_kwargs)
+
+ if update_kwargs:
+ cmpi_logging.logger.info('changing atributes of job %s to: %s',
+ job, ", ".join("%s=%s"%(k, v) for k, v in
+ update_kwargs.items()))
+ job = ydb.update_job(job.jobid, **update_kwargs)
+
+ return job2model(job, keys_only=False, model=instance)
+
+@cmpi_logging.trace_function
+def job2error(job):
+ """
+ @return instance of CIM_Error if job is in EXCEPTION state,
+ None otherwise
+ """
+ if not isinstance(job, jobs.YumJob):
+ raise TypeError("job must be isntance of YumJob")
+ if job.state == job.EXCEPTION:
+ errortup = job.result_data
+ kwargs = {}
+ if issubclass(errortup[0],
+ (errors.RepositoryNotFound, errors.PackageNotFound)):
+ kwargs['status_code'] = Error.Values. \
+ CIMStatusCode.CIM_ERR_NOT_FOUND
+ if issubclass(errortup[0], errors.PackageNotFound):
+ kwargs['status_code_description'] = "Package not found"
+ else:
+ kwargs['status_code_description'] = "Repository not found"
+ elif issubclass(errortup[0], errors.PackageAlreadyInstalled):
+ kwargs['status_code'] = Error.Values. \
+ CIMStatusCode.CIM_ERR_ALREADY_EXISTS
+ kwargs['message'] = getattr(errortup[1], 'message',
+ str(errortup[1]))
+ value = Error.make_instance(**kwargs)
+ return value