summaryrefslogtreecommitdiffstats
path: root/src/software/openlmi/software/LMI_SoftwareInstalledPackage.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/software/openlmi/software/LMI_SoftwareInstalledPackage.py')
-rw-r--r--src/software/openlmi/software/LMI_SoftwareInstalledPackage.py509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/software/openlmi/software/LMI_SoftwareInstalledPackage.py b/src/software/openlmi/software/LMI_SoftwareInstalledPackage.py
new file mode 100644
index 0000000..51d15b6
--- /dev/null
+++ b/src/software/openlmi/software/LMI_SoftwareInstalledPackage.py
@@ -0,0 +1,509 @@
+# -*- encoding: utf-8 -*-
+# Software Management Providers
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Authors: Michal Minar <miminar@redhat.com>
+#
+
+"""Python Provider for LMI_SoftwareInstalledPackage
+
+Instruments the CIM class LMI_SoftwareInstalledPackage
+
+"""
+
+import itertools
+import pywbem
+from pywbem.cim_provider2 import CIMProvider2
+from openlmi.software.LMI_SoftwarePackage import pkg2model, LMI_SoftwarePackage
+from openlmi.software.LMI_SoftwareFileCheck import filecheck2model
+from openlmi.software.util.common import *
+
+class LMI_SoftwareInstalledPackage(CIMProvider2):
+ """Instrument the CIM class LMI_SoftwareInstalledPackage
+
+ The InstalledSoftwareElement association allows the identification of
+ the ComputerSystem on which a particular SoftwareElement is installed.
+
+ """
+
+ def __init__ (self, env):
+ logger = env.get_logger()
+ logger.log_debug('Initializing provider %s from %s' \
+ % (self.__class__.__name__, __file__))
+
+ def get_instance(self, env, model):
+ """Return an instance.
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ model -- A template of the pywbem.CIMInstance to be returned. The
+ key properties are set on this instance to correspond to the
+ instanceName that was requested. The properties of the model
+ are already filtered according to the PropertyList from the
+ request. Only properties present in the model need to be
+ given values. If you prefer, you can set all of the
+ values, and the instance will be filtered for you.
+
+ Possible Errors:
+ CIM_ERR_ACCESS_DENIED
+ CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized
+ or otherwise incorrect parameters)
+ CIM_ERR_NOT_FOUND (the CIM Class does exist, but the requested CIM
+ Instance does not exist in the specified namespace)
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.get_instance()' \
+ % self.__class__.__name__)
+
+ if not "Software" in model:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing Software property.")
+ if not "System" in model:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing System property.")
+ check_computer_system_op(env, model['System'])
+ with YumDB.getInstance(env):
+ pkg = SoftwarePackage.object_path2pkg(env, model['Software'])
+ model['Software'] = pkg2model(env, pkg, True)
+ return model
+
+ def enum_instances(self, env, model, keys_only):
+ """Enumerate instances.
+
+ The WBEM operations EnumerateInstances and EnumerateInstanceNames
+ are both mapped to this method.
+ This method is a python generator
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ model -- A template of the pywbem.CIMInstances to be generated.
+ The properties of the model are already filtered according to
+ the PropertyList from the request. Only properties present in
+ the model need to be given values. If you prefer, you can
+ always set all of the values, and the instance will be filtered
+ for you.
+ keys_only -- A boolean. True if only the key properties should be
+ set on the generated instances.
+
+ Possible Errors:
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.enum_instances()' \
+ % self.__class__.__name__)
+
+ # Prime model.path with knowledge of the keys, so key values on
+ # the CIMInstanceName (model.path) will automatically be set when
+ # we set property values on the model.
+ model.path.update({'System': None, 'Software': None})
+
+ yum_package_path = pywbem.CIMInstanceName("LMI_SoftwarePackage",
+ namespace=model.path.namespace,
+ host=model.path.host)
+ model['System'] = get_computer_system_op()
+ with YumDB.getInstance(env) as yb:
+ for rpm in yb.rpmdb:
+ iname = pkg2model(env, rpm, True, yum_package_path)
+ model['Software'] = iname
+ if keys_only:
+ yield model
+ else:
+ try:
+ yield self.get_instance(env, model)
+ except pywbem.CIMError, (num, msg):
+ if num not in (pywbem.CIM_ERR_NOT_FOUND,
+ pywbem.CIM_ERR_ACCESS_DENIED):
+ raise
+
+ def set_instance(self, env, instance, modify_existing):
+ """Return a newly created or modified instance.
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ instance -- The new pywbem.CIMInstance. If modifying an existing
+ instance, the properties on this instance have been filtered by
+ the PropertyList from the request.
+ modify_existing -- True if ModifyInstance, False if CreateInstance
+
+ Return the new instance. The keys must be set on the new instance.
+
+ Possible Errors:
+ CIM_ERR_ACCESS_DENIED
+ CIM_ERR_NOT_SUPPORTED
+ CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized
+ or otherwise incorrect parameters)
+ CIM_ERR_ALREADY_EXISTS (the CIM Instance already exists -- only
+ valid if modify_existing is False, indicating that the operation
+ was CreateInstance)
+ CIM_ERR_NOT_FOUND (the CIM Instance does not exist -- only valid
+ if modify_existing is True, indicating that the operation
+ was ModifyInstance)
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.set_instance()' \
+ % self.__class__.__name__)
+
+ # parse and check arguments
+ if modify_existing is True:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_SUPPORTED,
+ "MofifyInstance is not supported")
+
+ if not "Software" in instance:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing Software property.")
+ if not "System" in instance:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing System property.")
+ check_computer_system_op(env, instance['System'])
+
+ with YumDB.getInstance(env) as yb:
+ pkg = SoftwarePackage.object_path2pkg_search(env, instance['Software'])
+ if isinstance(pkg, yum.rpmsack.RPMInstalledPackage):
+ raise pywbem.CIMError(pywbem.CIM_ERR_ALREADY_EXISTS,
+ "Package is already installed.")
+
+ logger.log_info('installing package {}'.format(pkg.nevra))
+ # install
+ yb.install(pkg)
+ yb.buildTransaction()
+ yb.processTransaction()
+ logger.log_info('package installed'.format(pkg.nevra))
+
+ # return instance
+ pkg_iname = pkg2model(env, pkg, True)
+ pkg_iname["SoftwareElementState"] = \
+ LMI_SoftwarePackage.Values.SoftwareElementState.Executable
+ instance["Software"] = pkg_iname
+ return LMI_SoftwareInstalledPackage(env).get_instance(env, instance)
+
+ def delete_instance(self, env, instance_name):
+ """Delete an instance.
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ instance_name -- A pywbem.CIMInstanceName specifying the instance
+ to delete.
+
+ Possible Errors:
+ CIM_ERR_ACCESS_DENIED
+ CIM_ERR_NOT_SUPPORTED
+ CIM_ERR_INVALID_NAMESPACE
+ CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized
+ or otherwise incorrect parameters)
+ CIM_ERR_INVALID_CLASS (the CIM Class does not exist in the specified
+ namespace)
+ CIM_ERR_NOT_FOUND (the CIM Class does exist, but the requested CIM
+ Instance does not exist in the specified namespace)
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.delete_instance()' \
+ % self.__class__.__name__)
+
+ if not "Software" in instance_name:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing Software property.")
+ if not "System" in instance_name:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing System property.")
+ check_computer_system_op(env, instance_name['System'])
+ with YumDB.getInstance(env) as yb:
+ pkg = SoftwarePackage.object_path2pkg(env, instance_name["Software"])
+ logger.log_info('removing package "%s"' % pkg.nevra)
+ yb.remove(pkg)
+ yb.buildTransaction()
+ yb.processTransaction()
+ logger.log_info('package "%s" removed' % pkg.nevra)
+
+ def references(self, env, object_name, model, result_class_name, role,
+ result_role, keys_only):
+ """Instrument Associations.
+
+ All four association-related operations (Associators, AssociatorNames,
+ References, ReferenceNames) are mapped to this method.
+ This method is a python generator
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ object_name -- A pywbem.CIMInstanceName that defines the source
+ CIM Object whose associated Objects are to be returned.
+ model -- A template pywbem.CIMInstance to serve as a model
+ of the objects to be returned. Only properties present on this
+ model need to be set.
+ result_class_name -- If not empty, this string acts as a filter on
+ the returned set of Instances by mandating that each returned
+ Instances MUST represent an association between object_name
+ and an Instance of a Class whose name matches this parameter
+ or a subclass.
+ role -- If not empty, MUST be a valid Property name. It acts as a
+ filter on the returned set of Instances by mandating that each
+ returned Instance MUST refer to object_name via a Property
+ whose name matches the value of this parameter.
+ result_role -- If not empty, MUST be a valid Property name. It acts
+ as a filter on the returned set of Instances by mandating that
+ each returned Instance MUST represent associations of
+ object_name to other Instances, where the other Instances play
+ the specified result_role in the association (i.e. the
+ name of the Property in the Association Class that refers to
+ the Object related to object_name MUST match the value of this
+ parameter).
+ keys_only -- A boolean. True if only the key properties should be
+ set on the generated instances.
+
+ The following diagram may be helpful in understanding the role,
+ result_role, and result_class_name parameters.
+ +------------------------+ +-------------------+
+ | object_name.classname | | result_class_name |
+ | ~~~~~~~~~~~~~~~~~~~~~ | | ~~~~~~~~~~~~~~~~~ |
+ +------------------------+ +-------------------+
+ | +-----------------------------------+ |
+ | | [Association] model.classname | |
+ | object_name | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
+ +--------------+ object_name.classname REF role | |
+ (CIMInstanceName) | result_class_name REF result_role +------+
+ | |(CIMInstanceName)
+ +-----------------------------------+
+
+ Possible Errors:
+ CIM_ERR_ACCESS_DENIED
+ CIM_ERR_NOT_SUPPORTED
+ CIM_ERR_INVALID_NAMESPACE
+ CIM_ERR_INVALID_PARAMETER (including missing, duplicate, unrecognized
+ or otherwise incorrect parameters)
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.references()' \
+ % self.__class__.__name__)
+ ch = env.get_cimom_handle()
+
+ # If you want to get references for free, implemented in terms
+ # of enum_instances, just leave the code below unaltered.
+ if ch.is_subclass(object_name.namespace,
+ sub=object_name.classname,
+ super='CIM_ComputerSystem') or \
+ ch.is_subclass(object_name.namespace,
+ sub=object_name.classname,
+ super='LMI_SoftwarePackage'):
+ return self.simple_refs(env, object_name, model,
+ result_class_name, role, result_role, keys_only)
+
+ def cim_method_checkintegrity(self, env, object_name):
+ """Implements LMI_SoftwarePackage.CheckIntegrity()
+
+ Verify existence and attributes of files installed from RPM
+ package. If all files installed exist and their attributes
+ matches, method returns "Pass". "Not passed" is returned when
+ arbitrary file differs in its attributes. And "Error" if
+ verification could not be done.
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName
+ specifying the object on which the method CheckIntegrity()
+ should be invoked.
+
+ Returns a two-tuple containing the return value (
+ type pywbem.Uint32 self.Values.CheckIntegrity)
+ and a list of CIMParameter objects representing the output parameters
+
+ Output parameters:
+ Failed -- (type REF (pywbem.CIMInstanceName(
+ classname='LMI_SoftwareFileCheck', ...))
+ Array of references to LMI_SoftwareFileCheck, that did not pass
+ verification.
+
+ Possible Errors:
+ CIM_ERR_ACCESS_DENIED
+ CIM_ERR_INVALID_PARAMETER (including missing, duplicate,
+ unrecognized or otherwise incorrect parameters)
+ CIM_ERR_NOT_FOUND (the target CIM Class or instance does not
+ exist in the specified namespace)
+ CIM_ERR_METHOD_NOT_AVAILABLE (the CIM Server is unable to honor
+ the invocation request)
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.cim_method_checkintegrity()' \
+ % self.__class__.__name__)
+
+ failed = []
+ if not "Software" in object_name:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing Software property.")
+ if not "System" in object_name:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing System property.")
+ with YumDB.getInstance(env) as yb:
+ pkg = SoftwarePackage.object_path2pkg(env, object_name['Software'])
+ csum = SoftwareFileCheck.pkg_checksum_type(pkg)
+ vpkg = yum.packages._RPMVerifyPackage(
+ pkg, pkg.hdr.fiFromHeader(), csum, [], True)
+ for vpf in vpkg:
+ fc = SoftwareFileCheck.test_file(env, csum, vpf)
+ if SoftwareFileCheck.filecheck_passed(fc): continue
+ failed.append(filecheck2model(
+ vpkg, vpf.filename, env, keys_only=True, fc=fc))
+ out_params = [ pywbem.CIMParameter('Failed', type='reference',
+ value=failed) ]
+ return ( getattr(self.Values.CheckIntegrity,
+ 'Pass' if len(failed) == 0 else 'Not_passed')
+ , out_params )
+
+ def cim_method_update(self, env, object_name,
+ param_epoch=None,
+ param_release=None,
+ param_version=None):
+ """Implements LMI_SoftwareInstalledPackage.Update()
+
+ Updates the package to latest version. When any of "version" or
+ "release" argument is given, install only matching available
+ package. Otherwise try to update to newest package available.
+
+ Keyword arguments:
+ env -- Provider Environment (pycimmb.ProviderEnvironment)
+ object_name -- A pywbem.CIMInstanceName or pywbem.CIMCLassName
+ specifying the object on which the method Update()
+ should be invoked.
+ param_release -- The input parameter release (type unicode)
+ Specify particular release of package to update to. Update to
+ newest, when empty
+ param_version -- The input parameter version (type unicode)
+ Specify particular version of package to update to. Update to
+ newest, when empty
+
+ Returns a two-tuple containing the return value (
+ type pywbem.Uint16 self.Values.Update)
+ and a list of CIMParameter objects representing the output parameters
+
+ Output parameters:
+ Installed -- (type REF (pywbem.CIMInstanceName(
+ classname='LMI_SoftwareInstalledPackage', ...))
+ The reference to newly installed package, if installation was
+ successful. Otherwise reference to current package.
+
+ Possible Errors:
+ CIM_ERR_ACCESS_DENIED
+ CIM_ERR_INVALID_PARAMETER (including missing, duplicate,
+ unrecognized or otherwise incorrect parameters)
+ CIM_ERR_NOT_FOUND (the target CIM Class or instance does not
+ exist in the specified namespace)
+ CIM_ERR_METHOD_NOT_AVAILABLE (the CIM Server is unable to honor
+ the invocation request)
+ CIM_ERR_FAILED (some other unspecified error occurred)
+
+ """
+
+ logger = env.get_logger()
+ logger.log_debug('Entering %s.cim_method_update()' \
+ % self.__class__.__name__)
+
+ if not "Software" in object_name:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing Software property.")
+ if not "System" in object_name:
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
+ "Missing System property.")
+ check_computer_system_op(env, object_name['System'])
+
+ with YumDB.getInstance(env) as yb:
+ orig = SoftwarePackage.object_path2pkg(env, object_name['Software'])
+
+ evr_str = []
+ for name, param in (
+ ('epoch', param_epoch),
+ ('version', param_version),
+ ('release', param_release)):
+ evr_str.append("%s(%s)"%(name,param))
+ if len(evr_str):
+ evr_str = "specific "+'-'.join(evr_str)
+ else:
+ evr_str = "the newest version-release"
+
+ logger.log_info('trying to update to %s of package \"%s\"' %
+ (evr_str, object_name["Software"]["Name"]))
+
+ pl = yb.doPackageLists('all', showdups=True)
+ exact,_,_ = yum.packages.parsePackages(
+ itertools.chain(pl.available, pl.installed),
+ [orig.name])
+ # NOTE: available ∩ installed = ∅
+ exact = sorted(exact, key=lambda a:a.evra)
+
+ try:
+ pkg = [ p for p in exact
+ if (not param_epoch or param_epoch == p.epoch)
+ and (not param_version or param_version == p.ver)
+ and (not param_release or param_release == p.rel) ] [-1]
+ except IndexError:
+ logger.log_error(
+ 'could not find any matching available package')
+ raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND)
+ out_params = [pywbem.CIMParameter('Installed', type='reference',
+ value=pkg2model(env, pkg, True))]
+ if orig.evra == pkg.evra:
+ logger.log_info('already up to date')
+ return (self.Values.Update.Already_newest, out_params)
+
+ yb.update(update_to=True,
+ name=pkg.name,
+ epoch=pkg.epoch,
+ version=pkg.version,
+ release=pkg.release)
+ yb.buildTransaction()
+ yb.processTransaction()
+ logger.log_info('package {} updated to: {}'.format(
+ orig.name, pkg.evra))
+
+ out_params[0].value["SoftwareElementState"] = \
+ LMI_SoftwarePackage.Values.SoftwareElementState.Executable
+
+ return (self.Values.Update.Successful_installation, out_params)
+
+ class Values(object):
+ class Update(object):
+ Already_newest = pywbem.Uint16(0)
+ Successful_installation = pywbem.Uint16(1)
+ Failed = pywbem.Uint16(2)
+
+ class CheckIntegrity(object):
+ Pass = pywbem.Uint32(0)
+ Not_passed = pywbem.Uint32(1)
+ Error = pywbem.Uint32(2)
+
+## end of class LMI_SoftwareInstalledPackage
+
+## get_providers() for associating CIM Class Name to python provider class name
+
+def get_providers(env):
+ lmi_softwareinstalledpackage_prov = LMI_SoftwareInstalledPackage(env)
+ return {'LMI_SoftwareInstalledPackage': lmi_softwareinstalledpackage_prov}