diff options
author | Peter Schiffer <pschiffe@redhat.com> | 2013-05-13 13:00:29 +0200 |
---|---|---|
committer | Peter Schiffer <pschiffe@redhat.com> | 2013-05-13 13:00:29 +0200 |
commit | afc343e81566c7707d2ee67c1f47a9ca23b8cd9f (patch) | |
tree | 4319416383cf36235f89b0a2365afc7c6cd63300 /src | |
parent | 1c3bd366f82d4f53c76b89f8fff9359356781622 (diff) | |
parent | 9a690650d5ba4cdf432091c4a095452cfa4faa37 (diff) | |
download | openlmi-providers-afc343e81566c7707d2ee67c1f47a9ca23b8cd9f.tar.gz openlmi-providers-afc343e81566c7707d2ee67c1f47a9ca23b8cd9f.tar.xz openlmi-providers-afc343e81566c7707d2ee67c1f47a9ca23b8cd9f.zip |
Merge branch 'master' of ssh://git.fedorahosted.org/git/openlmi-providers
Diffstat (limited to 'src')
-rw-r--r-- | src/python/openlmi/common/JobManager.py | 36 | ||||
-rw-r--r-- | src/python/openlmi/common/__init__.py | 18 | ||||
-rw-r--r-- | src/realmd/LMI_HostedRealmdServiceProvider.c | 2 | ||||
-rw-r--r-- | src/realmd/LMI_RealmdKerberosRealmProvider.c | 2 | ||||
-rw-r--r-- | src/realmd/LMI_RealmdRealmProvider.c | 2 | ||||
-rw-r--r-- | src/realmd/LMI_RealmdServiceProvider.c | 2 | ||||
-rw-r--r-- | src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c | 2 | ||||
-rw-r--r-- | src/realmd/rdcp_dbus.c | 137 | ||||
-rw-r--r-- | src/software/openlmi/software/LMI_AffectedSoftwareJobElement.py | 2 | ||||
-rw-r--r-- | src/software/openlmi/software/LMI_SoftwareInstallationService.py | 10 | ||||
-rw-r--r-- | src/software/openlmi/software/core/Error.py | 4 | ||||
-rw-r--r-- | src/software/openlmi/software/core/InstMethodCall.py | 144 | ||||
-rw-r--r-- | src/software/openlmi/software/core/InstallationJob.py | 60 | ||||
-rw-r--r-- | src/software/openlmi/software/core/InstallationService.py | 104 | ||||
-rw-r--r-- | src/software/openlmi/software/core/MethodResult.py | 18 | ||||
-rw-r--r-- | src/software/openlmi/software/yumdb/__init__.py | 48 | ||||
-rw-r--r-- | src/software/openlmi/software/yumdb/jobs.py | 2 |
17 files changed, 337 insertions, 256 deletions
diff --git a/src/python/openlmi/common/JobManager.py b/src/python/openlmi/common/JobManager.py index d7939cc..fc12d7e 100644 --- a/src/python/openlmi/common/JobManager.py +++ b/src/python/openlmi/common/JobManager.py @@ -47,6 +47,7 @@ import threading from Queue import Queue import pywbem import openlmi.common.cmpi_logging as cmpi_logging +import openlmi.common from openlmi.common.IndicationManager import IndicationManager from pywbem.cim_provider2 import CIMProvider2 import socket @@ -464,34 +465,6 @@ class Job(object): classname = self.job_manager.job_classname return 'LMI:' + classname + ':' + str(self.the_id) - @staticmethod - def parse_instance_id(instance_id, job_manager, classname=None): - """ - Return the last part of instance_id. - - :param instance_id: (``string``) InstanceID to parse. - :param job_manager: (``JobManager``) JobManager to query for Job's - classname. - :param classname: (``string``) Optional classname. If not given, - JobManager's job_classname will be used for parsing. Other - classnames may be used to parse e.g. LMI_<name>MethodResult - InstanceIDs. - - :rtype: ``string`` or None if the ``instance_id`` has wrong format. - """ - if classname is None: - classname = job_manager.job_classname - parts = instance_id.split(":") - if len(parts) != 3: - return None - if parts[0] != 'LMI': - return None - if parts[1] != classname: - return None - if not parts[2].isdigit(): - return None - return parts[2] - @cmpi_logging.trace_method def get_pre_call(self): """ @@ -871,11 +844,10 @@ class JobManager(object): """ if classname is None: classname = self.job_classname - the_id = Job.parse_instance_id(instance_id, self, classname) - if the_id: - return self.jobs.get(the_id, None) - else: + the_id = openlmi.common.parse_instance_id(instance_id, classname) + if not the_id.isdigit(): return None + return self.jobs.get(the_id, None) @cmpi_logging.trace_method def _worker_main(self): diff --git a/src/python/openlmi/common/__init__.py b/src/python/openlmi/common/__init__.py index 2d19515..baebcdb 100644 --- a/src/python/openlmi/common/__init__.py +++ b/src/python/openlmi/common/__init__.py @@ -22,3 +22,21 @@ """ Common utilities for OpenLMI python providers. """ +def parse_instance_id(instance_id, classname=None): + """ + Parse InstanceID, check it has LMI:<classname>:<ID> format and return + the ID. Return None if the format is bad. + :param instance_id: (``string``) String to parse. + :param classname: (``string``) Name of class, whose InstanceID we parse. + If the classname is None, it won't be checked. + :returns: ``string`` with the ID. + """ + parts = instance_id.split(":", 2) + if len(parts) != 3: + return None + if parts[0] != "LMI": + return None + real_classname = parts[1] + if classname and real_classname.lower() != classname.lower(): + return None + return parts[2] diff --git a/src/realmd/LMI_HostedRealmdServiceProvider.c b/src/realmd/LMI_HostedRealmdServiceProvider.c index 08732c1..1a9f399 100644 --- a/src/realmd/LMI_HostedRealmdServiceProvider.c +++ b/src/realmd/LMI_HostedRealmdServiceProvider.c @@ -230,4 +230,4 @@ KONKRET_REGISTRATION( "root/cimv2", "LMI_HostedRealmdService", "LMI_HostedRealmdService", - "instance association"); + "instance association") diff --git a/src/realmd/LMI_RealmdKerberosRealmProvider.c b/src/realmd/LMI_RealmdKerberosRealmProvider.c index 5dc90d2..aa43ba1 100644 --- a/src/realmd/LMI_RealmdKerberosRealmProvider.c +++ b/src/realmd/LMI_RealmdKerberosRealmProvider.c @@ -624,4 +624,4 @@ KONKRET_REGISTRATION( "root/cimv2", "LMI_RealmdKerberosRealm", "LMI_RealmdKerberosRealm", - "instance method"); + "instance method") diff --git a/src/realmd/LMI_RealmdRealmProvider.c b/src/realmd/LMI_RealmdRealmProvider.c index d8e0a18..13e0471 100644 --- a/src/realmd/LMI_RealmdRealmProvider.c +++ b/src/realmd/LMI_RealmdRealmProvider.c @@ -323,4 +323,4 @@ KONKRET_REGISTRATION( "root/cimv2", "LMI_RealmdRealm", "LMI_RealmdRealm", - "instance method"); + "instance method") diff --git a/src/realmd/LMI_RealmdServiceProvider.c b/src/realmd/LMI_RealmdServiceProvider.c index 01fc0b8..8bc1b79 100644 --- a/src/realmd/LMI_RealmdServiceProvider.c +++ b/src/realmd/LMI_RealmdServiceProvider.c @@ -628,4 +628,4 @@ KONKRET_REGISTRATION( "root/cimv2", "LMI_RealmdService", "LMI_RealmdService", - "instance method"); + "instance method") diff --git a/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c b/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c index 70d65f4..a80ab01 100644 --- a/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c +++ b/src/realmd/LMI_ServiceAffectsRealmdRealmProvider.c @@ -249,4 +249,4 @@ KONKRET_REGISTRATION( "root/cimv2", "LMI_ServiceAffectsRealmdRealm", "LMI_ServiceAffectsRealmdRealm", - "instance association"); + "instance association") diff --git a/src/realmd/rdcp_dbus.c b/src/realmd/rdcp_dbus.c index b05e5c9..75ee439 100644 --- a/src/realmd/rdcp_dbus.c +++ b/src/realmd/rdcp_dbus.c @@ -47,15 +47,6 @@ static gboolean append_g_variant_to_dbus_message(DBusMessage *message, GVariant *g_variant, GError **g_error); static gboolean -dbus_method_append_args_tuple(DBusMessage *message, GVariant *args, GError **g_error); - -static gboolean -marshal_dbus_string_variant(DBusMessageIter *iter, const char *value, GError **g_error); - -static gboolean -marshal_dbus_dict_string_entry(DBusMessageIter *array, const char *name, const char *value, GError **g_error); - -static gboolean dbus_iter_to_variant(DBusMessageIter *iter, GVariant **g_variant_return, GError **g_error); static gboolean @@ -681,134 +672,6 @@ append_g_variant_to_dbus_message(DBusMessage *message, GVariant *g_variant, GEr return TRUE; } -/** - * dbus_method_append_args_tuple: - * @message DBus message currently being built - * @args A GVariant tuple containing the method parameters to - * be appended to @message - * @g_error initialized to error info when FALSE is returned. - * - * Append the method parameters to a DBus method message. @args - * is a GVariant tuple representing the parameter list. - * - * Returns: return TRUE if successful, FALSE if error with @g_error initialized. - */ -static gboolean -dbus_method_append_args_tuple(DBusMessage *message, GVariant *args, GError **g_error) -{ - DBusMessageIter iter; - gsize n, i; - GVariant *arg; - - g_return_val_if_fail (message != NULL, FALSE); - g_return_val_if_fail (args != NULL && g_variant_is_of_type(args, G_VARIANT_TYPE_TUPLE), FALSE); - g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); - - if ((n = g_variant_n_children(args))) { - - dbus_message_iter_init_append(message, &iter); - - for (i = 0; i < n; i++) { - arg = g_variant_get_child_value(args, i); - if (!append_g_variant_to_dbus_msg_iter(&iter, arg, g_error)) { - G_VARIANT_FREE(arg); - return FALSE; - } - G_VARIANT_FREE(arg); - } - } - - return TRUE; -} - -/** - * marshal_dbus_string_variant: - * @iter iterator into which the string variant will be inserted - * @value string value to insert as variant - * @g_error initialized to error info when FALSE is returned. - * - * Add a string variant while marshaling DBus protocol. - * - * Returns: return TRUE if successful, FALSE if error with @g_error initialized. - */ -static gboolean -marshal_dbus_string_variant(DBusMessageIter *iter, const char *value, GError **g_error) -{ - DBusMessageIter variant; - - g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); - - if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &variant)) { - g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, - "cannot open dbus variant string container, value=\"%s\"", value); - return FALSE; - } - - if (!dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, &value)) { - g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, - "cannot append dbus variant string value, value=\"%s\"", value); - return FALSE; - } - - if (!dbus_message_iter_close_container(iter, &variant)) { - g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, - "cannot close dbus variant container, value=\"%s\"", value); - return FALSE; - } - - return TRUE; -} - -/** - * marshal_dbus_dict_string_entry: - * @array dictionary array into which entry is inserted - * @name entry's key - * @value entry's value - * @g_error initialized to error info when FALSE is returned. - * - * Adds a dictionary entry into an dictionary array whose key is a - * string and whose value is also a string while marshaling DBus protocol. - * - * Returns: return TRUE if successful, FALSE if error with @g_error initialized. - */ -static gboolean -marshal_dbus_dict_string_entry(DBusMessageIter *array, const char *name, const char *value, GError **g_error) -{ - DBusMessageIter entry; - - g_return_val_if_fail (array != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - g_return_val_if_fail (g_error == NULL || *g_error == NULL, FALSE); - - if (!dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL, &entry)) { - g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, - "cannot open dbus dict entry container for option <%s=%s>", name, value); - return FALSE; - } - - if (!dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &name)) { - g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, - "cannot append option name for option <%s=%s>", name, value); - return FALSE; - } - - if (!marshal_dbus_string_variant(&entry, value, g_error)) { - return FALSE; - } - - if (!dbus_message_iter_close_container(array, &entry)) { - g_set_error(g_error, RDCP_ERROR, RDCP_ERROR_DBUS, - "cannot close dbus dict entry container for option <%s=%s>", name, value); - return FALSE; - } - - return TRUE; -} - - /*----------------------------------------------------------------------------*/ diff --git a/src/software/openlmi/software/LMI_AffectedSoftwareJobElement.py b/src/software/openlmi/software/LMI_AffectedSoftwareJobElement.py index 601b1c3..33c0522 100644 --- a/src/software/openlmi/software/LMI_AffectedSoftwareJobElement.py +++ b/src/software/openlmi/software/LMI_AffectedSoftwareJobElement.py @@ -83,7 +83,7 @@ class LMI_AffectedSoftwareJobElement(CIMProvider2): elif ch.is_subclass(affected.namespace, sub=affected.classname, super='Linux_ComputerSystem'): AffectedSoftwareJobElement.fill_model_computer_system( - model, env, keys_only=False) + model, job, keys_only=False) elif ch.is_subclass(affected.namespace, sub=affected.classname, super='LMI_SystemSoftwareCollection'): diff --git a/src/software/openlmi/software/LMI_SoftwareInstallationService.py b/src/software/openlmi/software/LMI_SoftwareInstallationService.py index f1e0ea7..8727a14 100644 --- a/src/software/openlmi/software/LMI_SoftwareInstallationService.py +++ b/src/software/openlmi/software/LMI_SoftwareInstallationService.py @@ -369,8 +369,8 @@ class LMI_SoftwareInstallationService(CIMProvider2): out_params = [pywbem.CIMParameter('Job', type='reference', value=None)] try: jobid = InstallationService.install_or_remove_package( - env, "uri", param_uri, - param_target, None, param_installoptions, + env, InstallationJob.JOB_METHOD_INSTALL_FROM_URI, + param_uri, param_target, None, param_installoptions, param_installoptionsvalues) rval = self.values.InstallFromURI. \ Method_Parameters_Checked___Job_Started @@ -655,8 +655,10 @@ class LMI_SoftwareInstallationService(CIMProvider2): out_params = [pywbem.CIMParameter('Job', type='reference', value=None)] try: jobid = InstallationService.install_or_remove_package( - env, "identity", param_source, - param_target, param_collection, param_installoptions, + env, InstallationJob. \ + JOB_METHOD_INSTALL_FROM_SOFTWARE_IDENTITY, + param_source, param_target, param_collection, + param_installoptions, param_installoptionsvalues) rval = self.values.InstallFromSoftwareIdentity. \ Method_Parameters_Checked___Job_Started diff --git a/src/software/openlmi/software/core/Error.py b/src/software/openlmi/software/core/Error.py index 210c00e..92b71d5 100644 --- a/src/software/openlmi/software/core/Error.py +++ b/src/software/openlmi/software/core/Error.py @@ -23,7 +23,6 @@ Just a common functionality related to class CIM_Error. import pywbem from openlmi.common import cmpi_logging -from openlmi.software.core import InstallationService class Values(object): class ErrorSourceFormat(object): @@ -430,6 +429,8 @@ def make_instance( if not isinstance(locals()[param], (int, long)): raise TypeError('%s must be integer'%param) if error_source is None: + # this is a cyclic dependency + from openlmi.software.core import InstallationService error_source = InstallationService.get_path() if not isinstance(error_source, pywbem.CIMInstanceName): raise TypeError('error_source must be a CIMInstanceName') @@ -448,7 +449,6 @@ def make_instance( if message_arguments is not None: inst['MessageArguments'] = message_arguments inst['ProbableCause'] = pywbem.Uint16(probable_cause) - #inst['PerceivedSeverity'] = pywbem.Uint16(perceived_severity) if probable_cause_description is not None: inst['ProbableCauseDescription'] = probable_cause_description if recommended_actions is not None: diff --git a/src/software/openlmi/software/core/InstMethodCall.py b/src/software/openlmi/software/core/InstMethodCall.py new file mode 100644 index 0000000..4c7e890 --- /dev/null +++ b/src/software/openlmi/software/core/InstMethodCall.py @@ -0,0 +1,144 @@ +# -*- 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/>. + +""" +CIM values for enumeration types of CIM_InstMethodCall indication class. +""" + +import pywbem +import socket + +from openlmi.common import cmpi_logging +from openlmi.software.core import InstallationJob +from openlmi.software.core import InstallationService +from openlmi.software.yumdb import jobs, errors + +class Values(object): + class ReturnValueType(object): + boolean = pywbem.Uint16(2) + string = pywbem.Uint16(3) + char16 = pywbem.Uint16(4) + uint8 = pywbem.Uint16(5) + sint8 = pywbem.Uint16(6) + uint16 = pywbem.Uint16(7) + sint16 = pywbem.Uint16(8) + uint32 = pywbem.Uint16(9) + sint32 = pywbem.Uint16(10) + uint64 = pywbem.Uint16(11) + sint64 = pywbem.Uint16(12) + datetime = pywbem.Uint16(13) + real32 = pywbem.Uint16(14) + real64 = pywbem.Uint16(15) + reference = pywbem.Uint16(16) + # DMTF_Reserved = .. + _reverse_map = { + 2: 'boolean', + 3: 'string', + 4: 'char16', + 5: 'uint8', + 6: 'sint8', + 7: 'uint16', + 8: 'sint16', + 9: 'uint32', + 10: 'sint32', + 11: 'uint64', + 12: 'sint64', + 13: 'datetime', + 14: 'real32', + 15: 'real64', + 16: 'reference' + } + + class PerceivedSeverity(object): + Unknown = pywbem.Uint16(0) + Other = pywbem.Uint16(1) + Information = pywbem.Uint16(2) + Degraded_Warning = pywbem.Uint16(3) + Minor = pywbem.Uint16(4) + Major = pywbem.Uint16(5) + Critical = pywbem.Uint16(6) + Fatal_NonRecoverable = pywbem.Uint16(7) + # DMTF_Reserved = .. + _reverse_map = { + 0: 'Unknown', + 1: 'Other', + 2: 'Information', + 3: 'Degraded/Warning', + 4: 'Minor', + 5: 'Major', + 6: 'Critical', + 7: 'Fatal/NonRecoverable' + } + +@cmpi_logging.trace_function +def job2model(job, pre=True): + """ + Create post or pre indication instance used by clients to subscribe + to job's state changes. + + :param job: (``YumJob``) Instance of job created as a result of method + invocation. + :param pre: (``bool``) says, whether to make pre or post indication + instance. + :rtype CIMInstance of CIM_InstMethodCall. + """ + if not isinstance(job, jobs.YumJob): + raise TypeError("job must be a YumJob") + if not pre and job.state == job.NEW or job.state == job.RUNNING: + raise ValueError("job must be finished to make a post indication" + " instance") + path = pywbem.CIMInstanceName( + classname="CIM_InstMethodCall", + host=socket.gethostname(), + namespace="root/cimv2") + inst = pywbem.CIMInstance(classname="CIM_InstMethodCall", path=path) + src_instance = InstallationJob.job2model(job, False) + inst['SourceInstance'] = pywbem.CIMProperty("SourceInstance", + type="instance", value=src_instance) + inst['SourceInstanceModelPath'] = \ + str(src_instance.path) #pylint: disable=E1103 + inst['MethodName'] = InstallationJob.JOB_METHOD_NAMES[ + job.metadata["method"]] + inst['MethodParameters'] = InstallationJob.make_method_params( + job, '__MethodParameters', True, not pre) + inst['PreCall'] = pre + + if not pre: + inst["Error"] = pywbem.CIMProperty("Error", type="instance", + is_array=True, value=[]) + error = InstallationJob.job2error(job) + if error is not None: + inst["Error"].append(error) + inst["ReturnValueType"] = Values.ReturnValueType.uint32 + if job.state == job.COMPLETED: + inst["ReturnValue"] = str(InstallationService. \ + Values.InstallFromURI.Job_Completed_with_No_Error) + elif job.state == job.EXCEPTION: + if issubclass(job.result_data[0], ( + errors.InvalidNevra, errors.InvalidURI, + errors.PackageNotFound)): + inst["ReturnValue"] = str(InstallationService.Values. \ + InstallFromURI.Invalid_Parameter) + else: + inst["ReturnValue"] = str(InstallationService.Values. \ + InstallFromURI.Failed) + else: + inst["ReturnValue"] = str(InstallationService.Values. \ + InstallFromURI.Unspecified_Error) + return inst + diff --git a/src/software/openlmi/software/core/InstallationJob.py b/src/software/openlmi/software/core/InstallationJob.py index 7b06be2..e90ad1b 100644 --- a/src/software/openlmi/software/core/InstallationJob.py +++ b/src/software/openlmi/software/core/InstallationJob.py @@ -44,6 +44,18 @@ JOB_DESCRIPTIONS = { 'Software package installation job %(jobid)d from uri: "%(uri)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) + +# above identificators point to this array to their description +JOB_METHOD_NAMES = ( + "InstallFromSoftwareIdentity", + "InstallFromURI", + "InstallFromByteStream") + class Values(object): class DetailedStatus(object): Not_Available = pywbem.Uint16(0) @@ -386,6 +398,37 @@ class Values(object): } @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 and "output_params" in job.metadata: + # overwrite any input parameter + for (name, value) in job.metadata["output_params"].iteritems(): + inst[name] = value + return inst + +@cmpi_logging.trace_function def _fill_nonkeys(job, model): """ Fills into the model of instance all non-key properties. @@ -436,8 +479,12 @@ def _fill_nonkeys(job, model): type='uint16', value=None) model['OperationalStatus'] = [Values.OperationalStatus.Unknown] model['JobStatus'] = 'Unknown' - if 'method_name' in job.metadata: - model['MethodName'] = job.metadata['method_name'] + 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) @@ -502,7 +549,8 @@ def object_path2job(op): 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.") + "InstanceID must start with LMI:LMI_SoftwareInstallationJob:" + " prefix.") try: instid = int(instid[len("LMI:LMI_SoftwareInstallationJob:"):]) except ValueError: @@ -596,11 +644,9 @@ def job2error(job): kwargs['status_code'] = Error.Values. \ CIMStatusCode.CIM_ERR_NOT_FOUND if issubclass(errortup[0], errors.PackageNotFound): - kwargs['status_code_description'] = \ - "Package not found" + kwargs['status_code_description'] = "Package not found" else: - kwargs['status_code_description'] = \ - "Repository not found" + kwargs['status_code_description'] = "Repository not found" elif issubclass(errortup[0], errors.PackageAlreadyInstalled): kwargs['status_code'] = Error.Values. \ CIMStatusCode.CIM_ERR_ALREADY_EXISTS diff --git a/src/software/openlmi/software/core/InstallationService.py b/src/software/openlmi/software/core/InstallationService.py index acc7ca6..ccb27a6 100644 --- a/src/software/openlmi/software/core/InstallationService.py +++ b/src/software/openlmi/software/core/InstallationService.py @@ -26,10 +26,13 @@ import pywbem from openlmi.common import cmpi_logging from openlmi.software.core import ComputerSystem from openlmi.software.core import Identity +from openlmi.software.core import InstallationJob from openlmi.software.core import SystemCollection from openlmi.software.yumdb import errors from openlmi.software.yumdb import YumDB +JOB_METHOD_SRC_PARAM_NAMES = ["URI", "Source", "Image"] + class InstallationError(Exception): """This exception shall be raised upon any error within install_or_remove_package() function. @@ -593,7 +596,7 @@ def check_path_property(env, op, prop_name): return check_path(env, op[prop_name], prop_name) @cmpi_logging.trace_function -def _check_target_and_collection(env, src_type, target, collection): +def _check_target_and_collection(env, method, target, collection): """ Checks Target and Collection parameters of provider's installation methods. @@ -620,12 +623,13 @@ def _check_target_and_collection(env, src_type, target, collection): if not target and not collection: raise InstallationError(values.Unspecified_Error, "Either Target or Collection parameter must be specified." - if src_type == "identity" else + if method == InstallationJob. \ + JOB_METHOD_INSTALL_FROM_SOFTWARE_IDENTITY else "Missing Target parameter.") @cmpi_logging.trace_function def _install_or_remove_check_params( - env, src_type, source, target, collection, + env, method, source, target, collection, install_options, install_options_values): """ @@ -634,17 +638,20 @@ def _install_or_remove_check_params( @return tuple (action, force, repair) where action is one of Values.InstallFromSoftwareIdentity properties """ + if not method in ( + InstallationJob.JOB_METHOD_INSTALL_FROM_URI, + InstallationJob.JOB_METHOD_INSTALL_FROM_SOFTWARE_IDENTITY, + InstallationJob.JOB_METHOD_INSTALL_FROM_BYTE_STREAM): + raise ValueError("unknown method") + values = Values.InstallFromSoftwareIdentity supported_options = values.InstallOptions.supported.copy() - if src_type == "uri": + if method == InstallationJob.JOB_METHOD_INSTALL_FROM_URI: supported_options.remove(values.InstallOptions.Uninstall) - if not src_type in {"uri", "identity"}: - raise ValueError('uri must be one of {"uri", "identity"}') if not source: raise InstallationError(values.Unspecified_Error, - "Missing %s parameter." % ( - "URI" if src_type == "uri" else "Source")) + "Missing %s parameter." % (JOB_METHOD_SRC_PARAM_NAMES[method])) if not install_options: install_options = [] elif not isinstance(install_options, list): @@ -668,7 +675,7 @@ def _install_or_remove_check_params( raise InstallationError(values.Unspecified_Error, "install option \"%s\" can not have any" " associated value: %s" % (opt, val)) - _check_target_and_collection(env, src_type, target, collection) + _check_target_and_collection(env, method, target, collection) exclusive = [opt for opt in options if opt in { values.InstallOptions.Install, values.InstallOptions.Update, @@ -685,45 +692,88 @@ def _install_or_remove_check_params( , values.InstallOptions.Repair in options) @cmpi_logging.trace_function -def install_or_remove_package(env, src_type, source, target, collection, +def make_job_input_params(method, source, target, collection, install_options, install_options_values): """ - @param src_type is one of {"uri", "identity"} + Make dictionary of input parameters, that are stored in job's metadata. + This dictionary is used in creation of CIM_ConcreteJob and + CIM_InstMethodCall. + """ + input_params = { + "InstallOptionsValues" : pywbem.CIMProperty( + name="InstallOptionsValues", + type="string", + is_array=True, + value=install_options_values), + "InstallOptions" : pywbem.CIMProperty( + name="InstallOptions", type="uint16", + is_array=True, + value=install_options), + "Target" : pywbem.CIMProperty( + name="Target", type="reference", value=target), + } + if method == InstallationJob.JOB_METHOD_INSTALL_FROM_URI: + input_params["URI"] = pywbem.CIMProperty( + name="URI", type="string", value=source) + elif method == InstallationJob.JOB_METHOD_INSTALL_FROM_SOFTWARE_IDENTITY: + input_params["Source"] = pywbem.CIMProperty( + name="Source", type="reference", value=source) + input_params["Collection"] = pywbem.CIMProperty( + name="Collection", type="reference", value=collection) + elif method == InstallationJob.JOB_METHOD_INSTALL_FROM_BYTE_STREAM: + input_params["Image"] = pywbem.CIMProperty( + name="Image", type="reference", value=source) + return input_params + +@cmpi_logging.trace_function +def install_or_remove_package(env, method, + source, target, collection, + install_options, + install_options_values): + """ + :param method: (``int``) Identifier of method defined in + ``core.InstallationJob`` module with variables prefixed with + ``JOB_METHOD_``. """ values = Values.InstallFromSoftwareIdentity (action, force, repair) = _install_or_remove_check_params( - env, src_type, source, target, collection, + env, method, source, target, collection, install_options, install_options_values) + input_params = make_job_input_params(method, + source, target, collection, install_options, + install_options_values) + metadata = { "method" : method, "input_params" : input_params } try: ydb = YumDB.get_instance() if action == values.InstallOptions.Uninstall: - nevra = Identity.object_path2nevra( - source, with_epoch='ALWAYS') - cmpi_logging.logger.info('removing package %s', nevra) - jobid = ydb.remove_package(nevra, async=True) + src = Identity.object_path2nevra(source, with_epoch='ALWAYS') + cmpi_logging.logger.info('removing package %s', src) + jobid = ydb.remove_package(src, async=True, **metadata) else: update = action == values.InstallOptions.Update - if src_type == "uri": + if method == Job.JOB_METHOD_INSTALL_FROM_URI: cmpi_logging.logger.info('%s package "%s"', 'updating' if update else 'installing', source) + src = source jobid = ydb.install_package_from_uri( source, update_only=update, force=force or repair, - async=True) + async=True, **metadata) else: # software identity - nevra = Identity.object_path2nevra( - source, with_epoch='ALWAYS') + src = Identity.object_path2nevra(source, with_epoch='ALWAYS') if update: - jobid = ydb.update_package(nevra, - force=force or repair, async=True) + jobid = ydb.update_package(src, + force=force or repair, async=True, **metadata) else: - jobid = ydb.install_package( - nevra, force=force or repair, async=True) + jobid = ydb.install_package(src, + force=force or repair, async=True, **metadata) cmpi_logging.logger.info('installation job %s for pkg "%s"' - ' enqueued', jobid, nevra) + ' enqueued', jobid, src) return jobid + except (pywbem.CIMError, errors.InvalidURI) as exc: - cmpi_logging.logger.error('failed to install/remove package "%s"' - ' from %s: %s', source, src_type, str(exc)) + cmpi_logging.logger.exception('failed to install/remove package "%s"' + ' from %s: %s', source, + JOB_METHOD_SRC_PARAM_NAMES[method].lower(), str(exc)) raise InstallationError(values.Unspecified_Error, str(exc)) diff --git a/src/software/openlmi/software/core/MethodResult.py b/src/software/openlmi/software/core/MethodResult.py index 723edbb..05bcd78 100644 --- a/src/software/openlmi/software/core/MethodResult.py +++ b/src/software/openlmi/software/core/MethodResult.py @@ -23,6 +23,8 @@ Just a common functionality related to class LMI_SoftwareMethodResult. import pywbem from openlmi.common import cmpi_logging +from openlmi.software.core import InstallationJob +from openlmi.software.core import InstMethodCall from openlmi.software.yumdb import jobs, errors, YumDB @cmpi_logging.trace_function @@ -69,16 +71,18 @@ def job2model(job, keys_only=True, model=None): model['InstanceID'] = "LMI:LMI_SoftwareMethodResult:"+str(job.jobid) if not keys_only: model.path['InstanceID'] = model['InstanceID'] #pylint: disable=E1103 - model['Caption'] = 'Result of method %s' % job.metadata['method_name'] + method_name = InstallationJob.JOB_METHOD_NAMES[job.metadata['method']] + model['Caption'] = 'Result of method %s' % method_name model['Description'] = ( 'Result of asynchronous job number %d created upon invocation' " of %s's %s method." % (job.jobid, - "LMI_SoftwareInstallationService", - job.metadata['method_name'])) + "LMI_SoftwareInstallationService", method_name)) model['ElementName'] = 'MethodResult-%d' % job.jobid - #model['PostCallIndication'] = \ # TODO - #pywbem.CIMInstance(classname='CIM_InstMethodCall', ...) - #model['PreCallIndication'] = \ # TODO - #pywbem.CIMInstance(classname='CIM_InstMethodCall', ...) + model['PostCallIndication'] = pywbem.CIMProperty("PostCallIndication", + type="instance", + value=InstMethodCall.job2model(job, pre=False)) + model['PreCallIndication'] = pywbem.CIMProperty("PreCallIndication", + type="instance", + value=InstMethodCall.job2model(job)) return model diff --git a/src/software/openlmi/software/yumdb/__init__.py b/src/software/openlmi/software/yumdb/__init__.py index 04f2191..ccb4360 100644 --- a/src/software/openlmi/software/yumdb/__init__.py +++ b/src/software/openlmi/software/yumdb/__init__.py @@ -136,26 +136,6 @@ def _make_async_job(jobcls, *args, **kwargs): job.metadata = {} job.metadata['name'] = \ type(job).__name__[len('Yum'):] + ('-%d' % job.jobid) - frm = inspect.currentframe() - method_name = None - while ( frm is not None - and ( not 'self' in frm.f_locals - or not isinstance(frm.f_locals['self'], CIMProvider2))): - frm = frm.f_back - if frm is not None: - prov = frm.f_locals['self'] - method_name = frm.f_code.co_name.lower() - if method_name.startswith('cim_method_'): - method_name = method_name[len('cim_method_'):] - if hasattr(prov, 'values'): - lowertocorrectcase = { - k.lower(): k for k in prov.values.__dict__ } - try: - method_name = lowertocorrectcase[method_name] - except KeyError: - pass - if method_name is not None: - job.metadata['method_name'] = method_name return job # ***************************************************************************** @@ -526,7 +506,7 @@ class YumDB(singletonmixin.Singleton): # Asynchronous jobs # ************************************************************************* @job_request(async=True) - def install_package(self, pkg, async=False, force=False): + def install_package(self, pkg, async=False, force=False, **metadata): """ Install package. @param pkg is an instance of PackageInfo obtained with @@ -534,25 +514,25 @@ class YumDB(singletonmixin.Singleton): Package must not be installed if force is False. """ return self._do_job(_make_async_job(jobs.YumInstallPackage, - pkg, force=force, async=async)) + pkg, force=force, async=async, metadata=metadata)) @job_request(async=True) - def remove_package(self, pkg, async=False): + def remove_package(self, pkg, async=False, **metadata): """ @param pkg is an instance of PackageInfo obtained with get_package_list() or filter_packages(), which must be installed """ return self._do_job(_make_async_job(jobs.YumRemovePackage, - pkg, async=async)) + pkg, async=async, metadata=metadata)) @job_request(async=True) - def update_to_package(self, desired_pkg, async=False): + def update_to_package(self, desired_pkg, async=False, **metadata): """ @param desired_pkg is an instance of PackageInfo, which must be available """ return self._do_job(_make_async_job(jobs.YumUpdateToPackage, - desired_pkg, async=async)) + desired_pkg, async=async, metadata=metadata)) @job_request(async=True) def update_package(self, pkg, @@ -560,33 +540,35 @@ class YumDB(singletonmixin.Singleton): to_epoch=None, to_version=None, to_release=None, - force=False): + force=False, + **metadata): """ @param pkg is an instance of PackageInfo, which must be installed The other parameters filter candidate available packages for update. """ return self._do_job(_make_async_job(jobs.YumUpdatePackage, - pkg, async, to_epoch, to_version, to_release, force=force)) + pkg, async, to_epoch, to_version, to_release, force=force, + metadata=metadata)) @job_request(async=True) - def check_package(self, pkg, async=False): + def check_package(self, pkg, async=False, **metadata): """ @param pkg is an instance of PackageInfo representing installed package @return instance of yumdb.PackageCheck """ return self._do_job(_make_async_job(jobs.YumCheckPackage, - pkg, async=async)) + pkg, async=async, metadata=metadata)) @job_request(async=True) def install_package_from_uri(self, uri, - async=False, update_only=False, force=False): + async=False, update_only=False, force=False, **metadata): """ Install package from uri. @param uri is either remote url or local path. """ - return self._do_job(jobs.YumInstallPackageFromURI( - uri, async, update_only, force=force)) + return self._do_job(_make_async_job(jobs.YumInstallPackageFromURI, + uri, async, update_only, force=force, metadata=metadata)) # ************************************************************************* # Control of asynchronous jobs diff --git a/src/software/openlmi/software/yumdb/jobs.py b/src/software/openlmi/software/yumdb/jobs.py index 84fd3ed..5195f50 100644 --- a/src/software/openlmi/software/yumdb/jobs.py +++ b/src/software/openlmi/software/yumdb/jobs.py @@ -45,7 +45,7 @@ class YumJob(object): #pylint: disable=R0903 metadata attribute typically contain: name - name of job, that is modifiable by user - method_name - name of provider's method, that lead to creation of job + method - identificator of method, that lead to creation of job """ __slots__ = ( 'jobid', 'created', 'started', 'finished', 'last_change' , 'priority', 'result', 'result_data') |