summaryrefslogtreecommitdiffstats
path: root/src/software/openlmi/software/core/InstallationJob.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/software/openlmi/software/core/InstallationJob.py')
-rw-r--r--src/software/openlmi/software/core/InstallationJob.py579
1 files changed, 579 insertions, 0 deletions
diff --git a/src/software/openlmi/software/core/InstallationJob.py b/src/software/openlmi/software/core/InstallationJob.py
new file mode 100644
index 0000000..b082331
--- /dev/null
+++ b/src/software/openlmi/software/core/InstallationJob.py
@@ -0,0 +1,579 @@
+# -*- encoding: utf-8 -*-
+# Software Management Providers
+#
+# Copyright (C) 2012 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.
+"""
+
+from datetime import datetime, timedelta
+import pywbem
+import time
+
+from openlmi.common import cmpi_logging
+from openlmi.software.yumdb import errors, jobs
+from openlmi.software.yumdb import YumDB
+
+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.YumCheckPackage :
+ 'Software package check job %(jobid)d for "%(pkg)s".',
+ jobs.YumInstallPackageFromURI :
+ 'Software package installation job %(jobid)d from uri: "%(uri)s".',
+}
+
+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'
+ }
+
+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'
+ if 'method_name' in job.metadata:
+ model['MethodName'] = job.metadata['method_name']
+ else:
+ model["MethodName"] = pywbem.CIMProperty('MethodName',
+ type='string', value=None)
+ model['Name'] = job.metadata['name']
+ 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, 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
+ """
+ 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 model is None:
+ model = pywbem.CIMInstanceName("LMI_SoftwareInstallationJob",
+ namespace="root/cimv2")
+ if not keys_only:
+ model = pywbem.CIMInstance("LMI_SoftwareInstallationJob",
+ path=model)
+
+ jobid = job.jobid if isinstance(job, jobs.YumAsyncJob) else job
+ model['InstanceID'] = 'LMI:SoftwareInstallationJob:%d' % 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, "Wrong keys.")
+ instid = op['InstanceID']
+ if not instid.lower().startswith("lmi:softwareinstallationjob:"):
+ raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
+ "InstanceID must start with LMI:SoftwareInstallationJob: prefix.")
+ try:
+ instid = int(instid[len("LMI:SoftwareInstallationJob:"):])
+ except ValueError:
+ raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER,
+ 'Invalid InstanceID "%s"' % instid)
+ try:
+ return YumDB.get_instance().get_job(instid)
+ except errors.JobNotFound:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ 'Not 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)
+